How to trigger this event listener

Hey guys,

  I am trying to get my collision event to be triggered by the local variable crate,but I cannot find a way.So please help me.Thank you.

Also if I create another local function and place my crate variable in there,the transition doesn’t work,I tried and it gives me an error when I try to triger the collision event using that function.

My Main.lua file :

require ("Crate") local physics = require ("physics") physics.start() physics.setGravity (0,0) local function onSpawn (event) for i = 0,0 do local crate = Crate:new() physics.addBody (crate,"static") crate.x = math.random (50,300) crate.y = 450 local removeCrate = function () display.remove (crate) crate = nil end cIntro = transition.to (crate,{time = 20000,x = 0,onComplete = removeCrate}) end end timer.performWithDelay (9000,onSpawn,0) local function onCollision (event) if event.phase == "began" then print ("It works!") end end Runtime:addEventListener ("collision",onCollision)

And here is the Crate.lua file :

Crate = {} function Crate:new() local self = display.newGroup() self:insert(display.newImage("Icon.png")) return self end

The tutorial I followed: http://lazywombat.co.uk/object-oriented-programming-in-corona-sdk-part-1-basics/

I think you have a scoping problem. It’s a bit hard to tell because of the formatting. Your variable ‘crate’ needs to be a member of the object.  ‘crate’ is only in scope on onSpawn(). The crate stuff needs to be member variables - something like this code will create and dispose of it. 

This allows you to write further methods which act on the crate object, so for example you can write something like the Crate:transition() method below.

function Crate:new() self.m\_group = display.newGroup() self.m\_image = display.newImage("Icon.png") self.m\_group:insert(self.m\_image) end function Crate:dispose() self.m\_group:removeSelf() self.m\_group = nil self.m\_image = nil end

function Crate:transition() transition.to(self.m\_group, { x = 132,y = 412, time = 3000, onComplete = function() self:dispose() }) end

This function works because closures another very important lua context , basically because onComplete is a local function it keeps the scope at the point it was created so ‘self’ maintains the value and disposes the correct crate object.

This allows you to write things like:

local c1 = Crate:new() c1:transition()

Which will create a crate, transition it and then it disposes of itself (via the onComplete) - if you want 38 of them, just do it in a for loop. Whether you keep track of references or not depends on what you are doing.

The important thing is to encapsulate stuff relating to the crate in the crate method, so you have a ‘crate’ object which knows everything about ‘crates’ and has as little knowledge of non-crate things as possible. If you look at a lot of Corona code it is chaos with responsibility for things thrown all over the place, then when things get confusing it breaks because it’s impossible to figure out who is responsible for what.

Now, with regard to listeners and objects. It doesn’t work very well if you do it with functions, but Corona has the ability to apply listeners to objects, by passing the object reference rather than a function. 

So if you put :

c1.m\_group:addEventListener("tap",c1)

when the listener fires it by tapping on c1 doesn’t call a function , because c1 isn’t one - it’s an object, so it calls the object method c1:tap instead.  This is pretty much mandatory for objects, trying to do it with functions is just asking for troubles. I have no idea whether this works for physics listeners because I do not use them.

Hi mate,

 Thanks for the answer.I tried your code and it gives me an error. I put your code in the Crate.lua file and did a for loop so I can have my crate spawned,and here it is.

local function onSpawn (event) for i = 0,0 do local c1 = Crate:new() c1.x = math.random (50,350) c1.y = 400 end end timer.performWithDelay (9000,onSpawn,0)

Untitled-8.jpg

Bogdan,

You need to return Crate like this:

[lua]
– Crate.lua

local Crate = {}

function Crate:new()
    local self = display.newGroup()
    self:insert(display.newImage(“crate.png”))
    return self
end

return Crate

[/lua]

And “static” bodies don’t collide with other static bodies, so you can try “dynamic”:

[lua]
local Crate = require “Crate”

local physics = require “physics”
physics.start()
physics.setGravity(0,0)

local w = display.actualContentWidth
local halfH = display.contentCenterY

local function onSpawn(event)
    local crate = Crate:new()
    physics.addBody(crate, “dynamic”)
    crate.x = math.random(60, w-60) – crate.png is 60x60 pixels
    crate.y = halfH

    local removeCrate = function()
        display.remove(crate)
        crate = nil
    end

    transition.to(crate, { time=5000, x=0, onComplete=removeCrate })
end

timer.performWithDelay(2500, onSpawn, 0)

local function onCollision(event)
    if event.phase==“began” then
        print(“It works!”)
    end
end

Runtime:addEventListener(“collision”, onCollision)

[/lua]

You may want to deal with the crates after they collide (and crate.png can be found at the CoronaSDK/SampleCode/Physics/HelloPhysics folder).

Cheers,

Dave

I use this though there are lots of variations on a theme.

\_G.Base = \_G.Base or { new = function(s,...) local o = { } setmetatable(o,s) s.\_\_index = s o:initialise(...) return o end, initialise = function() end }

Defines a ‘class’ Base which can be extended.

Dave,
Thank you for the answer,but I want the collision event to be triggered by the crate. How can I do that?
Regards,
Bogdan

Did you try the code I posted? The crates are colliding and are triggering the event.

Dave,

  Yes I tried your code,and it works.Thank you :wink:

I haven’t expressed myself correct and didn’t explained you all the problem,I apologize for that.

I want my crate to colide with a laser beam.

The laser beam should colide with the crate and another circle,three diiferent objects.

The laser beam is a dynamic object and the crate and the circle are static objects.

So when the laser beam colides with the crate something should happen (an explosion animation will be triggered)

And when the laser beam colides with the circle,something else should happen (a sound wave will be triggered).

Please note that I use storyboard.

Regards,

Bogdan

local beam = display.newImageRect("Beam.png" ,90,200) physics.addBody (beam,"dynamic")

Hey guys,

 I fixed the collision problem! It was something relative simple.But now I moved from the prototype to the real game,and I am having some problems on loading the sprite sheet.Thank you.

cow = {} function cow:new() local self = display.newGroup() self:insert ( local sheetData = {width = 100,height = 100,numFrames = 14,sheetContentWidth = 200,sheetContentHeight = 700} local mySheet = graphics.newImageSheet ("cow.png",sheetData) local sequenceData = {{name = "cowOne2",start = 1,count = 8,time = 1000,loopcount = 0}, {name = "cowBeaming",frames = {9,10,11,12,13,14},time = 1000,loopcount = 0}} local cowOne = display.newSprite (mySheet,sequenceData) ) return self end 

Untitled-9.jpg

You can’t insert statements into a group. Try something like this:

[lua]
– cow.lua

local cow = {}

function cow:new()
    local self = display.newGroup()

    local sheetData = { width=100, height=100, numFrames=14, sheetContentWidth=200, sheetContentHeight=700 }
    local mySheet = graphics.newImageSheet(“cow.png”, sheetData)
    local sequenceData = {{ name=“cowOne2”, start=1, count=8, time=1000, loopcount=0 },

      { name=“cowBeaming”, frames={9,10,11,12,13,14}, time=1000, loopcount=0 }}
 

    self:insert(display.newSprite(mySheet, sequenceData))

    return self
end

[/lua]

Hi Dave,

Thanks it worked,but now I have another two issues.

  1. I have an error that say “attempted to call method “setSequence” a nil value”

  2. How can I start the function (with the timer) in order that my for loop would work,I tried with a touch event and it worked,but with the timer.performWithDelay,I can’t get it to work,why?

Thank you very much!

-- cow.lua file local cow = {} function cow:new() for i = 1,2 do local self = display.newGroup() local sheetData = { width=100, height=100, numFrames=14, sheetContentWidth=200, sheetContentHeight=700 } local mySheet = graphics.newImageSheet("cow.png", sheetData) local sequenceData = {{ name="cowOne2", start=1, count=8, time = 1000, loopcount = 0 }, { name="cowBeaming", frames={9,10,11,12,13,14}, time=1000, loopcount = 0 }} self:insert(display.newSprite(mySheet, sequenceData)) self.x = 38 self.y = math.random (0,500) self.rotation = 90 self:setSequence ("cowOne2") self:play() physics.addBody (self,"static") self.gravityScale = 0 self.isSensor = true self:setLinearVelocity (0,0) local removeCow = function () display.remove (self) self = nil end transition.to (self,{time = 10000,y = 10,onComplete = removeCow }) return self end end timer.performWithDelay (2000,cow:new(),0)

setSequence() is a method of the SpriteObject, and ‘self’ in your code is a display group; that’s why it’s nil.

Please refer to: http://docs.coronalabs.com/api/type/SpriteObject/setSequence.html

I haven’t tested the following, but try changing the code like this:

[lua]local cowOne = display.newSprite (mySheet,sequenceData)
self:insert(cowOne)

self.x = 38
self.y = math.random (0,500)
self.rotation = 90
cowOne:setSequence (“cowOne2”)
cowOne:play()[/lua]

And for the 2nd issue, would the following work?

