why eveyone do if event.phase == "began" then...? - lua

i see allways that people write in the collusion function (example):
local onCollision = function(event)
if event.phase == "began" then
event.object2:removeSelf();
event.object2 = nil;
end
end
Runtime:addEventListener("collision",onCollision);
why you dont just write:
local onCollision = function(event)
event.object2:removeSelf();
event.object2 = nil;
end
Runtime:addEventListener("collision",onCollision);
I dont understand what is the point?

consider this example,
local object = display.newImage( "ball.png" )
function object:touch( event )
if event.phase == "began" then
display.getCurrentStage():setFocus( self )
self.isFocus = true
elseif event.phase == "moved" then
print( "moved phase" )
elseif event.phase == "ended" or event.phase == "cancelled" then
display.getCurrentStage():setFocus( nil )
self.isFocus = false
end
end
return true
end
object:addEventListener( "touch", object )
If you doesn't add the phase your touch will be detected in all the three phase,
thus it executes all the statements with in function three times.
To avoid this we are using the phase.
In your case ,
local onCollision = function(event)
event.object2:removeSelf();
event.object2 = nil;
end
Runtime:addEventListener("collision",onCollision);
The code inside this will be called three times, this results in error. Since in began phase itself your object will be removed, when it comes to moved phase it will give you error, since object is already removed.
Please refer this, http://docs.coronalabs.com/api/event/touch/phase.html

Related

how to collide objects in corona labs

