Hi James thanks for replying.
Here’s my code - I’ve taken out a few things where I could but this is the gist of it. The game over code is indicated towards the end.
I realise this is long - I’m still learning and I guess my next lesson will be modules.
Since posting my original question I’m a small step closer to repositioning everything just before leaving the game scene - not removing anything - and then having it ready to begin when the player returns. The issue right now is when I try to move the character on returning to the game I get ‘Attempt to call method ‘applyLinearImpulse’ (a nil value)’.
I think the main problem is that the game file is so long and everything has become so interconnected that if I reposition anything I get errors. I know maybe I ought to have put some things in different scene functions… could that be an issue? I’d just like to be able to ‘restart’ the game either by returning to a reinitialised state, or by removing all elements and rebuilding.
To give you a picture of the game - the player character is Arthur - he’s chased by a squaddie. Arthur either gets caught and it’s game over, or he makes it to the end and succeeds. On the way he collects objects - one shown here is beer. The score is displayed on the end screen (via a myData.lua file to pass the variable).
Many thanks for any help, this is driving me around the bend.
[lua]
–
– game.lua
–
display.setStatusBar(display.HiddenStatusBar)
local composer = require( “composer” )
local scene = composer.newScene()
local myData = require( “mydata” )
local physics = require( “physics” )
system.activate( “multitouch” )
physics.start()
physics.pause()
local textureFilter = “nearest”
local screenW, screenH, halfW = display.contentWidth, display.contentHeight, display.contentWidth*0.5
local arthur
local map
local touchright = “yes”
local touchleft = “yes”
local score
local speed
local leftbutton
local rightbutton
local jumpbutton
local framerate = 900
local vx = 0
local vy = 0
local sx = 0
local sy = 0
local canJump = 0
local runsound = audio.loadSound ( “audio/runsound.wav” )
local gameisplaying = 0
local gameover = 0
local dusk = require(“Dusk.Dusk”)
map = dusk.buildMap(“levelgraphic2.json”)
map:scale (1, 1)
map.setTrackingLevel(0.9)
map.setCameraBounds ({ xMin = display.contentCenterX, yMin = display.contentCenterY, xMax = map.data.width - display.contentCenterX, yMax = map.data.height - display.contentCenterY })
map.layer[1].setCameraOffset(14, 24)
map.layer[2].setCameraOffset(14, 24)
function scene:create( event )
local sceneGroup = self.view
----------------------------------------------------------scene management
gui = display.newGroup()
gui.front = display.newGroup()
gui.back = display.newGroup()
gui:insert(gui.back) --map is in here (characters are in map)
gui:insert(gui.front) --buttons
gui.back:insert(map)
sceneGroup:insert(gui)
----------------------------------------------------------Target for level completion
local pubdoor = display.newImageRect( “pubdoor.png”, 40, 55 )
pubdoor.x, pubdoor.y = map.data.width - 128, 106
physics.addBody( pubdoor, “static” )
pubdoor.id = “pubdoor”
pubdoor.title = “pubdoor”
pubdoor.myName = “pubdoor”
map.layer[1]:insert(pubdoor)
---------------------------------------------------------Player
local sheet1 = graphics.newImageSheet( “arthur.png”, { width=25, height=37, numFrames=14 } )
local arthurData =
{
{ name=“standing”, frames= { 13 } },
{ name=“running”, start=1, count=12, time=framerate },
{ name=“beenhit”, frames= { 14 } }
}
local arthur = display.newSprite( sheet1, arthurData )
arthur.x = 140
arthur.y = 106
arthur.id = “arthur”
arthur.title = “arthur”
arthur.myName = “arthur”
arthur.rotation = 0
arthur.anchorY = 1
arthur.anchorX = 0.5
arthur:setSequence(“standing”)
arthur:play()
physics.addBody( arthur, “dynamic”, { density=0.9, friction=0.5, bounce=0} )
arthur.isFixedRotation = true
map.layer[1]:insert(arthur)
-------------------------------check for movement and set correct animation for player
local function motioncheck (vx)
local current_sequence = arthur.sequence
if vx > 1.5 then
if current_sequence == “running” then
return true
else
arthur:setSequence( “running” )
arthur:play()
end
end
if vx <= 1.5 then
if current_sequence == “standing” then
return true
else
arthur:setSequence(“standing”)
arthur:play()
end
end
end
---------------------------------------------------------------Create Squaddie
local sheet2 = graphics.newImageSheet( “squaddie.png”, { width=25, height=37, numFrames=16 } )
local squaddieData =
{
{ name=“running”, start=1, count=12, time=framerate },
{ name=“punch”, start=14, count=3, time=500, loopCount =1 }
}
local squaddie = display.newSprite( sheet2, squaddieData)
squaddie.x = -10
squaddie.y = 105
squaddie.id = “squaddie”
squaddie.title = “squaddie”
squaddie.myName = “squaddie”
squaddie:setSequence(“running”)
squaddie:play()
physics.addBody( squaddie, “dynamic”, { density=2, friction=1, bounce=0.0 } )
squaddie.isFixedRotation = true
map.layer[1]:insert(squaddie)
----------------------------------------------------Graphics at the top of the screen
------BEER---------
local beerGlimmer = display.newImageRect( “glimmer.png”, 35, 35 )
beerGlimmer.anchorX = 0.5
beerGlimmer.anchorY = 0.5
beerGlimmer.xScale = 2
beerGlimmer.yScale = 2
beerGlimmer.x, beerGlimmer.y = (screenW/10) * 7, 20
gui.front:insert(beerGlimmer)
local sheet3 = graphics.newImageSheet( “beerweb.png”, { width=12, height=12, numFrames=6, sheetContentWidth=72, sheetContentHeight=12} )
local beerData =
{
{ name=“beerpause”, frames = {1}, time=3000, loopCount =1},
{ name=“beershining”, frames = {2,3,4,5,6}, time=300, loopCount =1 }
}
local beer = display.newSprite( sheet3, beerData )
beer.x = (screenW/10) * 7
beer.y = 20
beer:setSequence(“beerpause”)
beer:play()
gui.front:insert(beer)
local function beerListener( event )
local beer_sequence = beer.sequence
if ( event.phase == “ended” ) and beer_sequence == “beerpause” then
local beerData = target
beer:setSequence( “beershining” )
beer:play()
elseif ( event.phase == “ended” ) and beer_sequence == “beershining” then
local beerData = target
beer:setSequence( “beerpause” )
beer:play()
end
end
local function spinBeerGlimmer (event)
transition.to( beerGlimmer, { rotation = beerGlimmer.rotation-360, time=4000, onComplete=spinBeerGlimmer } )
end
-------------------------------------------display number of collected items
local beerscoretext = display.newText( “” , ((screenW/10) * 7)+3, 44, native.systemFont, 14 )
beerscoretext:setFillColor( 1, 1, 1 )
beerscoretext.align = “center”
gui.front:insert(beerscoretext)
------------------------------------------Collectables that float in
---- collectable beer-------
local collectablebeer = display.newSprite( sheet3, beerData )
collectablebeer:setSequence(“beershining”)
collectablebeer.collected = 0
collectablebeer:play()
collectablebeer.x = 350
collectablebeer.y = math.random (32, 96)
map.layer [1]:insert(collectablebeer)
physics.addBody( collectablebeer, “static”, { density=0.1, friction=1, bounce=0.0, radius = 5 } )
collectablebeer.isFixedRotation = true
collectablebeer.speed = 0
collectablebeer.initY = collectablebeer.y
collectablebeer.amp = math.random(5,32)
collectablebeer.angle = math.random (1, 360)
collectablebeer.myName = “collectablebeer”
local function collectablebeerListener( event )
local collectablebeer_sequence = collectablebeer.sequence
if ( event.phase == “ended” ) and collectablebeer_sequence == “beerpause” then
local collectablebeerData = target
collectablebeer:setSequence( “beershining” )
collectablebeer:play()
elseif ( event.phase == “ended” ) and collectablebeer_sequence == “beershining” then
local collectablebeerData = target
collectablebeer:setSequence( “beerpause” )
collectablebeer:play()
end
end
collectablebeer:addEventListener( “sprite”, collectablebeerListener )
function scrollcollectbeer (self, event)
if self.x < (arthur.x-200) then
self.x = (arthur.x + 200)
else
if collectablebeer.collected == 0 then
self.x = self.x - self.speed
self.angle = self.angle + 0.1
self.y = self.amp * math.sin(self.angle) + self.initY
end
end
end
collectablebeer.enterFrame = scrollcollectbeer
Runtime:addEventListener(“enterFrame”, collectablebeer)
------------------invisible object that becomes the camera focus when squaddie to player distance is greater than x
local newfocus = display.newRect (arthur.x, arthur.y, 20, 30)
newfocus.strokeWidth = 3
newfocus:setFillColor( 1,1,0 )
newfocus:setStrokeColor( 1, 0, 0 )
map.layer[2]:insert(newfocus)
newfocus.alpha = 0
----------------------------------------------------------------left running button
local leftbutton = display.newRect( screenW/2, display.contentHeight-40, screenW/4, 30 )
leftbutton:setFillColor( 0, 1, 1 )
leftbutton.id = “leftbutton”
gui.front:insert(leftbutton)
--------------------------------------------------------------running mechanism (scrub buttons)
local function onButtonReleaseLeft ()
if touchright == “yes” and canJump > 0 then
audio.play ( runsound )
touchright = “no”
if vx <50 then
arthur:applyLinearImpulse( 1, 0, arthur.x, arthur.y )
end
elseif touchright == “no” then
return true
end
end
-------------------------------------------------------------------jumping functions
local function onJumpButtonRelease ( event )
if event.phase == “began” and arthur.y >105 then
print( “jumped” )
audio.play ( jumped )
arthur:applyLinearImpulse( 0, -2, arthur.x, arthur.y )
canJump = 0
return true
end
end
-----------------------------------------------------------------squaddie run function
local function squaddierun ()
random = math.random(5)
if random > 1 and sx <80 then
squaddie:applyLinearImpulse( 1.05, 0, squaddie.x, squaddie.y )
end
end
–replaces game objects on leaving game scene ready for replay on return – INCOMPLETE - unsure about this section
local function cleanup ()
squaddie:setSequence(“running”)
squaddie:play()
squaddie.x = -10
squaddie.y = 105
–arthur:setLinearVelocity( 0, 0 )
arthur.x = 140
arthur.y = 106
arthur.isSensor = false
arthur:setSequence(“standing”)
arthur:play()
gameisplaying = 1
gameover = 0
physics.addBody( arthur, “dynamic”, { density=0.9, friction=0.5, bounce=0} )
physics.start()
end
-----------------------------------------------------------when squaddie catches player
local function arthurHit (event)
–arthur:setLinearVelocity( 0, 0 )
arthur:setSequence(“beenhit”)
gameover = 1
vx, vy = 0,0
arthur:play()
arthur:applyLinearImpulse( 2, -2.5, arthur.x, arthur.y )
arthur.isSensor = true
audio.play ( scream )
timer.performWithDelay( 1000, cleanup )
end
------------------------------------------------sensor trailing player to play alert sound
local arthurrear = display.newRect (arthur.x-140, arthur.y-20, 1, 1)
arthurrear:setFillColor( 1,1,0 )
arthurrear:setStrokeColor( 1, 0, 0 )
map.layer[1]:insert(arthurrear)
arthurrear.alpha = 0
------------------------------------------------detect collision with sensor
local sounded = 0
local function hasCollided( arthurrear, squaddie )
if ( arthurrear == nil ) then
return false
end
if ( squaddie == nil ) then
return false
end
local left = arthurrear.contentBounds.xMin <= squaddie.contentBounds.xMin and arthurrear.contentBounds.xMax >= squaddie.contentBounds.xMin
local right = arthurrear.contentBounds.xMin >= squaddie.contentBounds.xMin and arthurrear.contentBounds.xMin <= squaddie.contentBounds.xMax
local up = arthurrear.contentBounds.yMin <= squaddie.contentBounds.yMin and arthurrear.contentBounds.yMax >= squaddie.contentBounds.yMin
local down = arthurrear.contentBounds.yMin >= squaddie.contentBounds.yMin and arthurrear.contentBounds.yMin <= squaddie.contentBounds.yMax
return (left or right) and (up or down)
end
local function testCollisions()
if hasCollided (arthurrear, squaddie) and sounded == 0 then
audio.play ( watchout )
sounded = 1
return true
end
end
--------------------------------------------makes collectables pass through squaddie
function squaddieCollision( event )
if ( event.phase == “began” ) then
if (event.other.myName == “collectablebeer” and event.other.isVisible==true) then
collectablebeer.isSensor = true
end
end
end
squaddie:addEventListener(“collision”, squaddieCollision)
------------------------------------------if collectable passes off screen, reset to right
local function resetcollectable (self)
self.collected = 0
self.x = (arthur.x - 220)
self.xScale = 1
self.yScale = 1
self.alpha =1
self.isSensor = false
self.speed = math.random (1,3)
self.y = math.random(32, 96)
self.initY = self.y
self.amp = math.random(5,32)
self.angle = math.random (1, 360)
self.x = self.x - self.speed
self.angle = self.angle + 0.1
self.y = self.amp * math.sin(self.angle) + self.initY
end
--------------------------------------------ending the game if the squaddie catches player
local function failed (event)
composer.gotoScene( “gameover”, “slideDown”, 200 )
end
-------------------------------------------effects of collisions with player
function onCollision( event )
if ( event.phase == “began” ) then
if (event.other.myName == “squaddie” and event.other.isVisible==true) then
squaddie:applyLinearImpulse( 6, 0, squaddie.x, squaddie.y )
squaddie:setSequence(“punch”)
squaddie:play()
Runtime:removeEventListener( “enterFrame”, onEveryFrame )
timer.performWithDelay( 290, arthurHit )
timer.performWithDelay( 1000, failed)
return true
elseif (event.other.myName == “pubdoor” and event.other.isVisible==true) then
audio.play ( beep )
arthur.alpha = 0
Runtime:removeEventListener( “enterFrame”, onEveryFrame )
composer.gotoScene( “success”, “zoomInOutFade”, 200 )
composer.removeScene(“level1”)
return true
elseif (event.other.myName == map.ground) then
canJump = 1
return true
end
end
end
arthur:addEventListener(“collision”, onCollision)
--------------------------check distance between squaddie and player, adjust camera
local function distanceCheck ( )
local distancex = arthur.x - squaddie.x
local backx = arthurrear.x - squaddie.x
if backx >40 then
sounded = 0
end
newfocus.x = arthur.x
newfocus.y = 106
if distancex > 200 then
transition.scaleTo( map, { xScale=2.3, yScale=2.3, time=1500 } )
map.setCameraFocus(newfocus)
map.updateView()
else if distancex <= 200 then
transition.scaleTo( map, { xScale=3.1, yScale=3.1, time=1500 } )
map.setCameraFocus(newfocus)
map.updateView()
end
end
end
--------------------------------------------------------------------gameloop?
function onEveryFrame( e )
if gameisplaying == 1 then
squaddierun ()
vx, vy = arthur:getLinearVelocity()
sx, sy = squaddie:getLinearVelocity( )
motioncheck (vx)
distanceCheck ()
end
distanceCheck ()
arthurrear.x = arthur.x -140
beerscoretext.text = myData.beerscore
end
Runtime:addEventListener( “enterFrame”, onEveryFrame )
end
function scene:show( event )
local sceneGroup = self.view
local phase = event.phase
if phase == “will” then
elseif phase == “did” then
physics.start()
end
end
function scene:hide( event )
local sceneGroup = self.view
local phase = event.phase
if event.phase == “will” then
elseif phase == “did” then
physics.stop() – not sure of I should leave this running?
end
end
function scene:destroy( event )
local sceneGroup = self.view
end
scene:addEventListener( “create”, scene )
scene:addEventListener( “show”, scene )
scene:addEventListener( “hide”, scene )
scene:addEventListener( “destroy”, scene )
return scene
------------------------- GAME OVER LUA FILE FROM HERE ------------------------------
local composer = require( “composer” )
local scene = composer.newScene()
local myData = require( “mydata” )
local screenW, screenH, halfW = display.contentWidth, display.contentHeight, display.contentWidth*0.5
function scene:create( event )
local sceneGroup = self.view
endgui = display.newGroup()
local background = display.newImageRect( “background.png”, display.contentWidth, display.contentHeight )
background.anchorX = 0
background.anchorY = 0
background.x, background.y = 0, 10
local sheet15 = graphics.newImageSheet( “rerun.png”, { width=200, height=40, numFrames=2 } )
local rerunButton =
{
{ name=“blink2”, start=1, count=2, time=1500 }
}
local rerun = display.newSprite( sheet15, rerunButton)
rerun.x = display.contentWidth * 0.68
rerun.y = display.contentHeight - 60
rerun:setSequence(“blink2”)
rerun:play()
local function onRerunBtnRelease()
rerun:removeEventListener( “touch”, onRerunBtnRelease )
composer.gotoScene( “game”, “fade”, 500 )
return true
end
rerun:addEventListener( “touch”, onRerunBtnRelease )
------------------------------------------------------------------display number of collected items
local myCircle = display.newCircle( ((screenW/10) * 3.25)+5, 25, 11 )
myCircle:setFillColor( 0 )
endgui:insert(myCircle)
local beerscoretext = display.newText( “” … myData.beerscore, ((screenW/10) * 3.25)+5, 25, native.systemFont, 14 )
beerscoretext:setFillColor( 1, 1, 1 )
beerscoretext.align = “center”
endgui:insert(beerscoretext)
print (beerscoretext)
sceneGroup:insert( background )
sceneGroup:insert( rerun )
sceneGroup:insert( endgui )
end
function scene:show( event )
local sceneGroup = self.view
local phase = event.phase
if phase == “will” then
elseif phase == “did” then
end
end
function scene:hide( event )
local sceneGroup = self.view
local phase = event.phase
if event.phase == “will” then
elseif phase == “did” then
end
end
function scene:destroy( event )
local sceneGroup = self.view
end
scene:addEventListener( “create”, scene )
scene:addEventListener( “show”, scene )
scene:addEventListener( “hide”, scene )
scene:addEventListener( “destroy”, scene )
return scene
[/lua]