Assertion Failed, can't figure out why.

Hello everyone,

I have attached the code for the game I am currently working on. I am currently trying to get collisions to work, but calling the function from my shoot(event) function is resulting in the following error:

assertion failed!

stack traceback:

   [c]: ?

   [c]: in function ‘assert’

   ?: in function ‘getOrCreateTable’

   ?: in function ‘addEventListener’

   ?: in function ‘addEventListener’

   

This particular error occurs at this line in my code:

bullet:addEventListener(“collision”, OnCollision)

For my player and my enemy listeners, this line of code works fine. I can’t seem to figure out the problem with this particular instance. Any help would be appreciated. 

capital “O”? (just a guess, didn’t read)

Oh my gosh…I can’t believe I didn’t see that. Thank you, that got rid of the error in question, but did leave me with another. 

On this line:

    if(event.player.myName == “player” and event.enemy.myName == “enemy”) then

"attempt to index field ‘player’ (a nil value)

This is in my onCollision function. Any ideas on what went wrong there? Something to do with it not being local, maybe?

The event handler doesn’t know anything about ‘player’ or ‘enemy’.

You get a reference to ‘object1’ which is the first object on the collision, and ‘object2’ which is the second object.

http://docs.coronalabs.com/api/event/collision/index.html

‘object1’ and ‘object2’, and be either ‘player’ or ‘enemy’, so you’ll have to code accordingly.

Ok, I switched it to the following:
 

    if(event.object1.myName == “player” and event.object2.myName == “enemy”) then

    

        enemyGroup:remove()

        GameRunning = false

        intscore = 0

    

    local function gameOverScreen()

            gameOver = display.newImage(‘GameOver.png’)

            gameOver.x = display.contentCenterX

            gameOver.y = display.contentCenterY + 10

            gameOver:addEventListener(“tap”, titleScreen)

        end

    end    

    

    if(event.object1.myName == “bullet” and event.object2.myName == “enemy”) then

        

        intscore = intscore + 100

        event.object2:removeSelf()

        event.object1:removeSelf()

        

    end

end

And got the same error, only with “object1” where “player” used to be. Is it something to do with me not using “begin” and “ended?” 

You’re using both global and local collision handling on your objects which I expect will cause weird results.

You should decide which approach you want to use. Your local collision handling is also declared incorrectly (you need to add a .collision property to your objects). It’s explained in the docs below.

I think it will help to read about Corona’s collision handling here:

http://docs.coronalabs.com/guide/physics/collisionDetection/index.html

Ok, so I should try adding

“object”.collision = onLocalCollision 

“object”:addEventListener(“collision”, “object”)

Where I declare each object? Such as one for player in spawnPlayer? 

You shouldn’t add the " ".

So it would be something like:

enemy.collision = onCollision enemy:addEventListener("collision", enemy)

(The name of the event handler is up to you)

…and remember to remove all Runtime:addEventListener(“collision”, onCollision) statements.

ingemar, thank you for your help so far, I feel like I’m better understanding how to organize my code.

But now whenever a bullet hits an enemy, I get the following error:

attempt to index upvalue ‘enemy’ (a nil value)

this occurs on the following line:

enemy.collision = onCollision

I checked, and there are no errors like the capital O earlier. I’ve also removed the Runtime EventListeners. Here is my onCollision function as it is now. 
 

function onCollision(event) if(event.object1.myName == "player" and event.object2.myName == "enemy") then enemyGroup:remove() GameRunning = false intscore = 0 local function gameOverScreen() gameOver = display.newImage('GameOver.png') gameOver.x = display.contentCenterX gameOver.y = display.contentCenterY + 10 gameOver:addEventListener("tap", titleScreen) end end if(event.object1.myName == "bullet" and event.object2.myName == "enemy") then intscore = intscore + 100 event.object2:removeSelf() event.object1:removeSelf() end end

I’m unclear on what “index upvalue” means exactly, so I’m not sure how to go about debugging it. 

I’m still getting alerts for this :smiley: so I’ll jump back in…

Collision handling is tricky, here’s a couple quick tips:

* note that player OR enemy could be object1 (or object2), there’s no guaranteed order, same for bullet vs enemy in second test.

* AND you may get BOTH versions! one from the ‘player perspective’ when it collides with enemy, another from the ‘enemy perspective’ when it collide with player. generally you need to set a flag on your objects (like player.alive=false) when collision occurs, and TEST for that flag before you RE-process the opposing collision. <- this could be the source of your “index upvalue” error - trying to remove something that was already removed - hard to know for sure as we don’t see the ‘enemy’ variable in use in your snippet.

* removeSelf() (or display.remove()) should be avoided inside the collision handler - physics will NOT be happy if you try to destroy a body it is currently processing. some would suggest timer.performWithDelay(), I’d suggest sweeping your objects later manually and purging the ones where “alive==false” (but that’s just me, as i don’t trust timers - as it seems they’re as likely to fire NEXT frame during some equally inopportune moment - i’d rather be completely in control of when important stuff like this occurs)

* is your gameOverScreen() function really intended to be local to that if statement??

etc, hth

Well I suppose I could just call the gameover function inside the if statement and place the function globally. 

Considering your second point about both versions, how would you recommend I go about doing this with my code? I’m kinda new to collisions and Corona in general, so I think maybe I set this up completely weird. 