I'm trying to make a game in Corona SDK where a player runs and survives through obstacles by either jumping over them or killing them using bullets. The problem is that the game ends even if the player fires the bullet. But it should be over only if the player collides with the obstacles.
This is my code till now!!
--local screen_adjustment = 1
local physics = require "physics"
physics.start()
local storyboard = require ("storyboard")
local scene = storyboard.newScene()
function scene:createScene( event )
local screenGroup=self.view
background=display.newImage("rsz_islands1-background-animation.png")
background:setReferencePoint(display.BottomLeftReferencePoint)
background.x=-50
background.y=330
background.speed=math.random(2,6)
screenGroup:insert(background)
background1=display.newImage("rsz_islands1-background-animation.png")
background1:setReferencePoint(display.BottomLeftReferencePoint)
background1.x=500
background1.y=330
background1.speed=math.random(2,6)
screenGroup:insert(background1)
rightArrow=display.newImageRect("right_arrow.png",50,100)
rightArrow:setReferencePoint(display.BottomLeftReferencePoint)
rightArrow.x=370
rightArrow.y=290
screenGroup:insert(rightArrow)
upArrow=display.newImageRect("up_Arrow.png",100,50)
upArrow:setReferencePoint(display.BottomLeftReferencePoint)
upArrow.x=250
upArrow.y=240
screenGroup:insert(upArrow)
stone=display.newImageRect("stone.png",100,50)
stone:setReferencePoint(display.BottomLeftReferencePoint)
stone.x=math.random(500,1500)
stone.y=280
stone.speed=math.random(2,6)
physics.addBody(stone,"static",{bounce=0,friction=0,})
screenGroup:insert(stone)
base = display.newRect(0,0,450,3)
base.x=-50
base.y=282
base:setReferencePoint(display.BottomLeftReferencePoint)
base:setFillColor(255,255,255)
--physics.addBody(base,"static",{bounce=0.1,friction=0.1})
physics.addBody(base,"static",{bounce=0,friction=1.0,density=1.0})
screenGroup:insert(base)
base.myName="base1"
local sheetData = {
width=65,
height=75,
numFrames=4,
sheetContentWidth=130,
sheetContentHeight=150
}
local mySprite = graphics.newImageSheet("imageSheet.png",sheetData)
local sequenceData = {
name="normalRun",
frames={1,2,3,4},
time=500,
loopcount=0
}
animation = display.newSprite(mySprite,sequenceData)
if(animation.x<50) then
animation.x=50
end
animation.y=245
physics.addBody(animation,{bounce=0.3,friction=1.0,density=1.0,radius=35})
animation:play()
screenGroup:insert(animation)
animation.myName="animation1"
local sheetTigerData = {
width=100,
height=57,
numFrames=8,
sheetContentWidth=400,
sheetContentHeight=120
}
local myTigerSprite
graphics.newImageSheet("tigerImageSheet.png",sheetTigerData)
local sequenceTigerData = {
name="normalRun",
frames={1,2,3,4,5,6,7,8},
time=500,
loopcount=0
}
tigeranimation = display.newSprite(myTigerSprite,sequenceTigerData)
--tigeranimation.x=700
tigeranimation.x=math.random(500,1500)
tigeranimation.y=255
tigeranimation.speed=math.random(2,6)
physics.addBody(tigeranimation,"static",{bounce=0,friction=.2})
tigeranimation:play()
screenGroup:insert(tigeranimation)
local sheetBirdData = {
width=60,
height=40,
numFrames=6,
sheetContentWidth=180,
sheetContentHeight=80
}
local myBirdSprite =
graphics.newImageSheet("birdimagesheet.png",sheetBirdData)
local sequenceBirdData = {
name="normalRun",
frames={1,2,3,4,5,6},
time=500,
loopcount=0
}
birdanimation = display.newSprite(myBirdSprite,sequenceBirdData)
birdanimation.x=math.random(500,2500)
birdanimation.y=math.random(100,200)
birdanimation.speed=2
birdanimation.initY=birdanimation.y
birdanimation.amp=50
birdanimation.angle=math.random(1,360)
physics.addBody(birdanimation,"static",{friction=.2,bounce=0})
birdanimation:play()
screenGroup:insert(birdanimation)
local sheetCatData = {
width=100,
height=48,
numFrames=8,
sheetContentWidth=200,
sheetContentHeight=200
}
local myCatSprite =
graphics.newImageSheet("rsz_runningcat.png",sheetCatData)
local sequenceCatData = {
name="normalRun",
frames={2,1,4,3,6,5,8,7},
time=500,
loopcount=0
}
catanimation = display.newSprite(myCatSprite,sequenceCatData)
catanimation.x=tigeranimation.x+math.random(110,1500)
catanimation.y=255
catanimation.speed=math.random(2,6)
physics.addBody(catanimation,"static",{bounce=0,friction=.2})
catanimation:play()
screenGroup:insert(catanimation)
gameSound=audio.loadStream("gamesound.mp3")
audio.play(gameSound)
gunshot=audio.loadStream("gunshot3.mp3")
end
function scrollBack( self,event )
if self.x<-590 then
self.x=500
audio.play(gameSound)
else
self.x=self.x-3
audio.play(gameSound)
end
end
function moveTiger( self,event )
if self.x<-100 then
self.x=math.random(1500,4000)
self.y=255
self.speed=math.random(3,6)
audio.play(gameSound)
else
self.x=self.x-self.speed
audio.play(gameSound)
end
end
function moveCat( self,event )
if self.x<-100 then
self.x=tigeranimation.x+math.random(800,2000)
self.y=255
self.speed=math.random(3,6)
else
self.x=self.x-self.speed
end
end
function moveStone( self,event )
if self.x<-100 then
self.x=math.random(1000,5000)
self.y=280
self.speed=math.random(3,6)
else
self.x=self.x-self.speed
end
end
function moveBird( self,event )
if self.x<-100 then
self.x=math.random(500,2500)
--self.x=300
self.y=math.random(100,200)
self.speed=2
self.amp=math.random(25,75)
self.angle=math.random(1,360)
--self.y=280
--self.speed=math.random(3,6)
else
self.x=self.x-self.speed
self.angle=self.angle+.1
self.y=self.amp*math.sin(self.angle)+self.initY
end
end
function fireLasers()
blaster = display.newImageRect( "bullet.png", 40, 15 )
physics.addBody(blaster,"dynamic")
blaster.x = animation.x+50
blaster.y = animation.y-10
--blaster.collided=false
if(animation.x<50) then
animation.x=50
end
transition.to( blaster, { time=1000, x=500} )
audio.play(gunshot)
end
function handleFireButton( event )
if ( event.phase == "began" ) then
-- Fire the weapon
fireLasers()
elseif ( event.phase == "ended" ) then
-- Stop firing the weapon
fireLasers()
end
return true
end
positionInAir = false
function jump(event)
if(event.phase == "began" and positionInAir==false) then
--playerInAir = true
--animation:setLinearVelocity( 0, 1 )
animation:applyForce(0,-1000,animation.x,animation.y)
positionInAir=true
--physics.addBody(animation,"dynamic")
--print("touch")
end
return true
end
function onCollision( event )
if(event.object1.myName == "base1" and event.object2.myName == "animation1")
then
positionInAir = false;
-- base:removeSelf()
end
end
local function onManCollide(event)
if ( event.phase == "began" ) then
storyboard.gotoScene("restart","fade",400)
audio.stop()
end
end
function scene:enterScene( event )
background.enterFrame=scrollBack
Runtime:addEventListener("enterFrame",background)
background1.enterFrame=scrollBack
Runtime:addEventListener("enterFrame",background1)
stone.enterFrame=moveStone
Runtime:addEventListener("enterFrame",stone)
tigeranimation.enterFrame=moveTiger
Runtime:addEventListener("enterFrame",tigeranimation)
birdanimation.enterFrame=moveBird
Runtime:addEventListener("enterFrame",birdanimation)
catanimation.enterFrame=moveCat
Runtime:addEventListener("enterFrame",catanimation)
animation.collision=onManCollide
animation:addEventListener("collision",onManCollide)
rightArrow:addEventListener( "touch", handleFireButton )
--Runtime:addEventListener( "touch", handleFireButton )
--Runtime:addEventListener( "enterFrame", handleFireButton )
--upArrow:addEventListener("touch", jump)
--Runtime:addEventListener( "collision", onCollision )
--Runtime:addEventListener( "touch", onScreenTouch )
--rightArrow:addEventListener( "touch", handleFireButton )
end
function scene:exitScene( event )
Runtime:removeEventListener("enterFrame",background)
Runtime:removeEventListener("enterFrame",background1)
Runtime:removeEventListener("enterFrame",stone)
Runtime:removeEventListener("enterFrame",tigeranimation)
Runtime:removeEventListener("enterFrame",birdanimation)
Runtime:removeEventListener("enterFrame",catanimation)
Runtime:removeEventListener("enterFrame",onManCollide)
rightArrow:removeEventListener( "touch", handleFireButton )
upArrow:removeEventListener("touch", jump)
Runtime:removeEventListener( "collision", onCollision )
end
function scene:destroyScene( event )
end
--local myGroup=display.newGroup()
--physics.addBody(background,"static",{bounce=0.1,friction=0.9})
--physics.addBody(background1,"static",{ bounce=0.1,friction=0.9})
scene:addEventListener("createScene",scene)
scene:addEventListener("enterScene",scene)
scene:addEventListener("exitScene",scene)
scene:addEventListener("destroyScene",scene)
return scene
You need to ask a specific question, what you have said is quite vague. Does the game end each time the player fires the bullet? Also you should consider migrating from storyboard to composer.

