Last active
March 18, 2023 17:47
-
-
Save dermotbalson/6509120 to your computer and use it in GitHub Desktop.
Step by step sliding puzzle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--# Notes | |
--This is a simulation of an old puzzle game | |
--where you have a flat plastic surface with balls that roll around on it | |
--there are little holes you have to get the balls into by tipping the puzzle to roll the balls | |
--but there are obstacles, and if you tip too far, the balls come out again | |
--in this version, we'll start to build the puzzle, and when we add more than one ball, we'll | |
--start using physics to manage the ball collisions | |
--this project also uses the built in accelerometer, so tipping the iPad will roll the balls. | |
--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) | |
--draw one slot | |
function setup() | |
--nothing to do here yet | |
print("create a round slot for our ball to 'fall into'") | |
end | |
function draw() | |
background(151, 190, 215, 255) | |
--draw round slot that balls will fall into | |
--draw two filled circles | |
--to create an illusion of a shadow | |
--the darker circle is offset by two pixels | |
pushStyle() | |
--darker (shadow) circle drawn behind | |
fill(78, 125, 148, 255) | |
ellipse(WIDTH/2,HEIGHT/2,50) | |
--draw slot, with a one pixel border | |
strokeWidth(1) | |
stroke(122, 152, 164, 255) --border colour | |
fill(143, 182, 198, 255) --fill colour | |
ellipse(WIDTH/2-2,HEIGHT/2+2,50) --put in middle of the screen just for now | |
popStyle() | |
end | |
--# Step_2 | |
_ENV = localise(2) --DELETE this line if you copy this code to another project (it is used to manage tab changes) | |
--draw four slots in the corners of the screen | |
function setup() | |
--put all the slot making code in a function so we can keep things tidy | |
SetupSlots() | |
print("now draw four slots") | |
end | |
function SetupSlots() | |
--set up one in each corner of the screen | |
slotsX={} --table to hold x pos | |
slotsY={} --table to hold y pos | |
offset=200 | |
slotsX[1]=offset slotsY[1]=HEIGHT-offset --top left | |
slotsX[2]=WIDTH-offset slotsY[2]=HEIGHT-offset --top right | |
slotsX[3]=offset slotsY[3]=offset --bottom left | |
slotsX[4]=WIDTH-offset slotsY[4]=offset --bottom right | |
numSlots=4 --number of slots | |
end | |
function draw() | |
background(151, 190, 215, 255) | |
--draw all the slots | |
for i=1,numSlots do | |
DrawSlot(i) | |
end | |
end | |
--this function draws one slot | |
function DrawSlot(i) | |
size=50 | |
pushStyle() | |
fill(78, 125, 148, 255) | |
ellipse(slotsX[i],slotsY[i],size) | |
strokeWidth(1) | |
stroke(66, 109, 141, 255) | |
fill(143, 182, 198, 255) | |
ellipse(slotsX[i]-2,slotsY[i]+2,size) | |
popStyle() | |
end | |
--# Step_3 | |
_ENV = localise(3) --DELETE this line if you copy this code to another project (it is used to manage tab changes) | |
--draw our ball | |
function setup() | |
size=50 | |
SetupSlots() | |
setupBall() | |
print("add a ball") | |
end | |
function SetupSlots() | |
--set up one in each corner of the screen | |
slotsX={} --x pos | |
slotsY={} --y pos | |
offset=200 | |
slotsX[1]=offset slotsY[1]=HEIGHT-offset --top left | |
slotsX[2]=WIDTH-offset slotsY[2]=HEIGHT-offset --top right | |
slotsX[3]=offset slotsY[3]=offset --bottom left | |
slotsX[4]=WIDTH-offset slotsY[4]=offset --bottom right | |
numSlots=4 --number of slots | |
end | |
--choose a random starting point | |
function setupBall() | |
ballX=WIDTH/2 + 200*(math.random()-.5) | |
ballY=HEIGHT/2 + 200*(math.random()-.5) | |
end | |
function draw() | |
background(151, 190, 215, 255) | |
for i=1,numSlots do | |
DrawSlot(i) | |
end | |
DrawBall() | |
end | |
function DrawSlot(i) | |
pushStyle() | |
fill(78, 125, 148, 255) | |
ellipse(slotsX[i]+2,slotsY[i]-2,size) | |
strokeWidth(1) | |
stroke(66, 109, 141, 255) | |
fill(143, 182, 198, 255) | |
ellipse(slotsX[i],slotsY[i],size) | |
popStyle() | |
end | |
--draw the ball with a shadow too | |
function DrawBall() | |
pushStyle() | |
fill(104, 126, 126, 255) | |
ellipse(ballX+2,ballY-2,size*.9) | |
fill(211, 120, 127, 100) | |
ellipse(ballX,ballY,size*.9) | |
popStyle() | |
end | |
--# Step_4 | |
_ENV = localise(4) --DELETE this line if you copy this code to another project (it is used to manage tab changes) | |
--get our ball to move as the iPad tilts | |
function setup() | |
size=50 | |
SetupSlots() | |
setupBall() | |
--fix the iPad orientation so the display doesnt rotate as you turn it | |
supportedOrientations(LANDSCAPE_RIGHT) | |
print("move the ball as the iPad tilts") | |
end | |
function SetupSlots() | |
--set up one in each corner of the screen | |
slotsX={} --x pos | |
slotsY={} --y pos | |
offset=200 | |
slotsX[1]=offset slotsY[1]=HEIGHT-offset --top left | |
slotsX[2]=WIDTH-offset slotsY[2]=HEIGHT-offset --top right | |
slotsX[3]=offset slotsY[3]=offset --bottom left | |
slotsX[4]=WIDTH-offset slotsY[4]=offset --bottom right | |
numSlots=4 --number of slots | |
end | |
function setupBall() | |
ballX=WIDTH/2 + 200*(math.random()-.5) | |
ballY=HEIGHT/2 + 200*(math.random()-.5) | |
ballSize=size*.9 | |
ballSpeed=2 | |
end | |
function draw() | |
background(151, 190, 215, 255) | |
for i=1,numSlots do | |
DrawSlot(i) | |
end | |
DrawBall() | |
end | |
function DrawSlot(i) | |
pushStyle() | |
fill(78, 125, 148, 255) | |
ellipse(slotsX[i]+2,slotsY[i]-2,size) | |
strokeWidth(1) | |
stroke(66, 109, 141, 255) | |
fill(143, 182, 198, 255) | |
ellipse(slotsX[i],slotsY[i],size) | |
popStyle() | |
end | |
function DrawBall() | |
--adjust position -- this is the new code | |
--it is simpler than it looks | |
--it takes the current x (or y) position, adds "gravity" (depending on the tilt of the iPad) | |
--with a minimum value of 0 and a maximum of width/height, ie the ball can't go past the edge | |
ballX=math.max(ballSize/2,math.min(WIDTH-ballSize/2,ballX+Gravity.x*ballSpeed)) | |
ballY=math.max(ballSize/2,math.min(HEIGHT-ballSize/2,ballY+Gravity.y*ballSpeed)) | |
--draw ball as usual | |
pushStyle() | |
fill(104, 126, 126, 255) | |
ellipse(ballX+2,ballY-2,ballSize) | |
fill(211, 120, 127, 100) | |
ellipse(ballX,ballY,ballSize) | |
popStyle() | |
end | |
--# Step_5 | |
_ENV = localise(5) --DELETE this line if you copy this code to another project (it is used to manage tab changes) | |
--get our ball to fall into a slot if it gets close enough | |
function setup() | |
size=50 | |
SetupSlots() | |
setupBall() | |
supportedOrientations(LANDSCAPE_RIGHT) | |
print("get our ball to fall into slots") | |
end | |
function SetupSlots() | |
--set up one in each corner of the screen | |
slotsX={} --x pos | |
slotsY={} --y pos | |
offset=200 | |
slotsX[1]=offset slotsY[1]=HEIGHT-offset --top left | |
slotsX[2]=WIDTH-offset slotsY[2]=HEIGHT-offset --top right | |
slotsX[3]=offset slotsY[3]=offset --bottom left | |
slotsX[4]=WIDTH-offset slotsY[4]=offset --bottom right | |
numSlots=4 --number of slots | |
end | |
function setupBall() | |
ballX=WIDTH/2 + 200*(math.random()-.5) | |
ballY=HEIGHT/2 + 200*(math.random()-.5) | |
ballSize=size*.9 | |
ballSpeed=2 | |
ballMove=true --NEW this will be set to false when the ball lands in a slot | |
end | |
function draw() | |
background(151, 190, 215, 255) | |
for i=1,numSlots do | |
DrawSlot(i) | |
end | |
DrawBall() | |
end | |
function DrawSlot(i) | |
pushStyle() | |
fill(78, 125, 148, 255) | |
ellipse(slotsX[i]+2,slotsY[i]-2,size) | |
strokeWidth(1) | |
stroke(66, 109, 141, 255) | |
fill(143, 182, 198, 255) | |
ellipse(slotsX[i],slotsY[i],size) | |
popStyle() | |
end | |
function DrawBall() | |
--adjust position | |
if ballMove then --if we're not in a slot, then move using gravity | |
ballX=math.max(ballSize/2,math.min(WIDTH-ballSize/2,ballX+Gravity.x*ballSpeed)) | |
ballY=math.max(ballSize/2,math.min(HEIGHT-ballSize/2,ballY+Gravity.y*ballSpeed)) | |
--test if we've fallen into any slots | |
for i=1,numSlots do | |
--fall into slot if we are within half the combined radius of ball and slot | |
if vec2(ballX,ballY):dist(vec2(slotsX[i],slotsY[i]))<(size+ballSize)/4 then | |
--if we fall into a slot, set the x and y position to the centre of the slot | |
--and set ballMove to false | |
ballX=slotsX[i] | |
ballY=slotsY[i] | |
ballMove=false | |
end | |
end | |
end | |
pushStyle() | |
fill(104, 126, 126, 255) | |
ellipse(ballX+2,ballY-2,ballSize) | |
fill(211, 120, 127, 100) | |
ellipse(ballX,ballY,ballSize) | |
popStyle() | |
end | |
--# Step_6 | |
_ENV = localise(6) --DELETE this line if you copy this code to another project (it is used to manage tab changes) | |
--test the use of gravity | |
--why? We need more balls, and it is difficult to collide them accurately | |
--physics will do it for us | |
--so we set up a little trial to see if we can control a ball using physics and tilting the iPad | |
function setup() | |
CreateBall() | |
CreateWalls() --create walls to bounce off | |
supportedOrientations(LANDSCAPE_RIGHT) | |
print("try using physics to move the ball") | |
end | |
function CreateBall() | |
--create a physics object for our ball | |
--the object is invisible, we draw the ball on top of it | |
--but we can use its x and y position to tell us where to draw | |
ballSize=50 | |
ballX=200 ballY=300 | |
b=physics.body(CIRCLE,ballSize/2) --note we use radius not diameter here | |
b.x=ballX b.y=ballY --initial position of physics body | |
b.restitution=0.6 --bounciness when it hits sides or another ball | |
end | |
--create a wall round each edge so our balls have something to bounce off | |
--there is a special physics object EDGE for this purpose (basically it's a straight line) | |
function CreateWalls() | |
w1=physics.body(EDGE,vec2(0,0),vec2(WIDTH,0)) | |
w2=physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT)) | |
w3=physics.body(EDGE,vec2(0,HEIGHT),vec2(WIDTH,HEIGHT)) | |
w4=physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT)) | |
end | |
function draw() | |
background(151, 190, 215, 255) | |
--tell Codea to use the iPad orientation to set gravity | |
physics.gravity(Gravity) | |
fill(255) | |
--draw the ball over the top of the physics object (ie same x and y) | |
ellipse(b.x,b.y,ballSize) | |
end | |
--# Step_7 | |
_ENV = localise(7) --DELETE this line if you copy this code to another project (it is used to manage tab changes) | |
--add gravity to our previous work | |
function setup() | |
size=50 | |
CreateWalls() | |
SetupSlots() | |
setupBall() | |
supportedOrientations(LANDSCAPE_RIGHT) | |
print("use physics and tilting to put the ball in a slot") | |
end | |
--create a wall round each edge so our balls have something to bounce off | |
--there is a special physics object EDGE for this purpose (basically it's a straight line) | |
function CreateWalls() | |
w1=physics.body(EDGE,vec2(0,0),vec2(WIDTH,0)) | |
w2=physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT)) | |
w3=physics.body(EDGE,vec2(0,HEIGHT),vec2(WIDTH,HEIGHT)) | |
w4=physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT)) | |
end | |
function SetupSlots() | |
--set up one in each corner of the screen | |
slotsX={} --x pos | |
slotsY={} --y pos | |
offset=200 | |
slotsX[1]=offset slotsY[1]=HEIGHT-offset --top left | |
slotsX[2]=WIDTH-offset slotsY[2]=HEIGHT-offset --top right | |
slotsX[3]=offset slotsY[3]=offset --bottom left | |
slotsX[4]=WIDTH-offset slotsY[4]=offset --bottom right | |
numSlots=4 --number of slots | |
end | |
function setupBall() | |
ballX=WIDTH/2 + 200*(math.random()-.5) | |
ballY=HEIGHT/2 + 200*(math.random()-.5) | |
ballSize=size*.9 | |
ballMove=true --can ball roll | |
b=physics.body(CIRCLE,ballSize/2) --note we use radius not diameter here | |
b.x=ballX b.y=ballY --initial position | |
b.restitution=0.6 --bounciness when it hits sides or another ball | |
end | |
function draw() | |
background(151, 190, 215, 255) | |
--tell Codea to use the iPad orientation to set gravity | |
physics.gravity(Gravity) | |
for i=1,numSlots do | |
DrawSlot(i) | |
end | |
DrawBall() | |
end | |
function DrawSlot(i) | |
pushStyle() | |
fill(78, 125, 148, 255) | |
ellipse(slotsX[i]+2,slotsY[i]-2,size) | |
strokeWidth(1) | |
stroke(66, 109, 141, 255) | |
fill(143, 182, 198, 255) | |
ellipse(slotsX[i],slotsY[i],size) | |
popStyle() | |
end | |
function DrawBall() | |
--test if we've fallen into any holes | |
if ballMove then | |
ballX=b.x | |
ballY=b.y | |
for i=1,numSlots do | |
if vec2(ballX,ballY):dist(vec2(slotsX[i],slotsY[i]))<(size+ballSize)/4 then | |
ballX=slotsX[i] | |
ballY=slotsY[i] | |
ballMove=false | |
end | |
end | |
end | |
pushStyle() | |
fill(104, 126, 126, 255) | |
ellipse(ballX+2,ballY-2,ballSize) | |
fill(211, 120, 127, 100) | |
ellipse(ballX,ballY,ballSize) | |
popStyle() | |
end | |
--get rid of physics object when we're done | |
function Cleanup() | |
b:destroy() | |
end | |
--# Step_8 | |
_ENV = localise(8) --DELETE this line if you copy this code to another project (it is used to manage tab changes) | |
--add more balls | |
function setup() | |
size=50 | |
CreateWalls() | |
SetupSlots() | |
setupBalls() | |
supportedOrientations(LANDSCAPE_RIGHT) | |
print("add more balls") | |
end | |
--create a wall round each edge so our balls have something to bounce off | |
--there is a special physics object EDGE for this purpose (basically it's a straight line) | |
function CreateWalls() | |
w1=physics.body(EDGE,vec2(0,0),vec2(WIDTH,0)) | |
w2=physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT)) | |
w3=physics.body(EDGE,vec2(0,HEIGHT),vec2(WIDTH,HEIGHT)) | |
w4=physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT)) | |
end | |
function SetupSlots() | |
--set up one in each corner of the screen | |
slotsX={} --x pos | |
slotsY={} --y pos | |
offset=200 | |
slotsX[1]=offset slotsY[1]=HEIGHT-offset --top left | |
slotsX[2]=WIDTH-offset slotsY[2]=HEIGHT-offset --top right | |
slotsX[3]=offset slotsY[3]=offset --bottom left | |
slotsX[4]=WIDTH-offset slotsY[4]=offset --bottom right | |
numSlots=4 --number of slots | |
end | |
function setupBalls() | |
numBalls=4 | |
balls={} | |
for i=1,numBalls do | |
b={} | |
b.x=WIDTH/2 + 200*(math.random()-.5) | |
b.y=HEIGHT/2 + 200*(math.random()-.5) | |
ballSize=size*.9 | |
b.move=true --can ball roll | |
b.p=physics.body(CIRCLE,ballSize/2) --note we use radius not diameter here | |
b.p.x=b.x | |
b.p.y=b.y --initial position | |
b.p.restitution=0.6 --bounciness when it hits sides or another ball | |
table.insert(balls,b) | |
end | |
end | |
function draw() | |
background(151, 190, 215, 255) | |
--tell Codea to use the iPad orientation to set gravity | |
physics.gravity(Gravity) | |
for i=1,numSlots do | |
DrawSlot(i) | |
end | |
for i=1,numBalls do | |
DrawBall(i) | |
end | |
end | |
function DrawSlot(i) | |
pushStyle() | |
fill(78, 125, 148, 255) | |
ellipse(slotsX[i]+2,slotsY[i]-2,size) | |
strokeWidth(1) | |
stroke(66, 109, 141, 255) | |
fill(143, 182, 198, 255) | |
ellipse(slotsX[i],slotsY[i],size) | |
popStyle() | |
end | |
function DrawBall(i) | |
--test if we've fallen into any holes | |
b=balls[i] --just to save us typing and make the code neater | |
if b.move then | |
b.x=b.p.x | |
b.y=b.p.y | |
for i=1,numSlots do | |
if vec2(b.x,b.y):dist(vec2(slotsX[i],slotsY[i]))<(size+ballSize)/4 then | |
b.x=slotsX[i] | |
b.y=slotsY[i] | |
b.move=false | |
end | |
end | |
else | |
b.p.x=b.x | |
b.p.y=b.y | |
end | |
pushStyle() | |
fill(104, 126, 126, 255) | |
ellipse(b.x+2,b.y-2,ballSize) | |
fill(211, 120, 127, 100) | |
ellipse(b.x,b.y,ballSize) | |
popStyle() | |
end | |
--get rid of physics objects when we're done | |
function Cleanup() | |
for i=1,numBalls do | |
balls[i].p:destroy() | |
end | |
balls=nil | |
end | |
--# Step_9 | |
_ENV = localise(9) --DELETE this line if you copy this code to another project (it is used to manage tab changes) | |
--get our balls to fall out of the slots if we tilt too much | |
function setup() | |
size=50 | |
CreateWalls() | |
SetupSlots() | |
setupBalls() | |
slotThreshold=(size+ballSize)/4 | |
tiltThreshold=0.7 | |
supportedOrientations(LANDSCAPE_RIGHT) | |
print("make the balls fall out of slots if the iPad tilts too much") | |
end | |
--create a wall round each edge so our balls have something to bounce off | |
--there is a special physics object EDGE for this purpose (basically it's a straight line) | |
function CreateWalls() | |
w1=physics.body(EDGE,vec2(0,0),vec2(WIDTH,0)) | |
w2=physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT)) | |
w3=physics.body(EDGE,vec2(0,HEIGHT),vec2(WIDTH,HEIGHT)) | |
w4=physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT)) | |
end | |
function SetupSlots() | |
--set up one in each corner of the screen | |
slotsX={} --x pos | |
slotsY={} --y pos | |
offset=200 | |
slotsX[1]=offset slotsY[1]=HEIGHT-offset --top left | |
slotsX[2]=WIDTH-offset slotsY[2]=HEIGHT-offset --top right | |
slotsX[3]=offset slotsY[3]=offset --bottom left | |
slotsX[4]=WIDTH-offset slotsY[4]=offset --bottom right | |
numSlots=4 --number of slots | |
end | |
function setupBalls() | |
numBalls=4 | |
balls={} | |
for i=1,numBalls do | |
b={} | |
b.x=WIDTH/2 + 200*(math.random()-.5) | |
b.y=HEIGHT/2 + 200*(math.random()-.5) | |
ballSize=size*.9 | |
b.move=true --can ball roll | |
b.p=physics.body(CIRCLE,ballSize/2) --note we use radius not diameter here | |
b.p.x=b.x | |
b.p.y=b.y --initial position | |
b.p.restitution=0.6 --bounciness when it hits sides or another ball | |
table.insert(balls,b) | |
end | |
end | |
function draw() | |
background(151, 190, 215, 255) | |
--tell Codea to use the iPad orientation to set gravity | |
physics.gravity(Gravity) | |
for i=1,numSlots do | |
DrawSlot(i) | |
end | |
for i=1,numBalls do | |
DrawBall(i) | |
end | |
end | |
function DrawSlot(i) | |
pushStyle() | |
fill(78, 125, 148, 255) | |
ellipse(slotsX[i]+2,slotsY[i]-2,size) | |
strokeWidth(1) | |
stroke(66, 109, 141, 255) | |
fill(143, 182, 198, 255) | |
ellipse(slotsX[i],slotsY[i],size) | |
popStyle() | |
end | |
function DrawBall(i) | |
--test if we've fallen into any holes | |
b=balls[i] --just to save us typing and make the code neater | |
if b.move then | |
b.x=b.p.x | |
b.y=b.p.y | |
for i=1,numSlots do | |
if vec2(b.x,b.y):dist(vec2(slotsX[i],slotsY[i]))<slotThreshold then | |
b.x=slotsX[i] | |
b.y=slotsY[i] | |
b.move=false | |
end | |
end | |
elseif math.abs(Gravity.x)>tiltThreshold or math.abs(Gravity.y)>tiltThreshold then | |
b.x=b.x+slotThreshold*Gravity.x/tiltThreshold | |
b.y=b.y+slotThreshold*Gravity.y/tiltThreshold | |
b.p.x=b.x | |
b.p.y=b.y | |
b.move=true | |
else | |
b.p.x=b.x | |
b.p.y=b.y | |
end | |
pushStyle() | |
fill(104, 126, 126, 255) | |
ellipse(b.x+2,b.y-2,ballSize) | |
fill(211, 120, 127, 100) | |
ellipse(b.x,b.y,ballSize) | |
popStyle() | |
end | |
--get rid of physics objects when we're done | |
function Cleanup() | |
for i=1,numBalls do | |
balls[i].p:destroy() | |
end | |
balls=nil | |
end | |
--# Step_10 | |
_ENV = localise(10) --DELETE this line if you copy this code to another project (it is used to manage tab changes) | |
--add some obstacles | |
function setup() | |
size=50 | |
CreateWallsAndObstacles() | |
SetupSlots() | |
setupBalls() | |
slotThreshold=(size+ballSize)/4 | |
tiltThreshold=0.7 | |
supportedOrientations(LANDSCAPE_RIGHT) | |
end | |
--create a wall round each edge so our balls have something to bounce off | |
--there is a special physics object EDGE for this purpose (basically it's a straight line) | |
function CreateWallsAndObstacles() | |
w1=physics.body(EDGE,vec2(0,0),vec2(WIDTH,0)) | |
w2=physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT)) | |
w3=physics.body(EDGE,vec2(0,HEIGHT),vec2(WIDTH,HEIGHT)) | |
w4=physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT)) | |
--obstacles | |
--create a table to hold their positions so we know where to draw them on the screen | |
O={} | |
O[1]={} | |
O[1].start=vec2(100,HEIGHT/2) | |
O[1].finish=vec2(WIDTH-100,HEIGHT/2) | |
O[1].b=physics.body(EDGE,O[1].start,O[1].finish) | |
O[2]={} | |
O[2].start=vec2(WIDTH/2,100) | |
O[2].finish=vec2(WIDTH/2,HEIGHT-100) | |
O[2].b=physics.body(EDGE,O[2].start,O[2].finish) | |
numObstacles=2 | |
print("add some obstacles") | |
end | |
function SetupSlots() | |
--set up one in each corner of the screen | |
slotsX={} --x pos | |
slotsY={} --y pos | |
offset=200 | |
slotsX[1]=offset slotsY[1]=HEIGHT-offset --top left | |
slotsX[2]=WIDTH-offset slotsY[2]=HEIGHT-offset --top right | |
slotsX[3]=offset slotsY[3]=offset --bottom left | |
slotsX[4]=WIDTH-offset slotsY[4]=offset --bottom right | |
numSlots=4 --number of slots | |
end | |
function setupBalls() | |
numBalls=4 | |
balls={} | |
for i=1,numBalls do | |
b={} | |
b.x=WIDTH/2 + 200*(math.random()-.5) | |
b.y=HEIGHT/2 + 200*(math.random()-.5) | |
ballSize=size*.9 | |
b.move=true --can ball roll | |
b.p=physics.body(CIRCLE,ballSize/2) --note we use radius not diameter here | |
b.p.x=b.x | |
b.p.y=b.y --initial position | |
b.p.restitution=0.6 --bounciness when it hits sides or another ball | |
table.insert(balls,b) | |
end | |
end | |
function draw() | |
background(151, 190, 215, 255) | |
--tell Codea to use the iPad orientation to set gravity | |
physics.gravity(Gravity) | |
for i=1,numSlots do | |
DrawSlot(i) | |
end | |
for i=1,numBalls do | |
DrawBall(i) | |
end | |
for i=1,numObstacles do | |
drawObstacles() | |
end | |
end | |
function DrawSlot(i) | |
pushStyle() | |
fill(78, 125, 148, 255) | |
ellipse(slotsX[i]+2,slotsY[i]-2,size) | |
strokeWidth(1) | |
stroke(66, 109, 141, 255) | |
fill(143, 182, 198, 255) | |
ellipse(slotsX[i],slotsY[i],size) | |
popStyle() | |
end | |
function DrawBall(i) | |
--test if we've fallen into any holes | |
b=balls[i] --just to save us typing and make the code neater | |
if b.move then | |
b.x=b.p.x | |
b.y=b.p.y | |
for i=1,numSlots do | |
if vec2(b.x,b.y):dist(vec2(slotsX[i],slotsY[i]))<slotThreshold then | |
b.x=slotsX[i] | |
b.y=slotsY[i] | |
b.move=false | |
end | |
end | |
elseif math.abs(Gravity.x)>tiltThreshold or math.abs(Gravity.y)>tiltThreshold then | |
b.x=b.x+slotThreshold*Gravity.x/tiltThreshold | |
b.y=b.y+slotThreshold*Gravity.y/tiltThreshold | |
b.p.x=b.x | |
b.p.y=b.y | |
b.move=true | |
else | |
b.p.x=b.x | |
b.p.y=b.y | |
end | |
pushStyle() | |
fill(104, 126, 126, 255) | |
ellipse(b.x+2,b.y-2,ballSize) | |
fill(211, 120, 127, 100) | |
ellipse(b.x,b.y,ballSize) | |
popStyle() | |
end | |
function drawObstacles() | |
pushStyle() | |
strokeWidth(3) | |
lineCapMode(ROUND) | |
stroke(77, 61, 197, 255) | |
for i=1,numObstacles do | |
line(O[i].start.x,O[i].start.y,O[i].finish.x,O[i].finish.y) | |
end | |
popStyle() | |
end | |
--get rid of physics objects when we're done | |
function Cleanup() | |
for i=1,numBalls do | |
balls[i].p:destroy() | |
end | |
balls=nil | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment