My missiles don't collide with the asteroids :(

Right now I am having my ship fire a missile at asteroids but I am having some trouble. 

local function createAsteroids() for i = 1, 100 do local asteroid = display.newImageRect(group, "sprite/rock/brownlarge1.png", 134, 115) asteroid.x, asteroid.y = math.random(1, 1000), math.random(1, 1000) asteroid.rotation = math.random(1, 360) physics.addBody(asteroid, "dynamic") asteroid:applyTorque(math.random(1, 15), math.random(1, 15)) asteroid.id = "asteroid" end end createAsteroids() local function missileCollision(self, event) if event.phase == "began" then if event.other and event.other.id == "asteroid" then createExplosion(event.other.x, event.other.y) display.remove(event.other) display.remove(self) print("collided") end end end local function shoot() local vx, vy = ship:getLinearVelocity() --print(vx, vy) if (vx \< -50 or vx \> 50) or (vy \< -50 or vy \> 50) then local missile = display.newImageRect(group, "sprite/ship/Rocket.png", 100, 65) missile.x, missile.y = ship.x, ship.y missile.rotation = ship.rotation - 90 physics.addBody(missile, "dynamic", {isSensor = true}) missile:setLinearVelocity(vx \* 3, vy \* 3) missile:toBack() missile.collision = missileCollision listen("collision", missile) end end

Any help would be great. Thanks! 

Another day, another project eh? :wink:

Looks like you’re using SSK2 so I can’t help on this one.

What is this line and what does it do? It’s certainly not a Corona API command… unless you’ve done something odd like try to override the Corona event listener (and in that case I would sincerely ask why that would/should be done).

[lua]

listen(“collision”, missile)

[/lua]

Brent

I believe it’s an SSK2 call. sdktester15, you should probably mention if you’re using 3rd party libraries, especially when it’s things in and around that call that seem to be the problem :slight_smile:

I would advise looking at where you have setup your collision filters and make sure that the missile is supposed to collide with the asteroid, and then make sure that when you create you missile you give it the correct parameters.

If need be zip up your lua file. and I’ll have a quick look at it (I already have SSK2).

He is using SSK2, but only the listen shorthand function is part of his help request.
 
https://roaminggamer.github.io/RGDocs/pages/SSK2/globals/#runtime-improvements
 

listen("collision", missile)

is shorthand for the too long to type all the time:

Runtime:addEventListener("collision", missile)

The mistake he has made is to treat ‘collision’ as a runtime event.  (fix suggested below in next post).

@sdktester15,

Your collision code is being set up wrong, try this.

local function shoot() local vx, vy = ship:getLinearVelocity() --print(vx, vy) if (vx \< -50 or vx \> 50) or (vy \< -50 or vy \> 50) then local missile = display.newImageRect(group, "sprite/ship/Rocket.png", 100, 65) missile.x, missile.y = ship.x, ship.y missile.rotation = ship.rotation - 90 physics.addBody(missile, "dynamic", {isSensor = true}) missile:setLinearVelocity(vx \* 3, vy \* 3) missile:toBack() missile.collision = missileCollision -- listen("collision", missile) -- WRONG missile:addEventListener( "collision" ) -- CORRECT end end

@roaminggamer,

As you already pointed out, the “problem” is that your SSK2 command overrides  global collision handling (Runtime), but @sdktester here is implementing local collision handling as evidenced by the “( self, event )” arguments in his listener function. I imagine this can be confusing to users of SSK2… what does SSK2 do to “override” things if you want to use local collision detection?

Brent

@Brent,

There is some confusion here.  SSK does not override anything.

This:

local obj = display.newCircle( 10, 10, 10) obj.enterFrame = function( self ) end obj.mouse = function( self, event ) end Runtime:addEventListener( "enterFrame", obj ) Runtime:addEventListener( "mouse", obj ) Runtime:removeEventListener( "enterFrame", obj ) Runtime:removeEventListener( "mouse", obj )

Is the same as this (but this is easier to type):

local obj = display.newCircle( 10, 10, 10) obj.enterFrame = function( self ) end obj.mouse = function( self, event ) end listen( "enterFrame", obj ) listen( "mouse", obj ) ignore( "enterFrame", obj ) ignore( "mouse", obj )

This is also the same, but safer and easier yet (especially in cases of multiple Runtime listeners)

local obj = display.newCircle( 10, 10, 10) obj.enterFrame = function( self ) end obj.mouse = function( self, event ) end listen( "enterFrame", obj ) listen( "mouse", obj ) -- accelerometer will be safely ignored because obj wasn't 'listening' for it. -- ignoreList( { "enterFrame", "mouse", "accelerometer" }, obj )

…continuation of last post.

In no case is ‘listen’ or its counterparts supposed to be used for local listeners.  Just as Runtime:addEventListener() should not be use for local listeners.

The issue here is @sdktester15 got carried away using listen()  probably because last he was working on control code that used enterFrame and a custom global event listener ‘onJoystick’.

SSK does not mess with local event helpers.   Local events must be set up as per the usual.  I entertained supplying something like this, but then realized it would be a waste and could cause issues:

-- THIS CODE WON'T WORK; It was something I thought about allowing. -- local obj = display.newCircle() function obj.collision( self, event ) end obj:listen( "collision" ) -- AGAIN THIS WON'T WORK

@sdktester15,

Plaese post back when you’ve added the suggested change so we know how it turned out.

One final note on SSK (really SSK2) unless other questions are asked.
 
I answer almost all questions exclusively using SSK.  I know this may be confusing, but since SSK is now free and time is precious, I feel I can’t spend time writing long hand code when the SSK equivalent is quite legible.
 
So, apologies to all, but this is the best I can do.
 
For example, if @sdktester15 was doing the full SSK2 thing, his code would actually look like this using the SSK equivalent of display.* calls:

local function createAsteroids() for i = 1, 100 do local asteroid = ssk.display.newImageRect( group, math.random(1,1000), math.random(1,1000), "sprite/rock/brownlarge1.png", { w = 134, h = 115, id = "asteroid", rotation = math.random(1,360) }, { } ) -- 2nd table adds basic body asteroid:applyTorque(math.random(1, 15), math.random(1, 15)) end end createAsteroids() local function missileCollision(self, event) if event.phase == "began" then if event.other and event.other.id == "asteroid" then createExplosion(event.other.x, event.other.y) display.remove(event.other) display.remove(self) print("collided") end end end local function shoot() local vx, vy = ship:getLinearVelocity() --print(vx, vy) if (vx \< -50 or vx \> 50) or (vy \< -50 or vy \> 50) then local missile = ssk.display.newImageRect( group, ship.x, ship.y, "sprite/ship/Rocket.png", { w = 100, h = 65, collision = missileCollision, rotation = ship.rotation - 90 }, { isSensor = true } ) missile:setLinearVelocity(vx \* 3, vy \* 3) missile:toBack() end end

More examples:

https://roaminggamer.github.io/RGDocs/pages/SSK2/libraries/display_standard/#ssk-versus-pure-corona-sdk

https://roaminggamer.github.io/RGDocs/pages/SSK2/libraries/display_samples/

None of the above should be read as me not liking Corona, nor as me poo poo-ing it.

Corona rocks, but I’m so used to using SSK any more that I just can’t change my ways when writing help (for the most part).

Call me lazy, it’s OK.

