Skip to content

Instantly share code, notes, and snippets.

@dermotbalson
Last active March 18, 2023 17:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dermotbalson/6509302 to your computer and use it in GitHub Desktop.
Save dermotbalson/6509302 to your computer and use it in GitHub Desktop.
Physics
--# Notes
--This project shows to use some basic physics, from bouncing balls and spinning
--rectangles, to the basics of a very simple platform game
--HOW TO USE THIS PROJECT
--There are a number of tabs at the top. Press on a tab to see its code.
--Work through the tabs from left to right, to see the project develop
--You can run the code in any of the project tabs, by
--1. running the program, and
--2. selecting the tab number using the controls at the upper left of the screen
--The program will remember your selection after that.
--This enables you to work with one tab at a time, make changes and see the effects by running the program
--# Main
--Main
--This code manages which Code tab is run
--it remembers your last choice, and if you select a different one, it runs that instead
local tabs = {}
local fnames = {"setup","draw","touched","collide","orientationChanged","close","restart","keyboard","cleanup"}
local fns = {}
local tabDesc={}
function setup()
for k,v in ipairs(fnames) do --store addresses of key event functions
fns[v] = _G[v]
end
LastCode=readProjectData("Code") or 1 --load stored tab number
parameter.integer("Choose_a_tab",1,#tabs,LastCode,ShowList) --tab selector
parameter.action("Run selected tab", RunCode)
RunCode()
end
function ShowList()
output.clear()
for i=1,#tabs do
print(i,tabDesc[i])
end
end
--these two functions do all the tab switching magic (thanks to Andrew_Stacey)
function localise(n,d)
if d then tabDesc[n]=d end
local t= {}
setmetatable(t,{__index = _G})
--setfenv(2,t)
tabs[n] = t
return t
end
--change tabs
function RunCode()
output.clear()
saveProjectData("Code",Choose_a_tab)
cleanup()
local t = tabs[Choose_a_tab]
for k,v in ipairs(fnames) do
if t[v] then _G[v] = t[v] else _G[v] = fns[v] end -- overwrite with the new code
end
setup()
end
--default empty function to avoid errors for tabs that don't have it
function cleanup()
end
--# Step_1
_ENV = localise(1) --DELETE this line if you copy this code to another project (it is used to manage tab changes)
--create one ball that moves across the screen and feels gravity
--but it disappears off the edges!
function setup()
p = physics.body(CIRCLE,50) --create physics ball, radius 50 pixels
p.restitution = .8 --very bouncy
--Now give it some velocity (velocity is in pixels per second, ie per 60 redraws)
p.linearVelocity = vec2(math.random(100,400),math.random(100,400))
p.x = math.random(60,250) --POSITION it randomly on the screen
p.y = math.random(400,600)
--choose a random colour for the ball
pColor=color(math.random(0,255),math.random(0,255),math.random(0,255),100)
print("One ball falling")
end
function draw()
background(220)
fill(pColor)
ellipse(p.x,p.y,100) --draw ellipse over the physics object, diameter 100 pixels
end
function cleanup() --get rid of physics object if we switch to another tab
p:destroy()
end
--# Step_2
_ENV = localise(2) --DELETE this line if you copy this code to another project (it is used to manage tab changes)
--add floor and walls for ball to bounce off
--- ********* < shows code changes
function setup()
p = physics.body(CIRCLE,50) --create physics ball, radius 50 pixels
p.restitution = .8 --very bouncy
--Now give it some velocity (velocity is in pixels per second, ie per 60 redraws)
p.linearVelocity = vec2(math.random(100,400),math.random(100,400))
p.x = math.random(60,250) --POSITION it randomly on the screen
p.y = math.random(400,600)
--choose a random colour for the ball
pColor=color(math.random(0,255),math.random(0,255),math.random(0,255),100)
--create floor and walls *******************************************
w1 = physics.body(EDGE,vec2(0,0),vec2(WIDTH,0)) -----bottom
w2 = physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT)) ---left side
w3 = physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT)) --right side
print("One ball bouncing off walls")
end
function draw()
background(220)
fill(pColor)
ellipse(p.x,p.y,100) --draw ellipse over the physics object, diameter 100 pixels
end
function cleanup() --get rid of physics object if we switch to another tab
p:destroy()
w1:destroy()
w2:destroy()
w3:destroy()
end
--# Step_3
_ENV = localise(3) --DELETE this line if you copy this code to another project (it is used to manage tab changes)
--add more balls
--put code in functions
function setup()
balls={} -- create table of 5 physics objects ************
for i=1,5 do
balls[i]=CreateBall()
end
CreateWalls()
print("Several balls bouncing")
end
function CreateBall() -- function to create a physics object **********
local p = physics.body(CIRCLE,50)
p.restitution = .8
--Now give it some velocity (velocity is in pixels per second, ie per 60 redraws)
p.linearVelocity = vec2(math.random(100,400),math.random(100,400))
--POSITION it randomly on the screen
p.x = math.random(60,250)
p.y = math.random(400,600)
p.color=color(math.random(0,255),math.random(0,255),math.random(0,255),100)
return p
end
function CreateWalls() ---create walls *********
w1 = physics.body(EDGE,vec2(0,0),vec2(WIDTH,0))
w2 = physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT))
w3 = physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT))
end
function draw()
background(220)
pushStyle()
fill(255,255,0)
for i=1,#balls do
fill(balls[i].color)
ellipse(balls[i].x,balls[i].y,100)
end
popStyle()
end
function cleanup() --get rid of physics objects if we switch to another tab
for i=1,#balls do
balls[i]:destroy()
end
balls=nil
w1:destroy()
w2:destroy()
w3:destroy()
end
--# Step_4
_ENV = localise(4) --DELETE this line if you copy this code to another project (it is used to manage tab changes)
--instead of balls falling to the floor, let's do a tabletop
--now the balls are rolling round a table
--we do this by simply turning off gravity
function setup()
balls={} -- create table of 5 physics objects
for i=1,5 do
balls[i]=CreateBall()
end
CreateWalls()
grav=physics.gravity() --store physics gravity so we can restore it if we switch tabs
physics.gravity(0,0) -- turn off gravity **************
print("Balls rolling around table")
end
function CreateBall() -- function to create a physics object
local p = physics.body(CIRCLE,50)
p.restitution = .8
--Now give it some velocity (velocity is in pixels per second, ie per 60 redraws)
p.linearVelocity = vec2(math.random(100,400),math.random(100,400))
--POSITION it randomly on the screen
p.x = math.random(60,250)
p.y = math.random(400,600)
p.color=color(math.random(0,255),math.random(0,255),math.random(0,255),100)
return p
end
function CreateWalls() ---create walls
w1 = physics.body(EDGE,vec2(0,0),vec2(WIDTH,0))
w2 = physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT))
w3 = physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT))
w4 = physics.body(EDGE,vec2(0,HEIGHT),vec2(WIDTH,HEIGHT)) --- put in top wall too **********
end
function draw()
background(220)
pushStyle()
fill(255,255,0)
for i=1,#balls do
fill(balls[i].color)
ellipse(balls[i].x,balls[i].y,100)
end
popStyle()
end
function cleanup() --get rid of physics objects if we switch to another tab
for i=1,#balls do
balls[i]:destroy()
end
balls=nil
w1:destroy()
w2:destroy()
w3:destroy()
w4:destroy()
physics.gravity(grav.x,grav.y) --restore default
end
--# Step_5
_ENV = localise(5) --DELETE this line if you copy this code to another project (it is used to manage tab changes)
--instead of balls falling to the floor, let's do a tabletop
--now the balls are rolling round a table
--we do this by simply turning off gravity
function setup()
rects={} --create table of rectangles **********
w=100 --width
h=80 --height
for i=1,5 do
rects[i]=CreateRect(w,h)
end
CreateWalls()
print("Rectangles spinning")
grav=physics.gravity() --store physics gravity so we can restore it if we switch tabs
physics.gravity(0,0) -- turn off gravity **************
end
function CreateRect(w,h) -- function to create a physics object
local p = physics.body(POLYGON,vec2(-w/2,h/2),vec2(-w/2,-h/2),vec2(w/2,-h/2),vec2(w/2,h/2))
p.restitution = .8
--Now give it some velocity (velocity is in pixels per second, ie per 60 redraws)
p.linearVelocity = vec2(math.random(100,400),math.random(100,400))
--POSITION it randomly on the screen
p.x = math.random(60,250)
p.y = math.random(400,600)
p.color=color(math.random(0,255),math.random(0,255),math.random(0,255),100)
return p
end
function CreateWalls() ---create walls
w1 = physics.body(EDGE,vec2(0,0),vec2(WIDTH,0))
w2 = physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT))
w3 = physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT))
w4 = physics.body(EDGE,vec2(0,HEIGHT),vec2(WIDTH,HEIGHT)) --- put in top wall too **********
end
function draw()
background(220)
pushStyle()
fill(255,255,0)
for i=1,#rects do
fill(rects[i].color)
local x,y=rects[i].x,rects[i].y
pushMatrix()
translate(x,y)
rotate(rects[i].angle)
rect(-w/2,-h/2,w,h)
popMatrix()
end
popStyle()
end
function cleanup() --get rid of physics objects if we switch to another tab
for i=1,#rects do
rects[i]:destroy()
end
rects=nil
w1:destroy()
w2:destroy()
w3:destroy()
w4:destroy()
physics.gravity(grav.x,grav.y) --restore default
end
--# Step_6
_ENV = localise(6) --DELETE this line if you copy this code to another project (it is used to manage tab changes)
--make a character walk and jump
--make it full screen
function setup()
CreateScene() --set up scene
SetupChar()
print("A jumping platform game")
end
function draw()
background(220)
DrawScene()
DrawChar()
ShowInstructions()
end
function SetupChar()
char=readImage("Planet Cute:Character Boy") --read in image (change it if you like)
ch = physics.body(CIRCLE,char.width/2) --create physics circle, radius = 1/2 height of char
ch.x=30
ch.y=floorHeight+100
ch.restitution = .1 --not very bouncy
ch.linearVelocity = vec2(0,0)
ch.x = WIDTH/2 --POSITION it randomly on the screen
ch.y = HEIGHT/2
end
function CreateScene()
--do floor first
floorHeight=50 --floor
floor=physics.body(EDGE,vec2(0,floorHeight),vec2(WIDTH,floorHeight))
--now do platforms
gap=150 --vertical gap between platforms
plat={}
plat[1]={x1=150,x2=350,y=floorHeight+gap}
plat[2]={x1=300,x2=550,y=floorHeight+2*gap}
plat[3]={x1=500,x2=700,y=floorHeight+gap}
--create physics objects for platforms
for i=1,#plat do
plat[i].body=physics.body(EDGE,vec2(plat[i].x1,plat[i].y),vec2(plat[i].x2,plat[i].y))
end
--set visible platform depth
platDepth=5 --pixels
--side walls
w1 = physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT)) ---left side
w2 = physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT)) --right side
end
function DrawScene()
pushStyle()
--draw ground as solid rectangle
fill(185, 157, 140, 255)
rect(0,0,WIDTH,floorHeight)
--draw floor on top, as a thick line
stroke(62, 121, 181, 255) --line colour
strokeWidth(5) --thick line
line(0,floorHeight-platDepth,WIDTH,floorHeight-platDepth)
--draw platforms
fill(62, 121, 181, 255)
for i=1,#plat do
line(plat[i].x1,plat[i].y-platDepth,plat[i].x2,plat[i].y-platDepth)
end
popStyle()
end
function DrawChar()
sprite(char,ch.x,ch.y)
end
function ShowInstructions()
--write instructions
pushStyle()
fill(255,0,0)
fontSize(24)
textMode(CORNER)
text("Touch middle of screen to jump",50,HEIGHT-80)
text("Touch left/right of screen to walk",50,HEIGHT-120)
text("Touch button at top left of screen for menu controls",50,HEIGHT-160)
popStyle()
end
function touched(touch)
if touch.state==BEGAN then
if touch.x<WIDTH/3 then --left side - go left
ch:applyForce(vec2(-500,0))
elseif touch.x<WIDTH*2/3 then --middle - jump
if ch.linearVelocity.y==0 then ch:applyForce(vec2(0,5000)) end
else --right side, go right
ch:applyForce(vec2(500,0))
end
end
end
function cleanup() --get rid of physics object if we switch to another tab
floor:destroy()
for i=1,#plat do
plat[i].body:destroy()
end
w1:destroy()
w2:destroy()
ch:destroy()
displayMode(STANDARD)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment