The code below is a first prototype for a game that could involve any number of balls bouncing around on the screen. The prototype just implements two balls right now and also just one level.
The code places two balls on the screen, moves them around in a billard-ball fashion and listens for touch inputs to check if a touch has hit one of the balls during either a began or moved phase. It keeps count of a bunch of things, including the number of balls hit (numberOfBallsHit), and a table with references to the balls that have been hit. Again, in the future there could be many more balls than just two.
Once a ball has been hit, the code sets the velocity of that ball to zero, so it stops its movement on the screen.
Once both balls have been hit, the code makes all of the balls disappear. This is meant to be the end of that level, i.e. all balls have been cleared.
At this point, the intention is that the code initialises the next level (which could have different balls), but an error occurs. In this simple prototype there is only one level, so my intention is that once both balls have been hit and removed from the screen, the code should initialize this same level again, i.e. the balls should be newly created and placed in the upper left corner of the screen and start moving again. However, I can’t figure out how to fix the bug and suspect it has something to do with fundamental game architecture , i.e. how I’ve implemented the game loop and the event listeners and where I’ve placed the lines that trigger the ending of one level and the initialisation of the next level.
Can someone help to make this prototype work? After both balls have been hit and been removed from the screen, the initializeNextLevel function is meant to be executed and the gameLoop started again (which in the case of this simple prototype would just replay the only level that the prototype contains, i.e. starting the balls from the top left corner again). But the architecture is meant to allow for further levels to be added later.
[lua]local physics = require “physics”
physics.start()
physics.setGravity(0,0)
local numberOfBallsHit = 0
local ballsHit = {}
local ball1Hit = false
local ball2Hit = false
local levelHasEnded = false
local gameLoopSpeed = 200
local function emitAndInitializeBall1()
ball1 = display.newImage (“ball.png”)
ball1.name = “ball1”
local Ball1Scale = 2
ball1:scale(Ball1Scale, Ball1Scale)
ball1.x = 0; ball1.y = 0
ball1VelocityX = 2
ball1VelocityY = -0.5
physics.addBody(ball1, “dynamic”, {density=1.0, friction=0.9, bounce=0.8, radius=15*Ball1Scale})
ball1:addEventListener(“touch”, CheckIfBallsAreHit)
end
local function emitAndInitializeBall2()
ball2 = display.newImage (“ball.png”)
ball2.name = “ball2”
local Ball2Scale = 2
ball2:scale(Ball2Scale, Ball2Scale)
ball2.x = 0; ball2.y = 0
ball2VelocityX = 0.25
ball2VelocityY = -0.5
physics.addBody(ball2, “dynamic”, {density=1.0, friction=0.9, bounce=0.8, radius=15*Ball2Scale})
ball2:addEventListener(“touch”, CheckIfBallsAreHit)
end
local function moveBalls()
if (ball1) then
ball1.x = ball1.x + ball1VelocityX
ball1.y = ball1.y + ball1VelocityY
if ball1.x < 0 or ball1.x + ball1.width > display.contentWidth then
ball1VelocityX = -ball1VelocityX
end
if ball1.y < 0 or ball1.y + ball1.height > display.contentHeight then
ball1VelocityY = -ball1VelocityY
end
end
if (ball2) then
ball2.x = ball2.x + ball2VelocityX
ball2.y = ball2.y + ball2VelocityY
if ball2.x < 0 or ball2.x + ball2.width > display.contentWidth then
ball2VelocityX = -ball2VelocityX
end
if ball2.y < 0 or ball2.y + ball2.height > display.contentHeight then
ball2VelocityY = -ball2VelocityY
end
end
return true
end
function CheckIfBallsAreHit(event)
if (event.phase == “began” or event.phase == “moved”) then
if event.target then – event.target = nil for as long as line hasn’t hit any balls
if (event.target.name==“ball1” and ball1Hit==false) then
ball1VelocityX = 0
ball1VelocityY = 0
numberOfBallsHit = numberOfBallsHit +1
table.insert(ballsHit, 1)
ball1:removeEventListener(“touch”, CheckIfBallsAreHit)
ball1Hit = true
end
if (event.target.name==“ball2” and ball2Hit==false) then
ball2VelocityX = 0
ball2VelocityY = 0
numberOfBallsHit = numberOfBallsHit +1
table.insert(ballsHit, 2)
ball2:removeEventListener(“touch”, CheckIfBallsAreHit)
ball2Hit = true
end
end
end
return false
end
local function endLevel()
Runtime:removeEventListener(“enterFrame”, moveBalls)
Runtime:removeEventListener(“touch”, CheckIfBallsAreHit)
ball1:removeSelf()
ball1.myName=nil
ball2:removeSelf()
ball2.myName=nil
emitter1:removeSelf()
end
local function initializeNextLevel()
numberOfBallsHit = 0
ballsHit = {}
ball1Hit = false
ball2Hit = false
levelHasEnded = false
emitAndInitializeBall1()
timer.performWithDelay(1, emitAndInitializeBall2)
Runtime:addEventListener(“enterFrame”, moveBalls)
Runtime:addEventListener( “touch”, CheckIfBallsAreHit )
end
local function gameLoop()
if numberOfBallsHit==2 and levelHasEnded==false then
endLevel()
levelHasEnded = true
numberOfBallsHit = 0
end
if levelHasEnded==true then
timer.performWithDelay(5000, initializeNextLevel)
levelHasEnded = false
end
end
–Start game
emitAndInitializeBall1()
timer.performWithDelay(1000, emitAndInitializeBall2)
Runtime:addEventListener(“enterFrame”, moveBalls)
Runtime:addEventListener( “touch”, CheckIfBallsAreHit)
timer.performWithDelay(gameLoopSpeed, gameLoop,0)
[/lua]
Hmmm … my indentations are all gone with the wrapping-in-tags-method of pasting … I’ll try again with the code icon …
local physics = require "physics" physics.start() physics.setGravity(0,0) local numberOfBallsHit = 0 local ballsHit = {} local ball1Hit = false local ball2Hit = false local levelHasEnded = false local gameLoopSpeed = 200 local function emitAndInitializeBall1() ball1 = display.newImage ("ball.png") ball1.name = "ball1" local Ball1Scale = 2 ball1:scale(Ball1Scale, Ball1Scale) ball1.x = 0; ball1.y = 0 ball1VelocityX = 2 ball1VelocityY = -0.5 physics.addBody(ball1, "dynamic", {density=1.0, friction=0.9, bounce=0.8, radius=15\*Ball1Scale}) ball1:addEventListener("touch", CheckIfBallsAreHit) end local function emitAndInitializeBall2() ball2 = display.newImage ("ball.png") ball2.name = "ball2" local Ball2Scale = 2 ball2:scale(Ball2Scale, Ball2Scale) ball2.x = 0; ball2.y = 0 ball2VelocityX = 0.25 ball2VelocityY = -0.5 physics.addBody(ball2, "dynamic", {density=1.0, friction=0.9, bounce=0.8, radius=15\*Ball2Scale}) ball2:addEventListener("touch", CheckIfBallsAreHit) end local function moveBalls() if (ball1) then ball1.x = ball1.x + ball1VelocityX ball1.y = ball1.y + ball1VelocityY if ball1.x \< 0 or ball1.x + ball1.width \> display.contentWidth then ball1VelocityX = -ball1VelocityX end if ball1.y \< 0 or ball1.y + ball1.height \> display.contentHeight then ball1VelocityY = -ball1VelocityY end end if (ball2) then ball2.x = ball2.x + ball2VelocityX ball2.y = ball2.y + ball2VelocityY if ball2.x \< 0 or ball2.x + ball2.width \> display.contentWidth then ball2VelocityX = -ball2VelocityX end if ball2.y \< 0 or ball2.y + ball2.height \> display.contentHeight then ball2VelocityY = -ball2VelocityY end end return true end function CheckIfBallsAreHit(event) if (event.phase == "began" or event.phase == "moved") then if event.target then -- event.target = nil for as long as line hasn't hit any balls if (event.target.name=="ball1" and ball1Hit==false) then ball1VelocityX = 0 ball1VelocityY = 0 numberOfBallsHit = numberOfBallsHit +1 table.insert(ballsHit, 1) ball1:removeEventListener("touch", CheckIfBallsAreHit) ball1Hit = true end if (event.target.name=="ball2" and ball2Hit==false) then ball2VelocityX = 0 ball2VelocityY = 0 numberOfBallsHit = numberOfBallsHit +1 table.insert(ballsHit, 2) ball2:removeEventListener("touch", CheckIfBallsAreHit) ball2Hit = true end end end return false end local function endLevel() Runtime:removeEventListener("enterFrame", moveBalls) Runtime:removeEventListener("touch", CheckIfBallsAreHit) ball1:removeSelf() ball1.myName=nil ball2:removeSelf() ball2.myName=nil emitter1:removeSelf() end local function initializeNextLevel() numberOfBallsHit = 0 ballsHit = {} ball1Hit = false ball2Hit = false levelHasEnded = false emitAndInitializeBall1() timer.performWithDelay(1, emitAndInitializeBall2) Runtime:addEventListener("enterFrame", moveBalls) Runtime:addEventListener( "touch", CheckIfBallsAreHit ) end local function gameLoop() if numberOfBallsHit==2 and levelHasEnded==false then endLevel() levelHasEnded = true numberOfBallsHit = 0 end if levelHasEnded==true then timer.performWithDelay(5000, initializeNextLevel) levelHasEnded = false end end --Start game emitAndInitializeBall1() timer.performWithDelay(1000, emitAndInitializeBall2) Runtime:addEventListener("enterFrame", moveBalls) Runtime:addEventListener( "touch", CheckIfBallsAreHit) timer.performWithDelay(gameLoopSpeed, gameLoop,0)
Hmmm … now the colors didn’t come through … not sure how to paste my code in here so it has the indentations and color coding. I’m copying and pasting from Sublime Text Editor.