[lua]local function newCow()
    return cow:new()
end

timer.performWithDelay (2000, newCow, 0)[/lua]

Hi Dave,

  Thank you very much it worked! But for some wierd reasons I don’t know why the collision event doesn’t work with all the spawned objects.It works only with one cow,but the rest of the spawned cows it doesn’t. Any ideas?

UPDATE:

I manage to fix the collision,butI have a doubt on how to get my collision event to be triggered by the cow.

In my game there will be a cow and a cowboy,and when the laser beam hits the cow an animation should start and when the laser beam hits the cowboy a different animation should start.

Thanks

local function cows (event) local c = Cow:new() c.x = 100 c.y = math.random (0,500) physics.addBody (c,"static") end local function spawning (event) for i = 0,0 do cows() end end local function onCol (event) if event.phase == "began" then print ("works") end end timer.performWithDelay (10000,spawning,0) Runtime:addEventListener ("collision",onCol)

From the code you provided, I can’t tell how your cowboy and laser are set up. Because you are only creating static bodies here, collision won’t happen between them as mentioned previously.

You may want to familiar yourself with this: http://docs.coronalabs.com/guide/physics/collisionDetection/index.html

Dave

Hey Dave,

  I fixed the collision problem.The laser beam is a dynamic object and the cows are static objects.The cow is a sprite object declared in another file.

But how do I get the cow to trigger the collision event? 

I can do this in two ways:

  1. Declaring the cow as a global variable,if I choose this option how can I make my for loop to work?

  2. declaring in in a local function,as a local variable,but if I choose the second option it will give me a nil value when I call the seSequence method.

Thank you!

local beam = display.newImageRect("Beam.png" ,90,200) beam.rotation = 90 beam.isVisible = false physics.addBody (beam,"dynamic") beam.gravityScale = 0 beam.isSensor = true beam:setLinearVelocity (0,0) -- This is the first method that I used. local function cows (event) local c = Cow:new() c.x = 100 c.y = math.random (0,500) physics.addBody (c,"static") end local function spawning (event) for i = 0,0 do cows() end end local function onCol (event) if event.phase == "began" then print ("works") end end timer.performWithDelay (10000,spawning,0) Runtime:addEventListener ("collision",onCol)

Return the cow:

[lua]

local function cows (event)
    local c = Cow:new()
    c.x = 100
    c.y = math.random (0,display.contentHeight)
    physics.addBody (c,“static”)
    return c
end

[/lua]

And add this to test:

[lua]

local beam = display.newImageRect(“Beam.png” ,90,200)
beam.rotation = 90
beam.isVisible = false
physics.addBody(beam,“dynamic”)
beam.gravityScale = 0
beam.isSensor = true
beam:setLinearVelocity(0,0)
beam.x, beam.y = display.contentWidth,500

local function fireLaser(event)
    beam.isVisible = true
    beam:setLinearVelocity(-2000,0)
end

Runtime:addEventListener(“touch”, fireLaser)

[/lua]

Touch the screen when there’s a cow at the same height (500) as the laser to see if it works.

BTW, I’m not sure why you have a loop like this: [lua]for i = 0,0 do[/lua]

Dave

Hi Dave,

  I have a different function that activates the beam and the only way this can work is via the collision event.I also tried non physics collision with no luck.

If I create a global variable for example :

var = cows()

and then to run the collision event:

var.collision = onCollision Runtime:addeventListener ("collision",onCollision)

Hope this will help me.I’ll come back with an update.

Thank you,

Bogdan

UPDATE

I manage to fix the collision problem.Thank you for the help.

But still having this issue.

And you can find the setSequence method in cowboys function and onCollisionWithCowboy function.

Thank you!

local function cowboys (event) local e = Cowboy:new() e.x = 48 e.y = math.random (600,800) e.rotation = 90 physics.addBody (e,"static")  e:setSequence ("cowboyWalking") e:play() local removeE = function () display.remove (e) end  transition.to (e,{time = 20000,y = -50,onComplete = removeE}) return e end  local function cowboySpawning (event) for i = 0,0 do  cowboys() end  end  varE = cowboys() local function onCollisionWithCowboy (self,event) if event.phase == "began" then  varE:setSequence ("shooting") varE:play() end  end 

local ve = cowboys() ve.collision = onCollisionWithCowboy Runtime:addEventListener ("collision",ve)

Untitled-10.jpg

As I mentioned before: setSequence() is a method of the SpriteObject.

And it looks like e is not a SpriteObject from this statement:

local e = Cowboy:new()