Collision detection scope with multiple lua files.

Hi all,

I’m new to Lua, only started about 4 days ago. I’m not new to programming though.

I’ve been working on a moderately simple game, of the vertical shooter sort like Galaga etc.

I noticed a strange bug in my code, basically I have several files, main which I use to load up backgrounds/sounds etc which I also wish to use to handle collisions. I also have a file pow which I use to create power ups for use in the game. Currently I’m implementing a speedup power up, simply on collision between the player and the image of the power up.
This is my current code in this class:

module(..., package.seeall);  
function new()   
 require "sprite";  
 local sheetSpeed = sprite.newSpriteSheet( "Media/Images/speedSheet.png", 59,66);  
 local spriteSetSpeed = sprite.newSpriteSet(sheetSpeed, 1, 2); -- two frames.  
 sprite.add( spriteSetSpeed, "flash", 1, 2, 200, 0 ); -- play 2 frames every 500 ms  
  
 local speedUp = sprite.newSprite( spriteSetSpeed );  
 speedUp.myName = "speed";  
 speedUp.x = \_W/2; speedUp.y = 0;  
 physics.addBody(speedUp, { isSensor = true });  
  
 speedUp:prepare("flash");  
 speedUp:play();  
  
 speedUp:setLinearVelocity(0,100);  
  
 speedUp.collision = speedCollision  
 speedUp:addEventListener( "collision", speedUp );  
 --end  
end  
  
function speedCollision( self, event ) -- Self is the power up in this case. Other is the player.  
 if(event.phase == "began") then  
 if(event.other.myName == "Flyer") then  
 audio.play(power\_sound);  
 print( self.myName .. ": collision began with " .. event.other.myName )  
 end  
 end  
end  

Now if I create the function speedCollision in main, when a collision occurs no code is executed in the body of the function. However, if I create the function speedCollision in the lua file where this power up resides, or any other file for that manner, the code works perfectly. I have done a similar thing with collision detection between an enemy and a players bullet, whereby I said enemy.collison = … and that … was created and handled in main which works perfectly.

Is there a limit to the number of collision functions in each lua file or something? What’s going on here? [import]uid: 116225 topic_id: 20739 reply_id: 320739[/import]

Are you using multiple groups? [import]uid: 52491 topic_id: 20739 reply_id: 81456[/import]

Thanks for your reply.
I’m not using any groups. [import]uid: 116225 topic_id: 20739 reply_id: 81462[/import]

I expect this may be because the speedUp is local - try removing local, test that and let me know results please.

Peach :slight_smile: [import]uid: 52491 topic_id: 20739 reply_id: 81469[/import]

Unfortunately it didn’t work. I tested changing it to global late at night last night and I didn’t put it back in main so I thought it worked. I tried it again this morning putting it in main and still nothing :(.

Hmmm, I just found something interesting. If I put both the collision handling functions in pow.lua only the speedUp collision works, the collision code between enemies and the player’s bullet no longer works. Could the error be something with my enemy bullet collision code?

  
function fire\_button:touch(event)  
 if(event.phase == "began") then  
 image\_Select({type = "fire\_btn\_start"});  
 audio.play(bullet\_sound);  
 player\_shot = display.newImage("Media/Images/Player\_Bullet.png");  
 player\_shot.myName = "bullet";  
 player\_shot:setReferencePoint(display.CenterReferencePoint);  
 player\_shot.x = plane.x; player\_shot.y = plane.y-40; -- Can't use plane.x wonder why?  
 physics.addBody(player\_shot, { isSensor = true });  
 player\_shot:setLinearVelocity(0,bullet\_speed);  
  
 -- Every player bullet gets assigned it's own collision label.  
 player\_shot.collision = onBulletCollision  
 player\_shot:addEventListener( "collision", player\_shot );  
 end  
  
function onBulletCollision( self, event )  
 if(event.phase == "began") then  
 if(event.other.myName == "met") then -- This stops multiple collisions Without it has collision detected if object off screen also.  
 audio.play(explode\_sound);  
 print( self.myName .. ": collision began with " .. event.other.myName ) -- Collision testing ok.  
 self:removeSelf(); -- Remove bullet.  
 -- Bug with explosion scope??? Always seen as nil. Doesn't know which explosion instance talking about.  
 xCoord = event.other.x; yCoord = event.other.y;  
 event.other:removeSelf();  
  
 -- Once enemy is gone, create explosion at coordinate. This happens for every enemy.  
 require "sprite";  
 sheetExplosion = sprite.newSpriteSheet( "Media/Images/explosionSheet.png", 99,119);  
 spriteSetExplosion = sprite.newSpriteSet(sheetExplosion, 1, 3); -- three frames.  
 sprite.add( spriteSetExplosion, "expl", 1, 3, 100,0); -- play 3 frames once. 0.1s animation.  
  
 explosion = sprite.newSprite( spriteSetExplosion );  
 explosion.x = xCoord; explosion.y = yCoord;  
  
 explosion:prepare("expl");  
 explosion:play();  
 timer.performWithDelay(100, explody, 1);  
 end  
 end  
end  

I only put the lines

player\_shot.collision = onBulletCollision  
 player\_shot:addEventListener( "collision", player\_shot );  

In one of the objects involved in my collisions. In the bullet collision only on the bullet, and in the power up collision only the power up. Would this have anything to do with it?
[import]uid: 116225 topic_id: 20739 reply_id: 81481[/import]

Could you return the object so it was local in your main game file, perhaps?

I believe Ghosts VS Monsters may demonstrate that.

Peach :slight_smile: [import]uid: 52491 topic_id: 20739 reply_id: 81631[/import]

Thanks for all your help Peach :slight_smile:

Unfortunately your suggestion didn’t work either. I have many scoping issues in this game. I think I may have to rewrite the game, the functionality is all fine, but I just need to organise it much better and make as much as I can local. [import]uid: 116225 topic_id: 20739 reply_id: 81643[/import]

I am surprised to hear that didn’t work and yes, the problem seems a little broad - you may want to consider reading this article as you proceed; http://blog.anscamobile.com/2011/09/a-better-approach-to-external-modules/

Sorry I couldn’t give you a simple answer :frowning: [import]uid: 52491 topic_id: 20739 reply_id: 81653[/import]

Thanks for that link Peach, I have reprogrammed my game using that method of external modules. Unfortunately the error must not be related to that because I have ended up with the exact same error :(.

I will elaborate more this time. I don’t think it is because multiple collision per file are not allowed, because I tested using 2 collisions in a file and it worked fine, something else is going on here.

In main I wish for the following collision handling functions to be used: (I will post my entire main file as I suspect there is something wrong in there somewhere).

-- Shooter Engine 1.0.  
-- If an object is not defined when it is called, a nil error will occur.  
-- Don't want anything global - creates scope issues.  
-- Touch listeners and collision listeners (I think) get removed auto, only enterFrames don't.  
-- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
-- Private part of module.  
-- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
  
-- Use this to access other modules.  
local Player = require("Player");  
local Enemy = require("Enemy");  
local Pow = require("Pow");  
  
-- Local Constants  
local \_H = display.contentHeight;  
local \_W = display.contentWidth;  
  
-- Local Variables  
local xCoord; -- Used to position explosion.  
local yCoord; -- Used to position explosion.  
local explosion; -- Solve timer parameter issue.  
local sheetExplosion; -- Solve timer parameter issue.  
-- Enable Physics Engine.  
physics = require("physics");  
physics.start();  
physics.setGravity(0,0); -- Eliminate gravity.  
  
-- Background music to be loaded.  
local soundtrack = audio.loadStream("Media/Sound/Background\_Music.aiff");  
  
-- Background images to be loaded.  
-- Used to remove bullets off stage.  
local ceiling = display.newRect(0,0,\_W,1); -- position top left, \_W is display width 20 is height.  
ceiling:setReferencePoint(display.CenterReferencePoint); -- center ref pt is important with physics.  
ceiling.x = \_W/2; ceiling.y = -30;  
ceiling.isHitTestable = true;  
ceiling.isVisible = false;  
ceiling.myName = "ceiling";  
physics.addBody(ceiling, { isSensor = true });  
  
-- Play music when app is launched.  
audio.play(soundtrack, {loops=-1}); -- Loops infinite times (-1).  
audio.setVolume(1.0, { channel=1 } ); -- Use to adjust background sound volume.   
  
-- Load background image here.  
-- Instantiate Player.  
local hero = Player.new(); -- Call new function in player.lua.  
Player.start\_Playing(); -- Call start\_Playing function in player.lua  
Enemy.new(100,0,0,100);  
Enemy.new(300,0,0,100);  
Pow.new();  
  
-- Instantiate Enemies.  
  
local function explody()  
 print( "in explody" );  
 explosion:removeSelf();  
 explosion = nil;  
 -- These two lines free texture from memory.  
 sheetExplosion:dispose();  
 sheetExplosion = nil;  
end  
-- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
-- Public part of module.  
-- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
  
-- Put collision stuff here.  
function onBulletCollision( self, event )  
 if(event.phase == "began") then  
 -- Use an elseif here, so it hits the enemy OR it goes off screen for a second and is removed. Don't want to be able to shoot enemies off screen.  
 -- Could use another if here if have different types of enemies.  
 -- To free up memory. Remove bullet when off screen.  
 if(event.other.myName == "met") then  
 print( self.myName .. ": collision began with " .. event.other.myName ); -- Collision testing ok. (Remove on release).  
 self:removeSelf(); -- Remove self (bullet).  
 self = nil; -- Extra cautious.  
  
 xCoord = event.other.x; yCoord = event.other.y; -- Get coordinates of meteor.  
 event.other:removeSelf(); -- Remove the meteor from memory.  
 event.other = nil; -- Removing this allows us to go into other if statement.  
 print( xCoord .. " " .. yCoord ); -- Check ok. (Remove on release).  
  
 -- Once enemy is gone, create explosion at coordinate. This happens for every enemy.  
 require "sprite";  
 sheetExplosion = sprite.newSpriteSheet( "Media/Images/explosionSheet.png", 99,119);  
 local spriteSetExplosion = sprite.newSpriteSet(sheetExplosion, 1, 3); -- three frames.  
 sprite.add( spriteSetExplosion, "expl", 1, 3, 100,0); -- play 3 frames once. 0.1s animation.  
  
 explosion = sprite.newSprite( spriteSetExplosion ); -- Load explosion image.  
 explosion.x = xCoord; explosion.y = yCoord; -- Position at the (x,y) coordinates of meteor.  
  
 explosion:prepare("expl"); -- Load animation.  
 explosion:play(); -- Play animation.  
 timer.performWithDelay(100, explody, 1); -- Give object time to animate. Pass newly created explosion object to explody function.  
 elseif(event.other.myName == "ceiling") then  
 print( self.myName .. ": collision began with " .. event.other.myName ); -- Collision testing ok.  
 self:removeSelf();  
 self = nil;  
 end  
 end  
end  
  
function onPlaneCollision( self, event )  
 if(event.phase == "began") then  
 if(event.other.myName == "met") then  
 print( self.myName .. ": collision began with " .. event.other.myName );  
 end  
 end  
end  
  
function speedCollision( self, event )  
 if(event.phase == "began") then  
 if(event.other.myName == "Hero") then  
 print( self.myName .. ": collision began with " .. event.other.myName );  
 end  
 end  
end  

my onBulletCollision( self, event ) code executes perfectly. the problem arises with the other two functions, onPlaneCollision and speedCollision. When a collision happens no code is executed for either of the two. If I put the two functions inside any other file - Pow.lua for example, it works fine. Shown below:

-- Power up functionality code.  
-- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
-- Private part of module.  
-- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*   
  
-- Local Constants.  
local \_H = display.contentHeight;  
local \_W = display.contentWidth;  
  
-- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
-- Public part of module.  
-- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
local Pow = {};  
  
-- Create a power up object.  
Pow.new = function()   
 require "sprite";  
 local sheetSpeed = sprite.newSpriteSheet( "Media/Images/speedSheet.png", 59,66);  
 local spriteSetSpeed = sprite.newSpriteSet(sheetSpeed, 1, 2); -- two frames.  
 sprite.add( spriteSetSpeed, "flash", 1, 2, 200, 0 ); -- play 2 frames every 500 ms  
  
 local speedUp = sprite.newSprite( spriteSetSpeed );  
 speedUp.myName = "speed";  
 speedUp.x = 400; speedUp.y = 0;  
 physics.addBody(speedUp, { isSensor = true });  
  
 speedUp:prepare("flash");  
 speedUp:play();  
  
 speedUp:setLinearVelocity(0,100);  
  
 speedUp.collision = speedCollision  
 speedUp:addEventListener( "collision", speedUp );  
 return speedUp;  
end  
  
function onPlaneCollision( self, event )  
 if(event.phase == "began") then  
 if(event.other.myName == "met") then  
 print( self.myName .. ": collision began with " .. event.other.myName );  
 end  
 end  
end  
  
function speedCollision( self, event )  
 if(event.phase == "began") then  
 if(event.other.myName == "Hero") then  
 print( self.myName .. ": collision began with " .. event.other.myName );  
 end  
 end  
end  
  
return Pow;  

I am doing my collisions the exact same way as my onBulletCollision code, I’ll show direct comparisons here: (they both appear in the same file).

function fire\_button:touch(event)  
 if(event.phase == "began") then  
 image\_Select({type = "fire\_btn\_start"});  
 audio.play(bullet\_sound);  
 local player\_shot = display.newImage("Media/Images/Player\_Bullet.png");  
 player\_shot:setReferencePoint(display.CenterReferencePoint);  
 player\_shot.x = plane.x; player\_shot.y = plane.y-40;  
 player\_shot.myName = "bullet";  
 physics.addBody(player\_shot, { isSensor = true });  
 player\_shot:setLinearVelocity(0,bullet\_speed);  
  
-- Every player bullet gets assigned it's own collision label.  
 player\_shot.collision = onBulletCollision -- Can call onBulletCollision in main directly as it is public.  
 player\_shot:addEventListener( "collision", player\_shot );  
 end  
 if(event.phase == "ended") then  
 image\_Select({type = "fire\_btn\_end"});  
 end  
 return true;  
end  
fire\_button:addEventListener("touch", fire\_button);  
Player.new = function()  
 require "sprite";  
 local sheetPlayer = sprite.newSpriteSheet( "Media/Images/spriteSheet1.png", 123,120);  
 local spriteSetPlayer = sprite.newSpriteSet(sheetPlayer, 1, 2); -- two frames.  
 sprite.add( spriteSetPlayer, "flying", 1, 2, 200, 0 ); -- play 2 frames every 1000 ms  
  
 plane = sprite.newSprite( spriteSetPlayer ); -- Uses local plane declared up top, this plane is not scoped to this function, so other functions in player.lua can access it.  
 plane.x = \_W/2; plane.y = \_H-plane.width-30;  
 plane.myName = "Hero";  
 physics.addBody(plane, { isSensor = true });  
  
 plane:prepare("flying");  
 plane:play();  
  
-- Every plane gets assigned it's own collision label.  
 plane.collision = onPlaneCollision;  
 plane:addEventListener( "collision", plane );  
  
 return plane;  
end  

The way I did speedUp was shown in the Pow.lua code. I can’t for the life of me figure out why they don’t work in main, it is quite frustrating, I thought it would definitely have been resolved after reprogramming virtually everything to avoid global variables where possible and avoided the deprecated method of using modules.

Any additional help on this issue would be greatly appreciated.
[import]uid: 116225 topic_id: 20739 reply_id: 82433[/import]

I would suggest perhaps uploading your project and posting a link and hoping someone has the free time to look at it, or if it is a matter of urgency using premium support; http://www.anscamobile.com/corona/support/

This is just because the above will take a fair chunk of time to go through.

Alternatively you could try to make a new project, a mini one, to try and isolate the problem further. (This is often my first course of action in these situations.) [import]uid: 52491 topic_id: 20739 reply_id: 82440[/import]

Hi Peach, you make a good point.

Here is my game here, this will be much easier to read. It’s not too urgent, I’ll try making my game by spreading the collisions over a few files to avoid this issue. This issue won’t stop me from making the game, but I really want to learn from it.

Below is the link for my game:

http://uploading.com/files/4948m315/Game1_11.zip/

Thanks in advance anyone who takes the time to look at it, it’s not a massive game at the moment, it is just under 400 lines, I’ve tried to make it as easy to follow as possible. [import]uid: 116225 topic_id: 20739 reply_id: 82603[/import]