Should I add if statements going in both directions? That seems like a lot of extra code, but I’m not sure. 

Also, is alive something I need to declare, or is it a built in function? If it’s built in, I think I have an idea of how to implement it, namely just calling things alive when I spawn them and then setting alive to false as things hit them. And then I could just do that sweep thing where alive is equal to false, as I go into the gameOverScreen. Am I thinking about that right?

i just mentioned your gameover since it’s not called there, and not callable from elsewhere since local, so it’s “dead code” as is - but maybe it’s just a stub for work in progress and will make sense later?

you can just “decorate” your corona display objects with user-defined properties, like “alive”, or “isDead” (flipping the logic) or whatever, after creation: player.alive=true, simple as that. (just watch out not to “clobber” corona internal property names)

yep, more code. first thing i usually do is create some easier-to-type aliases, then get on with the ugly tests:

-- consider this pseudo-code, just to convey ideas, not to run as-is: local o1 = event.object1 -- just an alias for lazy typers local o2 = event.object2 if ((o1.name=="player" and o2.name=="enemy") or (o2.name=="player and o1.name=="enemy")) then -- ok, it's player-versus-enemy, but are they both still alive? if (o1.alive and o2.alive) then -- yep, both alive, collision needs handling.. o1.alive = false o2.alive = false -- etc else -- NOP, at least one is already dead, ignore this "late" collision end end -- much later, cleanup, in an enterFrame loop for example: if (not player.alive) then display.remove(player) -- spawn cool explosion gfx -- play awesome sound effect -- show "game over" -- etc end for each enemy if not enemy.alive then -- remove it, add score, etc end end for each bullet, similar

hth

Ok, I added the .alive declarations where necessary, and added the if statements to my onCollision function. I now get an error on my object1 in the inital if statement, and I think I may know why.

Since I am using local collisions by calling things like 

player.collision = onCollision player:addEventListener("collision",&nbsp;player)

in my spawnPlayer function, do I need to use the words “self” and “other” instead of “object1” and “object2?” 

EDIT: Apparently not. Unless I’m misusing “self” and “other,” I get the same error. 

It reads: attempt to index field ‘object1’ (a nil value)

I feel like I’m missing something crucial about the use of words like ‘object1.’ 

Ah, totally different - and you’ll have to sort out the differences. When I saw your use of “object1/object2” in your snippet I assumed you were using a “global” collision listener. (since those properties don’t exist in the local listener event)

If, as it now appears, you’re using local listeners, then much of my previous reply simply doesn’t apply. The first parameter of the listener IS guaranteed to be the “self” object (player in your last snippet), and the second parameter “event” will only have ONE “.other” object (not two: .object1 and .object2) So the if statements are simplified, and the event object itself has changed. You can name the parameters of your listener function whatever you want, but “self” and “event” are the convention.

Your use of any of those magic words (self, other, object1, object2, etc) are merely dependent on what you name your parameters of the listener, and what Corona has named the properties of two different events (for local and global listeners). Though using standard conventions helps when following examples in the docs.

It’s not a big deal, but you DO have to get it sorted, or you’ll continue to get these errors when referring to things that don’t exist. This doc in particular is well worth the time to read word-for-word: https://developer.coronalabs.com/content/game-edition-collision-detection

hth

Thanks guys, I made a major breakthrough after I switched back to global collisions. Now I get none of those errors that I was getting, and I can actually score and everything!

There is still one minor problem…the collisions don’t work every time. Sometimes the bullet hits the enemy, it disappears, and so does the enemy, and I get points. Every other time the bullet goes right past the enemy, BUT the physics body for the enemy rotates a little as it gets hit. Do I need some sort of collider to fix this?

I’ve uploaded my code again, just in case. Also, let me know if I should start another topic for this particular problem, as my original issue is technically resolved, it just spawned a bunch of other issues. 

capital “O”? (just a guess, didn’t read)

Oh my gosh…I can’t believe I didn’t see that. Thank you, that got rid of the error in question, but did leave me with another. 

On this line:

    if(event.player.myName == “player” and event.enemy.myName == “enemy”) then

"attempt to index field ‘player’ (a nil value)

This is in my onCollision function. Any ideas on what went wrong there? Something to do with it not being local, maybe?

The event handler doesn’t know anything about ‘player’ or ‘enemy’.

You get a reference to ‘object1’ which is the first object on the collision, and ‘object2’ which is the second object.

http://docs.coronalabs.com/api/event/collision/index.html

‘object1’ and ‘object2’, and be either ‘player’ or ‘enemy’, so you’ll have to code accordingly.

Ok, I switched it to the following:
 

    if(event.object1.myName == “player” and event.object2.myName == “enemy”) then

    

        enemyGroup:remove()

        GameRunning = false

        intscore = 0

    

    local function gameOverScreen()

            gameOver = display.newImage(‘GameOver.png’)

            gameOver.x = display.contentCenterX

            gameOver.y = display.contentCenterY + 10

            gameOver:addEventListener(“tap”, titleScreen)

        end

    end    

    

    if(event.object1.myName == “bullet” and event.object2.myName == “enemy”) then

        

        intscore = intscore + 100

        event.object2:removeSelf()

        event.object1:removeSelf()

        

    end

end

And got the same error, only with “object1” where “player” used to be. Is it something to do with me not using “begin” and “ended?”