Collision Event in Corona - lua

I am wondering how to make my collision work correctly in Corona. Here is what I have so far:
local function onLocalCollision( event )
if ( event.phase == "began" ) then
print( "began: " .. event.object1.myName .. " and " .. event.object2.myName )
test = display.newRect(screenW - 50, halfH, 100, screenH)
elseif ( event.phase == "ended" ) then
print( "ended: " .. event.object1.myName .. " and " .. event.object2.myName )
end
lilPig.collision = onLocalCollision
lilPig:addEventListener( "collision", lilPig )
endOfScreen.collision = onLocalCollision
endOfScreen:addEventListener( "collision", endOfScreen )
If you could help me that would be great! Thanks in advance!

I think, firstly you should add some property with your COLLISION objects, like:
lilPig.myName = "lilPig"
endOfScreen.myName = "endOfScreen"
so, we can directly check them in Collision listener and also if we have more Collision's after that, we can easily check by another condition.
we can also implement it by RunTime listener.
--------
RuntimeListener("collision", onCollision )
--------
function onCollision( event)
if (event.phase == "began") then
print("COLLISION: ".. event.object1.myName .. " & ".. event.object2.myName)
if (event.object1.myName == "lilPig" and event.object2.myName == "endOfScreen") or
(event.object1.myName == "endOfScreen" and event.object2.myName == "lilPig") then
print("Your code of block for collision event")
end

Related

I have created a laser that takes 2 hit to kill the type 2 asteroid and 1 hit to kill the type 1. What am i doing wrong?

So I have been making adjustments to an sdk game called "Star Explorer" in lua. I came across this idea about having 2 types of asteroids, 1 which will take 2 hits by the laser to actually die. I did not have any errors while creating the asteroid that takes up 2 hits to die. Although it still does not take 2 shots top die.
Code:
local function onCollision( event )
if ( event.phase == "began" ) then
local obj1 = event.object1
local obj2 = event.object2
if ( ( obj1.myName == "laser" and obj2.myName == "asteroid" ) or
( obj1.myName == "asteroid" and obj2.myName == "laser" ) or
( obj1.myName == "lasers" and obj2.myName == "asteroid" ) )
then
-- Remove both the laser and asteroid
display.remove( obj2 )
-- Play explosion sound!
audio.play( explosionSound )
for i = #asteroidsTable, 1, -1 do
if ( asteroidsTable[i] == obj1 or asteroidsTable[i] == obj2 ) then
table.remove( asteroidsTable, i )
break
end
end
-- Increase score
score = score + 100
scoreText.text = "Score: " .. score
elseif ( ( obj1.myName == "ship" and obj2.myName == "asteroid" ) or
( obj1.myName == "asteroid" and obj2.myName == "ship" ) )
then
if ( died == false ) then
died = true
-- Play explosion sound!
audio.play( explosionSound )
-- Update lives
lives = lives - 1
livesText.text = "Lives: " .. lives
if ( lives == 0 ) then
display.remove( ship )
display.remove(emitter)
timer.performWithDelay( 2000, endGame )
else
ship.alpha = 0
emitter.alpha = 0
timer.performWithDelay( 2000, restoreShip )
end
end
end
end
end
local function onCollision( event )
if ( event.phase == "began" ) then
local obj1 = event.object1
local obj2 = event.object2
if ( ( obj1.myName == "laser" and obj2.myName == "asteroid" ) or
( obj1.myName == "asteroid" and obj2.myName == "laser" ) or
( obj1.myName == "lasers" and obj2.myName == "asteroid" ) )
then
-- Remove both the laser and asteroid
display.remove( obj2 )
-- Play explosion sound!
audio.play( explosionSound )
for i = #asteroidsTable, 1, -1 do
if ( asteroidsTable[i] == obj1 or asteroidsTable[i] == obj2 ) then
table.remove( asteroidsTable, i )
break
end
end
-- Increase score
score = score + 200
scoreText.text = "Score: " .. score
elseif ( ( obj1.myName == "ship2" and obj2.myName == "asteroid" ) or
( obj1.myName == "asteroid" and obj2.myName == "ship2" ) )
then
if ( died == false ) then
died = true
-- Play explosion sound!
audio.play( explosionSound )
-- Update lives
lives = lives - 4
livesText.text = "Lives: " .. lives
if ( lives == 0 ) then
display.remove( ship2 )
display.remove(emitter)
timer.performWithDelay( 2000, endGame )
else
ship2.alpha = 0
emitter.alpha = 0
timer.performWithDelay( 2000, restoreShip )
end
end
end
end
end

Corona Touch Listener

I am learning corona sdk
This is the following code
when the two objects overlaps it becomes 1 objects(Moves together), i have no clue whats going on...
-----------------------------------------------------------------------------------------
--
-- main.lua
--
-----------------------------------------------------------------------------------------
-- Your code here
local physics = require( "physics" )
physics.start()
local crate1 = display.newImage( "crate.png", display.contentCenterX, 100 )
crate1.name = "crate1"
local crate2 = display.newImage( "crate.png", display.contentCenterX + 100, 100 )
crate2.name = "crate2"
crate1:scale(0.2, 0.2)
crate2:scale(0.2, 0.2)
local bodyTouched = function(event)
if(crate1.name == event.target.name and event.phase == "moved")
then
print("Moved " , event.target.name )
crate1.x = event.x
crate1.y = event.y
elseif (crate2.name == event.target.name and event.phase == "moved")
then
print( "Moved ", event.target.name )
crate2.x = event.x
crate2.y = event.y
end
end
physics.addBody( crate1, "static")
physics.addBody( crate2, "static")
crate1:addEventListener( "touch", bodyTouched )
crate2:addEventListener( "touch", bodyTouched )
Please refer to the Corona SDK documentation.
https://docs.coronalabs.com/daily/guide/events/detectEvents/index.html#TOC
Section: Understanding Hit Events
In general you should read the documentation on anything you use.
Your touch event will propagate through all display objects that intersect with the event coordinate. The event will trigger all registered event listeners on its way.
To avoid having multiple listeners triggered your event listener bodyTouch has to return true which will tell Corona that you handled the event and no further listeners should be invoked.

corona + collision not working

I am learning Corona and I am trying to use the collision event.
The target of the following program is that the rock is moving towards to the car using transition.to. And print a line to report the collision where it occurs.
However, it does not work. Moreover, I even cannot receive the message "enterenter", what is the reason why the program cannot even get into the enter function?
My code is as follow. Thank you in advance.
local composer = require( "composer" )
local scene = composer.newScene()
local physics = require "physics"
physics.start(); physics.pause()
local function onLocalCollision( self, event )
if ( event.phase == "began" ) then
print( self.myName .. ": collision began with " .. event.other.myName )
elseif ( event.phase == "ended" ) then
print( self.myName .. ": collision ended with " .. event.other.myName )
end
end
local widget = require "widget"
function scene:create( event )
print("entercreate")
local sceneGroup = self.view
local backgrd = display.newImage("background2.png",0,260)
backgrd:scale(3,3)
local car = display.newImage("car2.png",80,270)
physics.addBody(car,"static")
car.myName="Car"
local rock = display.newImage("rock.jpg",520,280)
rock:scale(0.05,0.05)
physics.addBody(rock,"static")
rock.myName="rock"
sceneGroup:insert(backgrd)
sceneGroup:insert(car)
sceneGroup:insert(rock)
transition.to(backgrd,{time=24000, x=-1800,onComplete=endScroll})
transition.to(rock,{time=4000, delay=2500,x=-40})
end
function scene:enter( event )
print("enterenter")
physics.start()
local sceneGroup = self.view
Runtime:addEventListener( "collision", onLocalCollision )
end
scene:addEventListener( "create", scene )
scene:addEventListener( "enter", scene )
return scene
Working code with a local and a global (Runtime) listener:
local widget = require "widget"
local composer = require( "composer" )
local scene = composer.newScene()
local physics = require "physics"
physics.start()
physics.setGravity( 0,0 )
local function onGlobalCollision( event )
local target = event.object1
local other = event.object2
if ( event.phase == "began" ) then
print( "GLOBAL: " .. target.name .. ": collision began with " .. other.name )
elseif ( event.phase == "ended" ) then
print( "GLOBAL: " .. target.name .. ": collision ended with " .. other.name )
end
end
local function onLocalCollision( event )
local target = event.target
local other = event.other
if ( event.phase == "began" ) then
print( "LOCAL: " .. other.name .. ": collision began with " .. target.name )
elseif ( event.phase == "ended" ) then
print( "LOCAL: " .. other.name .. ": collision ended with " .. target.name )
end
end
function scene:create( event )
print("scene:create")
local sceneGroup = self.view
local car = display.newRect( 100, 100, 100, 100 )
car.name = "car"
physics.addBody( car )
local rock = display.newRect( 250, 250, 100, 100 )
rock.name = "rock"
rock:setFillColor( 0.5, 0.5, 0.5 )
physics.addBody( rock )
rock:addEventListener( "collision", onLocalCollision )
sceneGroup:insert(car)
sceneGroup:insert(rock)
transition.to(rock,{time=4000, x = -40, y = -100})
Runtime:addEventListener( "collision", onGlobalCollision )
end
function scene:enter( event )
print("scene:enter")
local sceneGroup = self.view
end
scene:addEventListener( "create", scene )
scene:addEventListener( "enter", scene )
return scene
The problem that you have with your code is that the two bodies are static and two static bodies can't collide with each other and that there is nothing called scene:enter in composer (so that's why it doesn't gets called and therefor not the onLocalListener).
Some body types will — or will not — collide with other body types. In
a collision between two physical objects, at least one of the objects
must be dynamic, since this is the only body type which collides with
any other type. See the Physics Bodies guide for details on body
types.
https://docs.coronalabs.com/daily/guide/physics/collisionDetection/index.html
Here is some information about the Composer API and you'll that you should probably use scene:show:
https://coronalabs.com/blog/2014/01/21/introducing-the-composer-api-plus-tutorial/

collision detection doesn't work inside scene:show

I'm trying to detect collision on two object inside my scene:show function
This is my first set of objects which have a collision listener on it
for i = 1, table.maxn(layout.playgrid) do
physics.addBody( leftholes[i], "static" )
sceneGroup:insert(3,leftholes[i])
leftholes[i].name = "hole"
leftholes[i]:addEventListener( "collision", lis )
physics.addBody( rightholes[i], "static")
sceneGroup:insert(3,rightholes[i])
rightholes[i].name = "hole"
rightholes[i]:addEventListener( "collision", lis )
physics.addBody( topholes[i], "static" )
sceneGroup:insert(3,topholes[i])
topholes[i].name = "hole"
topholes[i]:addEventListener( "collision", lis )
physics.addBody(bottomholes[i], "static")
sceneGroup:insert(3,bottomholes[i])
bottomholes[i]:addEventListener( "collision", lis )
bottomholes[i].name = "hole"
end
and this is the object which will collision with the hole object
hand = display.newImage("assets/hand.png",350,490)
hand.name = "hand"
physics.addBody( hand, "static")
and that my collision listener
local function lis(event)
if event.phase == "began" and event.object2.name=="hand" then
print( "detected" )
local function tra( )
trans = display.newImage('assets/gray.png',indicesToOuterCordinate(layout.finalx,layout.finaly,layout.finalside,false))
physics.addBody( trans, "static")
sceneGroup:insert(trans)
hand:toFront()
end
end
end
Just check whether your are adding your collision listener with the RuntimeEvent listener .
If you does not add your collision with runtime event listeners your will not be detected .
local function onCollision( event )
if ( event.phase == "began" ) then
print( "began: " .. event.object1.myName .. " and " .. event.object2.myName )
elseif ( event.phase == "ended" ) then
print( "ended: " .. event.object1.myName .. " and " .. event.object2.myName )
end
end
Runtime:addEventListener( "collision", onCollision )

Game speed increases itself on every restart - Corona

am trying to make a jetpack joyride concept game on corona. First of all unlike other sdk where when you change a scene, the previous scene is automatically removed, in corona you have to remove each and object and function yourself.
After a week I was finally able to remove objects while changing scene, but now I have ran into a new problem. Everytime when I change scenes and come back to the gameScreen the speed of lasers and missiles increases every time ( maybe twice? ). How can I reset its speed?
I even added another "gameStatus" variable to remove the event listener and tried to print it, but game status never actually returned "ended", it was always "running". Here is the gameScene screen where everything happens
EDIT : I just noticed something, For example if 3 objects have already spawned then after reloading the screen only first 3 objects seem to be fast and its normal from fourth.
local composer = require( "composer" )
local scene = composer.newScene()
local physics = require( "physics" )
physics.start()
local image, text1
local function onSceneTouch( self, event )
if event.phase == "began" then
composer.gotoScene( "startScreen", "fade", 400 )
return true
end
end
function scene:create( event )
local sceneGroup = self.view
-- Variable
---------------------------------------
sW = display.contentWidth
sH = display.contentHeight
-- trying to reset gameStatus on restart
gameStatus = "ended"
gameStatus = "running"
--------------------------------------------------------
backgroundTiles = {}
drawBackground = function()
cieling = display.newRect( 0, 0, 2 * sW, sH * 0.05)
physics.addBody( cieling, "static", { density=0, friction=0, bounce=0 } )
cieling.x, cieling.y = cieling.contentWidth / 4, cieling.contentHeight * 0.25
cieling.alpha = 0
cieling.name = "ceiling"
ground = display.newRect( 0, sH, 2 * sW, sH * 0.05)
physics.addBody( ground, "static", { density=3, friction=1, bounce=0.1 } )
ground.x, ground.y = ground.contentWidth / 4, sH - ground.contentHeight * 0.25
ground.alpha = 0
ground.name = "ground"
end
drawBackground()
--------------------------------------------------------
--------------------------------------------------------
drawBird = function()
bird = display.newImageRect( "a/img/hero/hero.png", 80, 58)
bird.x, bird.y = 0 - sW * 0.1, ground.y - ground.contentHeight - 10
bird.isFixedRotation = true; bird.angularVelocity = 0;
physics.addBody( bird, { density=1, friction=0.5, bounce=0.1 } )
bird.name = "bird"
sceneGroup:insert( bird )
bird:addEventListener( "collision", onCollision )
end
coinsCollected, tokensCollected = 0, 0
birdFlight = function()
if ( gameStatus == "running" ) then
transition.to(bird, {
y = bird.y - 75,
transition = easing.outQuad,
onComplete = function() end
})
function birdFlight()
--transition.to( bird, { rotation=-45, time=300 } )
end
birdFlight()
function birdFall()
--transition.to( bird, { rotation=90, time=300 } )
end
timer.performWithDelay(700, birdFall, 1)
end
end
display.currentStage:addEventListener( "tap", birdFlight )
function onCollision(event)
if event.phase == "began" then
if event.other.name == "coin" then
coinsCollected = coinsCollected + 1
end
if event.other.name == "token" then
tokensCollected = tokensCollected + 1
end
if event.other.name == "missile" or event.other.name == "laser" or event.other.name == "rod" then
-- game ended
end
end
end
drawBird()
function atFrame(event)
if gameStatus == "running" then
bird.x,bird.y = sW / 3,bird.y + 9
if ( bird.y > sH - 70) then bird.y = sH - 70 end
if ( gameStatus == "ended" ) then bird.y = bird.y + 15 end
end
end
Runtime:addEventListener( "enterFrame", atFrame )
--------------------------------------------------------
--------------------------------------------------------
missile, missileAlert, missileMoving = {}, {}, {}
function removeMissile(i)
local onEnterFrame = function( event )
if missile[i] ~= nil and missile[i].x ~= nil and gameStatus == "running" then
if missile[i].x < -100 then
display.remove( missile[i] )
missile[i] = nil
end
end
end
Runtime:addEventListener( "enterFrame", onEnterFrame )
print(gameStatus)
if gameStatus == "ended" then
Runtime:removeEventListener( "enterFrame", onEnterFrame )
end
end
function flyMissile(i)
local onEnterFrame = function( event )
if missile[i] ~= nil and missile[i].x ~= nil and missile[i].y ~= nil and gameStatus == "running" then
if missileMoving[i] == true then
missile[i].y = bird.y
end
missile[i].x = missile[i].x - 5
if missileAlert[i] ~= nil then
if missileMoving[i] == true then
missileAlert[i].y = bird.y
end
if missile[i].x < sW then
display.remove( missileAlert[i] )
missileAlert[i] = nil
end
end
end
end
Runtime:addEventListener( "enterFrame", onEnterFrame )
print(gameStatus)
if gameStatus == "ended" then
Runtime:removeEventListener( "enterFrame", onEnterFrame )
end
end
function holdMissile(i)
local onEnterFrame = function( event )
if missile[i] ~= nil and missile[i].x ~= nil and gameStatus == "running" then
if missile[i].x < sW * 1.5 then
if missileAlert[i] ~= nil then
missileAlert[i]:setFillColor(1,1,0)
end
missileMoving[i] = false
end
end
end
Runtime:addEventListener( "enterFrame", onEnterFrame )
print(gameStatus)
if gameStatus == "ended" then
Runtime:removeEventListener( "enterFrame", onEnterFrame )
end
end
function spawnMissile(i)
missile[i] = display.newRect( sW*2, sH/2, 80, 80 )
missileAlert[i] = display.newRect( sW-80, bird.y, 80, 80 )
physics.addBody(missile[i],"kinematic",{isSensor=true})
missile[i].name = "missile"
sceneGroup:insert( missile[i] )
sceneGroup:insert( missileAlert[i] )
missileMoving[i] = true
flyMissile(i)
removeMissile(i)
holdMissile(i)
end
spawnMissile(1)
--------------------------------------------------------
--------------------------------------------------------
laser = {}
function moveAndRemovelaser(i)
local onEnterFrame = function( event )
if laser[i] ~= nil and laser[i].x ~= nil and gameStatus == "running" then
laser[i].x = laser[i].x - 5
if laser[i].x < 0 - sW / 2 then
display.remove( laser[i] )
laser[i] = nil
end
end
end
Runtime:addEventListener( "enterFrame", onEnterFrame )
print(gameStatus)
if gameStatus == "ended" then
Runtime:removeEventListener( "enterFrame", onEnterFrame )
end
end
function spawnlaser(i)
laserSize = math.random(1,2)
laserPosition = math.random(1,3)
laserRotation = math.random(1,4)
if laserSize == 1 then
laser[i] = display.newRect( 100,100,50,sH/3 )
else
laser[i] = display.newRect( 100,100,50,sH/2 )
end
sceneGroup:insert( laser[i] )
laser[i].x = sW * 2
laser[i].y = sH / 2
laser[i].name = "laser"
if laserPosition == 1 and laserRotation ~= 4 then
laser[i].y = sH * 0.05 + 12
laser[i].anchorY = 0
elseif laserPosition == 3 and laserRotation ~= 4 then
laser[i].y = sH * 0.95 - 12
laser[i].anchorY = 1
end
if laserPosition == 1 and laserRotation == 4 then
laser[i].y = sH * 0.05 + laser[i].contentHeight / 2
elseif laserPosition == 3 and laserRotation == 4 then
laser[i].y = sH * 0.95 - laser[i].contentHeight / 2
end
if laserRotation == 1 then
laser[i].rotation = -45
elseif laserRotation == 2 then
laser[i].rotation = 0
elseif laserRotation == 3 then
laser[i].rotation = 45
elseif laserRotation == 4 then
local onEnterFrame = function( event )
if laser[i] ~= nil and laser[i].rotation ~= nil then
laser[i].rotation = laser[i].rotation + 5
end
end
Runtime:addEventListener( "enterFrame", onEnterFrame )
end
laser[i]:setFillColor(1,1,0)
physics.addBody(laser[i],"kinematic",{isSensor=true})
moveAndRemovelaser(i)
end
spawnlaser(1)
--------------------------------------------------------
image = display.newRect (100,100,100,100)
image.x = display.contentCenterX
image.y = display.contentCenterY
sceneGroup:insert( image )
image.touch = onSceneTouch
text1 = display.newText( "Game Screen", 0, 0, native.systemFontBold, 24 )
text1:setFillColor( 255 )
text1.x, text1.y = display.contentWidth * 0.5, 50
sceneGroup:insert( text1 )
end
function scene:show( event )
local phase = event.phase
if "will" == phase then
gameStatus = "ended"
end
if "did" == phase then
print( "4" )
composer.removeScene( "startScreen" )
image:addEventListener( "touch", image )
gameStatus = "running"
end
end
function scene:hide( event )
local phase = event.phase
if "will" == phase then
print( "5" )
gameStatus = "ended"
image:removeEventListener( "touch", image )
Runtime:removeEventListener( "enterFrame", onEnterFrame )
end
end
function scene:destroy( event )
print( "6" )
end
scene:addEventListener( "create", scene )
scene:addEventListener( "show", scene )
scene:addEventListener( "hide", scene )
scene:addEventListener( "destroy", scene )
return scene
You are getting this problem because you are registering an event listener twice.
You need to add and remove them only when the scene enters and exits. The proper place to remove game objects is scene:destroy() and scene:hide()
My advice is that you try to re-organize your code and try to follow these guidelines:
scene:create() : This happens the first time a scene is used. You want create your game objects here. This event will only happen once, unless the scene is destroyed and then used again.
scene:show() : You want to register all your event listeners here (touch, etc) and setup your game. This function gets called every-time the scene is shown. Every event listener that is registered here should be un-registered to prevent double-triggering.
scene:hide() : You want to un-register all event listeners here. This will prevent the next scene from triggering events on your previous scene's listeners too.
scene:destroy() : You want to remove all game objects here (images, text, widgets, etc). The scene is no longer needed and everything should be cleaned.
To better understand how the Scene's work I recommend reading this doc:
http://coronalabs.com/blog/2014/01/21/introducing-the-composer-api-plus-tutorial/
So I ended up creating a function and putting all the removeEventListeners in that function and called that function when the game ended.
For future reference always keep a list of all the timer and event listeners that you have created anywhere in the screen and remove them all together when ending the game

Resources