Attempt to call global 'gameover' (a table value)

So i'm working on a little game using onCollision event's :
local function onCollision(event)
if event.phase == "began" and gameIsActive == true then
local obj1 = event.object1;
local obj2 = event.object2;
if obj1.name == "bill" then
if obj2.name == "rocks" then gameover()
elseif obj2.name == "" then
end
end
end
end
Runtime:addEventListener( "collision", onCollision )
But i have a bit of a problem the code works as expected the first time it runs but is you restart the game i'm getting this error :
File: game.lua
Line: 649
Attempt to call global 'gameover' (a table value)
stack traceback: game.lua:649: in function <game.lua:643> ?: in function <?:221>
649 = if obj2.name == "rocks" then gameover()
643 = local function onCollision(event)
Any idea what this could be?
gameover function :
function gameover()
rightTAP:removeEventListener("tap", movePLAYERr)
leftTAP:removeEventListener("tap", movePLAYERl)
timer.pause(spawnBits)
timer.pause(Rockspawner1)
timer.pause(tmrscore)
timer.pause(updateScoretimer)
timer.pause(spawnDinosControll)
audio.pause( drillingChannel )
drillbg.isVisible = false
scoreText.isVisible = false
Restartg = display.newText( "Restart", 0, 0,nil, 20)
Restartg:setFillColor(0, 0, 0)
screenGroup:insert(Restartg)
Restartg.x= display.contentWidth/2
Restartg.y= display.contentHeight/2 + 160
Restartg:addEventListener("tap", RestartGame1)
end
The error message is clear: you are trying to call gameover and it has a table value instead of a function value. You get the same error is you run the following: gameover = {}; gameover().
This means that either you are not correctly defining gameover function or overwriting gameover value somewhere in your script.
if you have an object of functions you can call whit the key that you use to declare.
example
el = {}
print(el)
table: 0x7f8fe9e003f0
el.f1 = function()
print('hola')
end
el.f1()
hola
On restart you have to remove all Runtime listeners. Otherwise they will be still listening and it may cause errors, because they lead to already removed methods.
Place it in RestartGame1:
Runtime:removeEventListener( "collision", onCollision )
fixed by adding "transition.pause( thisRock )" to the gameover function

Add ID to listener after loading remote image

I have a listener for loading remote images, but I need to be able to pass an ID number to that listener, and I'm not really sure how to do it. My code to retrieve the remote image is:
display.loadRemoteImage("http://www.newyorker.com/online/blogs/photobooth/NASAEarth-01.jpg", "GET", networkListener, "banner.png",system.TemporaryDirectory, (globalData.contentX * rows2) + globalData.contentX/2, 20 + (i - 1) % 6 * 140
And the listener I have is:
local function networkListener( event )
if ( event.isError ) then
print ( "Network error - download failed" )
else
local target = event.target
target.alpha = 0
transition.to( target, { alpha = 1.0 } )
target.width = 590
target.height = 110
target:addEventListener( "touch", target )
scrollView:insert(target)
function target:touch(event)
if event.phase == "began" then
display.getCurrentStage():setFocus( self )
self.isFocus = true
elseif self.isFocus then
if event.phase == "moved" then
numMoved = numMoved + 1
if(numMoved > 10) then
display.getCurrentStage():setFocus( nil )
self.isFocus = false
scrollView:takeFocus( event )
end
elseif event.phase == "ended" or event.phase == "cancelled" then
globalData.selectedLocationID = target.id --This needs to be the ID that I pass to this listener
if(globalData.approvedToggle == 1) then
storyboard.gotoScene("businessScene")
else
storyboard.gotoScene("locationScene")
end
display.getCurrentStage():setFocus( nil )
self.isFocus = false
end
end
return true
end
end
Any help in this matter would be greatly appreciated, thanks!
I did this a while back on an Ecommerence app I was making. I'm not to familer with storyboard, but I do remember using this API. If I remember correctly, you need to use event.target as the event listener and pass everything through there. I also remember that you can embed a function inside of the display.loadRemoteImage API like this:
itemImage = display.loadRemoteImage(itemData.imageURL, "GET",
function(event)
event.target.xScale = 0.4
event.target.yScale = 0.4
function openSite(event)
if event.phase == "ended" then
system.openURL( itemData.itemURL )
end
end
event.target:addEventListener( "tap", openSite )
end)
My advice is remove all the story board stuff, and try making the API work in a different document. I think that you need to simplify it so you aren't confused.
Hopefully this helps.

Lua collision nil value

When I tried to execute the following piece of code it gives me this error:
Attempt to index field 'other' (a nil value)
but I don't know why.
The code:
function onCollision(event)
if event.phase == "began" then
if event.other.star == "star" then
score = score + 1
elseif event.other.mine1 == "mine1" then
if jet.collided == false then
timer.cancel(tmr)
jet.collided = true
jet.bodyType = "static"
explode()
end
end
end
end
Thanks in advance :)
As #lhf and #RBerteig said the problem is event.other is nil, so trying to access the star member fails attempting to index a nil value.
Assuming event.other can indeed be nil, the idiomatic way to solve your problem would be to add a nil check to the previous if if event.phase == "began" and event.other then, since both if and else conditions depend on event.other to be set.
function onCollision(event)
if event.phase == "began" and event.other then
if event.other.star == "star" then
score = score + 1
elseif event.other.mine1 == "mine1" then
if jet.collided == false then
timer.cancel(tmr)
jet.collided = true
jet.bodyType = "static"
explode()
end
end
end
end
In case you're wondering about the message of 'attempt to index field' you can also read more about lua index metamethod here

Moving a character with Lua

I am new to Lua and am attempting to simulate a character moving.
I have the character moving left and right at the moment. I would like the character to move 16 pixels at a time. That works fine given that the user doesn't touch the phone rapidly. In that case, the character moves a random number of pixels.
my question is, how can i get the touch event to only register once at a time.
my code:
-- move character
function moveCharacter(event)
if event.phase == 'began' then
if event.x > character.x+8 then
transition.to(background, {time=800, x=background.x-16})
end
if event.x < character.x-8 then
transition.to(background, {time=800, x=background.x+16})
end
end
end
function touchScreen(event)
Runtime:removeEventListener('touch', moveCharacter)
if event.phase == 'began' then
Runtime:addEventListener('touch', moveCharacter)
end
end
Runtime:addEventListener('touch', touchScreen)
You can try this:
function moveCharEF()
if event.x > character.x+8 then
background.x = background - 16
end
if event.x < character.x-8 then
background.x = background + 16
end
end
function moveCharacter(event)
if event.phase == 'began' then
display.getCurrentStage():setFocus( event.target )
event.target.isFocus = true
Runtime:addEventListener( "enterFrame", moveCharEF )
elseif event.target.isFocus then
if event.phase == "ended" then
Runtime:removeEventListener( "enterFrame", moveCharEF )
display.getCurrentStage():setFocus( nil )
event.target.isFocus = false
end
end
end
function touchScreen(event)
Runtime:removeEventListener('touch', moveCharacter)
if event.phase == 'began' then
Runtime:addEventListener('touch', moveCharacter)
end
end
Runtime:addEventListener('touch', touchScreen)
By the way, I dont know about your application. So character may move too fast or too slow. Just change moveCharEF() function's related lines
Is it is what you looking for..?
local isTransitionInProgress = false
local function resetFlag()
isTransitionInProgress = false
end
function moveCharacter(event)
if(event.x > character.x+8 and isTransitionInProgress==false) then
isTransitionInProgress = true
transition.to(background, {time=800, x=background.x-16,onComplete=resetFlag()})
end
if(event.x < character.x-8 and isTransitionInProgress==false) then
isTransitionInProgress = true
transition.to(background, {time=800, x=background.x+16,onComplete=resetFlag()})
end
end
background:addEventListener("tap", moveCharacter)
Keep coding... :)
You can try using the "tap" listener instead of "touch". It only registers one touch at a time.
Runtime:addEventListener('tap', touchScreen)

Resources