(This is most definitely a hijack, so if requested I’ll remove this post;  Also I am sure this is better documented elsewhere so again, if requested I’ll remove this post or shorten it and link to the official docs.

Not about SSK, but it occured to me that nomenclature is confusing and I often mess it up, so … at the risk of hijacking this thread, I’d like to post my understanding of events, listeners, and the nomenclature for them…
 
Events
As I have always understood it, there are two basic categories of events: local and global.  Most events exist in only one category, while some existin both.

  • enterFrame - global
  • collision - local
  • touch - local or globl

Listeners
Similarly, listeners come in two basic varieties:

  • Function Listeners

    local obj = display.newCircle( 10, 10, 10 ) local function enterFrame() end Runtime:addEventListener( “enterFrame”, enterFrame )

  • Table Listeners

    local obj = display.newCircle( 10, 10, 10 ) local function enterFrame( self ) end obj.enterFrame = enterFrame Runtime:addEventListener( “enterFrame”, obj )

The Confusing Part (It was for me… for a long time)
There is generally no specific rule that says one type of event must use one type of listener.  In fact, all of these examples are legal.  
 
global event - enterFrame w/ function listener

local obj = display.newCircle( 10, 10, 10 ) local function enterFrame() obj.x = obj.x + 1 end Runtime:addEventListener( "enterFrame", enterFrame )

 
global event - enterFrame w/ table listener

local obj = display.newCircle( 10, 10, 10 ) local function enterFrame( self ) self.x = self.x + 1 end obj.enterFrame = enterFrame Runtime:addEventListener( "enterFrame", obj )

 
global event - touch w/ function listener  (corrected after initial post)
 

-- obj is not the object that is being touched. It is the screen. local obj = display.newCircle( 10, 10, 10 ) local function touch( event ) obj:setFillColor( 1, 1, math.random() ) end Runtime:addEventListener( "touch", touch)

 
global event - touch w/ table listener   (corrected after initial post)

-- obj is not the object that is being touched. It is the screen. local obj = display.newCircle( 10, 10, 10 ) local function touch( self, event ) self:setFillColor( 1, 1, math.random() ) end obj.touch = touch Runtime:addEventListener( "touch", obj )

local event - touch w/ function listener (corrected after initial post)

local obj = display.newCircle( 10, 10, 10 ) local function touch( self, event ) self:setFillColor( 1, 1, math.random() ) end obj:addEventListener( "touch", touch )

  
local event - touch w/ table listener

local obj = display.newCircle( 10, 10, 10 ) local function touch( self, event ) self:setFillColor( 1, 1, math.random() ) end obj.touch = touch obj:addEventListener( "touch" )

 
 
Having said that, I typically restrict myself to table listeners because that makes associating the code with objects easier and cleaner.

Finally, if I messed up anything in this post, please correct me!  I don’t want to be wrong and I don’t want to lead anyone astray!  I think I have this all straight, but I have misused these terms many a time in the past.

Cheers,

Ed

Thanks for all your replies guys:

@everyone: I’ll add SSK2 in the title so you know that the problem will have something to do with that.  :smiley:

@roaminggamer: I added your code, and when the missile hits the asteroid, Corona has a heart attack and the application quits.  :wacko:

I did leave out another line of code that might have something to do with this:

timer.performWithDelay(1000, shoot, 0)&nbsp;

@nick: Don’t worry about me starting multiple projects, my other game is ongoing, these are just a few tests for a game I want to release in the future.  :wink:

@appletreeman: If this discussion hits the second page, then I will zip up my project.  :lol:

I am abusing the emojis now.

  1. Remember, if you have global event listeners attached to an object, you have to stop those listeners before deleting the object.

  2. Don’t do any physics related work in a collision handler.  Defer it by one cycle:

    function collision( self, event ) timer.performWithDelay( 1, – wait 1ms ends up being next frame function() – physics work here end ) end

  3. Did you get a crash log?

I did not get a crash log of any kind. The application just quits.

I have modified my collision code to this:

local function missileCollision(self, event) if event.phase == "began" then if event.other and event.other.id == "asteroid" then timer.performWithDelay(1, function() self:removeEventListener("collision") createExplosion(event.other.x, event.other.y) display.remove(event.other) display.remove(self) end, 1) end end end

And the same occurs. Should I use a finalize listener?

No need… objects can be safely removed on a collision event, you don’t need to defer that by a timer delay.

I will remove the timer then.

I figured out the source of the crash. I was getting a crash log, but Corona quit way too fast for me to see it. I recorded my screen and I see the error:

local explosionData = {name = "explosion", start = explosionInfo:getFrameIndex("thruster1"), count = 8, time = 350, loopCount = 1} | | | V start = explosionInfo:getFrameIndex("thruster1") -- Wrong starting index start = explosionInfo:getFrameIndex("explosion1") -- Right starting index

Anyways, that’s done, but my explosions do not appear where I want them to be. They should be appearing where the asteroids are, but they appear somewhere else.

https://youtu.be/12BTRC0cuHc