How many checks can the corona engine handle for "collision"

Hello I have my normal

Runtime:addEventListener(“collision”, onCollision) for my player which is working nicely,

I also have Runtime:addEventListener(“collision”, weaponCollision) for the weapons that the player are using.

An example of me checking like a single item/npc/monster/etc:

elseif (agro.type == "player" and hit.type == "randItem\_1") or             (agro.type == "randItem\_1" and hit.type == "player") then

List goes down using only elseif so only 1 check per function…I would like them all to be if’s to check for multiple still…but that could eventually be checking down 3600 times in a function (see my math below for this)!

Both are working nicely, I’m making a more adventure style game and the amount I am checking for is increasing everyday. example for the player colliding/checking with NPCs, randomItemSpawns (10+), small monsters(10+), medium monsters(10+), monster hit types depending on the monsters(countless amounts), save touches, etc etc etc list goes on.

Also the weaponCollision I plan to even be higher with like 60 different weapons(would be nice) right now there are 6, and this is starting to become a very big list for the weaponCollision being (ex. boomerang checking against 10 different pots, and also sword checking for 10 different pots, boomerang checking against the 30 types of monsters and sword checking for different types of monsters, etc) so the weaponCollision will soon get huge depending on the increase of weapons.

My question is, how many checks can this handle and could I implement 60 weapons with possibly checking against 60 different things 60x60 = 3600 checks on the weaponCollision alone. Currently they both are checking for upwards of 40+ things on their own, but I’m thinking about the future. Also would have the animations for each weapon being (128x128 for 2 sides and x 2( for all 4 sides of player), can the phone even handle this amount of texture space? I’m assuming I would have to clean them out when not using them so only have 4 different weapons at least on use at once and call them in when being used. I also got the normal game (UI, weapons, npc’s, monsters, several maps, blah blah) which all seem to be running pretty close to constant 30 fps fine right now (hell of a work to get that to constant 30 fps).

Corona Dev would be greatly appreciated on this since they are the ones who made the engine :). Would like to give answers to my boss to let him know how far we can go with this weapon/item thing.

I’m not a Corona Labs employee, but here are some thoughts anyways:

  • You could decide what the worst case comparison is and make a piece of code to simulate that.  Then run it on your device.  This would definitively answer how many operations per collision are too many for that device.

  • However, I’d suggest turning your method above into a math equation.  Bitwise operations are supported using the bit library.

  • At the very least, if you are going to access values attached to objects over and over localize them like this:

    local obj = display.newCircle( … ) obj.myType = “weapon” obj.myValue = math.random(1,100) – This is slower… for i = 1, 100000 do if( ( obj.myType == “weapon” and (obj.myValue > 5 and obj.myValue < 20)) or ( obj.myType == “weapon” and obj.myValue == 99 ) then – empty fake case do nothing end end – This is faster for i = 1, 100000 do local objType = obj.myType local objValue = obj.myValue if( ( objType == “weapon” and (objValue > 5 and objValue < 20)) or ( objType == “weapon” and objValue == 99 ) then – empty fake case do nothing end end

Hey thanks for response, sorry I do localize them I forgot to add that important part:

local function onCollision(event) &nbsp;&nbsp; if event.phase == "began" then &nbsp;&nbsp; &nbsp;&nbsp; local agro = event.object1 &nbsp;&nbsp; &nbsp;&nbsp; local hit = event.object2 &nbsp;&nbsp; &nbsp;&nbsp; if (agro.type == "player" and hit.type == "sMob\_2") or &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;(agro.type == "sMob\_2" and hit.type == "player")then &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; --stuff &nbsp;&nbsp; elseif (agro.type == "player" and hit.type == "sMob\_1") or &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;(agro.type == "sMob\_1" and hit.type == "player")then &nbsp;&nbsp; elseif ... ...continue on down 3600 possible checks for future (I desire 60 weapons x 60 possible stuff to compare against minimum) end end

Could you explain more detail on using bitwise operations? Or please send me to a link or something so I can read up on it.

Hi Azmar,

You can read up on bit operations here:

http://bitop.luajit.org/api.html

And the plugin docs are here:

http://docs.coronalabs.com/daily/plugin/bit/index.html

Best regards,

Brent

My only concern with the bit thing is makes the current game very hard to read/understand, and sure I would understand it after implementing it…but any other programmer that joins the team in a few months makes the bit thing useability very low.

Brent any input on the current setup if it can handle it, with your experience?

If you think this is going to be a problem, isolate the bit operations in a separate function. Bear in mind that bitops probably limits your counts of things to 64 (possibly 63) as lua integers are 64 bit.

My base testing for speed is to have the worst Android tablet/phone I can get. eBay, for example, have 7" cheapies for £20-£30. They’re actually quite useable :slight_smile: (If I was Apple I’d be petrified), and an old phone my daughter was delighted to get rid of because it was rubbish ; if it’ll run on these it’ll run on pretty much anything. 

@Azamar,

I forgot to mention this, as I assumed it, but just in case.  Your 60x60 checks  won’t result in 3600 checks.  You can reduce your code significantly through the application of intelligent ordering:

This is inefficient:

-- Case 1 if (agro.type == "player" and hit.type == "randItem\_1") or (agro.type == "randItem\_1" and hit.type == "player") then end -- Case 2 if (agro.type == "player" and hit.type == "randItem\_2") or (agro.type == "randItem\_2" and hit.type == "player") then end ... -- Case N if (agro.type == "player" and hit.type == "randItem\_N") or (agro.type == "randItem\_N" and hit.type == "player") then end

This is better:

if (agro.type == "player" or hit.type == "player") then -- Case 1 if (agro.type == "randItem\_1" or hit.type == "randItem\_1") then end -- Case 2 if (agro.type == "randItem\_2" or hit.type == "randItem\_2") then end ... -- Case N if (agro.type == "randItem\_N" or hit.type == "randItem\_N") then end end

However, when I look at this code, I see a major issue.  It implies (as does your original question) that all objects are running the same listener code.  This will not work as you expect.  In fact, for every case where two objects have this listener code and they have a ‘true’ case in your code, the handler will do double work.

From what I see of your code, it seems that only the player should be running this.  Then the code could be simplified to this:

-- Assumes 'agro type' is player -- Case 1 if (hit.type == "randItem\_1") then end -- Case 1 if (hit.type == "randItem\_2") then end ... -- Case N if (hit.type == "randItem\_N") then end

Now, I may have totally misunderstood your need, but I have a solution to make your code faster regardless of your choices. 

In your code, you are creating and comparing a bunch of temporary strings, which is very slow when done frequently.  Instead you could use enumerations.

local \_player = 1 local \_randItem\_1 = 2 local \_randItem\_2 = 3 ... local \_randItem\_99 = 100 ... etc -- Case 1 if (agro.type == \_player and hit.type == \_randItem\_1 ) or (agro.type == \_randItem\_1 and hit.type == \_player ) then end -- Case 2 if (agro.type == \_player and hit.type == \_randItem\_2 ) or (agro.type == \_randItem\_2 and hit.type == \_player ) then end ... -- Case 100 if (agro.type == \_player and hit.type == \_randItem\_99 ) or (agro.type == \_randItem\_99 and hit.type == \_player) then end

Yes, you will have to be careful and this means having duplicate lists of enumeration, as well as a way to convert them to strings when you need them, but integer comparisons are  WAY faster than temporary string creation + comparison.  Also, the storage efficiency is better.

Cheers,

Ed

PS - As far as those duplicate lists of enumerated types, you can use my auto-localization code to make that faster to code and maintain:

http://roaminggamer.com/2014/07/08/auto-localization-trick-lua/

Thank you for the A+ answer , very much appreciated!!! I took the time to use the method to simplify the code and I used numbers instead for comparisons. Left out the player as normal string for now to keep this simple to read for the forum.

if (agro.type == "player" or hit.type == "player") then &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (agro.type == 1 or hit.type == 1) then &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; ... &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;elseif (agro.type == 2" or hit.type == 2) then &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; ... &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; end end

I don’t use enumerations, instead I just physically compare the numbers inside without using enumerations to create new temp variables. I don’t see how using temp enumerations that hold the integer value to after put the enumeration variable in to compare would be easier (only visibility to see the wording I guess).

I am having troubles doing “-- Assumes ‘agro type’ is player” as mentioned above, that would further simplify my code and would be useful, just can’t seem to figure out making the agro type always player. On the other hand, yes I did not think about the “double work” of the function, I do have very very rare occasions where right now only in boss fight on a certain move and how it resolves it will use the player function to do something. Otherwise its only used for the player 95% of the time, should that be in its own runtime function? Seems like a pain and a waste to have its own runtime function for this, as I already have 4 runtime functions always activated.

Yeah if I can figure out to always assume that agro.type is player or for the weapon case (since everything is now numbers) i can just determine is its below the max number of weapons amount it would register and only need 1 check:

ex.

if (agro.type \<= weaponNum and hit.name == "pot\_1")

That way inside that check I can just get the number and determine what to do (like how much damage based on weapon), problem is since I need to know that player or weapon always is agro.type like mentioned above otherwise it will crash because I would be comparing a string. I don’t want to convert agro.type to a number, that would cause new complications. How do I check to make sure it always assumes agro.type is player?

Sorry to bump, any input on the above post, great appreciated! Thanks for your time. I would like to figure out how to always know something in the collision function is always agro.type and something else is always hit.type so I don’t have to do double checks on

if (agro.type == “player” and hit.type == “sMob_2”) or (agro.type == “sMob_2” and hit.type == “player”)then

I’m not a Corona Labs employee, but here are some thoughts anyways:

  • You could decide what the worst case comparison is and make a piece of code to simulate that.  Then run it on your device.  This would definitively answer how many operations per collision are too many for that device.

  • However, I’d suggest turning your method above into a math equation.  Bitwise operations are supported using the bit library.

  • At the very least, if you are going to access values attached to objects over and over localize them like this:

    local obj = display.newCircle( … ) obj.myType = “weapon” obj.myValue = math.random(1,100) – This is slower… for i = 1, 100000 do if( ( obj.myType == “weapon” and (obj.myValue > 5 and obj.myValue < 20)) or ( obj.myType == “weapon” and obj.myValue == 99 ) then – empty fake case do nothing end end – This is faster for i = 1, 100000 do local objType = obj.myType local objValue = obj.myValue if( ( objType == “weapon” and (objValue > 5 and objValue < 20)) or ( objType == “weapon” and objValue == 99 ) then – empty fake case do nothing end end

Hey thanks for response, sorry I do localize them I forgot to add that important part:

local function onCollision(event) &nbsp;&nbsp; if event.phase == "began" then &nbsp;&nbsp; &nbsp;&nbsp; local agro = event.object1 &nbsp;&nbsp; &nbsp;&nbsp; local hit = event.object2 &nbsp;&nbsp; &nbsp;&nbsp; if (agro.type == "player" and hit.type == "sMob\_2") or &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;(agro.type == "sMob\_2" and hit.type == "player")then &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; --stuff &nbsp;&nbsp; elseif (agro.type == "player" and hit.type == "sMob\_1") or &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;(agro.type == "sMob\_1" and hit.type == "player")then &nbsp;&nbsp; elseif ... ...continue on down 3600 possible checks for future (I desire 60 weapons x 60 possible stuff to compare against minimum) end end

Could you explain more detail on using bitwise operations? Or please send me to a link or something so I can read up on it.

Hi Azmar,

You can read up on bit operations here:

http://bitop.luajit.org/api.html

And the plugin docs are here:

http://docs.coronalabs.com/daily/plugin/bit/index.html

Best regards,

Brent

My only concern with the bit thing is makes the current game very hard to read/understand, and sure I would understand it after implementing it…but any other programmer that joins the team in a few months makes the bit thing useability very low.

Brent any input on the current setup if it can handle it, with your experience?

If you think this is going to be a problem, isolate the bit operations in a separate function. Bear in mind that bitops probably limits your counts of things to 64 (possibly 63) as lua integers are 64 bit.

My base testing for speed is to have the worst Android tablet/phone I can get. eBay, for example, have 7" cheapies for £20-£30. They’re actually quite useable :slight_smile: (If I was Apple I’d be petrified), and an old phone my daughter was delighted to get rid of because it was rubbish ; if it’ll run on these it’ll run on pretty much anything. 

@Azamar,

I forgot to mention this, as I assumed it, but just in case.  Your 60x60 checks  won’t result in 3600 checks.  You can reduce your code significantly through the application of intelligent ordering:

This is inefficient:

-- Case 1 if (agro.type == "player" and hit.type == "randItem\_1") or (agro.type == "randItem\_1" and hit.type == "player") then end -- Case 2 if (agro.type == "player" and hit.type == "randItem\_2") or (agro.type == "randItem\_2" and hit.type == "player") then end ... -- Case N if (agro.type == "player" and hit.type == "randItem\_N") or (agro.type == "randItem\_N" and hit.type == "player") then end

This is better:

if (agro.type == "player" or hit.type == "player") then -- Case 1 if (agro.type == "randItem\_1" or hit.type == "randItem\_1") then end -- Case 2 if (agro.type == "randItem\_2" or hit.type == "randItem\_2") then end ... -- Case N if (agro.type == "randItem\_N" or hit.type == "randItem\_N") then end end

However, when I look at this code, I see a major issue.  It implies (as does your original question) that all objects are running the same listener code.  This will not work as you expect.  In fact, for every case where two objects have this listener code and they have a ‘true’ case in your code, the handler will do double work.

From what I see of your code, it seems that only the player should be running this.  Then the code could be simplified to this:

-- Assumes 'agro type' is player -- Case 1 if (hit.type == "randItem\_1") then end -- Case 1 if (hit.type == "randItem\_2") then end ... -- Case N if (hit.type == "randItem\_N") then end

Now, I may have totally misunderstood your need, but I have a solution to make your code faster regardless of your choices. 

In your code, you are creating and comparing a bunch of temporary strings, which is very slow when done frequently.  Instead you could use enumerations.

local \_player = 1 local \_randItem\_1 = 2 local \_randItem\_2 = 3 ... local \_randItem\_99 = 100 ... etc -- Case 1 if (agro.type == \_player and hit.type == \_randItem\_1 ) or (agro.type == \_randItem\_1 and hit.type == \_player ) then end -- Case 2 if (agro.type == \_player and hit.type == \_randItem\_2 ) or (agro.type == \_randItem\_2 and hit.type == \_player ) then end ... -- Case 100 if (agro.type == \_player and hit.type == \_randItem\_99 ) or (agro.type == \_randItem\_99 and hit.type == \_player) then end

Yes, you will have to be careful and this means having duplicate lists of enumeration, as well as a way to convert them to strings when you need them, but integer comparisons are  WAY faster than temporary string creation + comparison.  Also, the storage efficiency is better.

Cheers,

Ed

PS - As far as those duplicate lists of enumerated types, you can use my auto-localization code to make that faster to code and maintain:

http://roaminggamer.com/2014/07/08/auto-localization-trick-lua/

Thank you for the A+ answer , very much appreciated!!! I took the time to use the method to simplify the code and I used numbers instead for comparisons. Left out the player as normal string for now to keep this simple to read for the forum.

if (agro.type == "player" or hit.type == "player") then &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (agro.type == 1 or hit.type == 1) then &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; ... &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;elseif (agro.type == 2" or hit.type == 2) then &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; ... &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; end end

I don’t use enumerations, instead I just physically compare the numbers inside without using enumerations to create new temp variables. I don’t see how using temp enumerations that hold the integer value to after put the enumeration variable in to compare would be easier (only visibility to see the wording I guess).

I am having troubles doing “-- Assumes ‘agro type’ is player” as mentioned above, that would further simplify my code and would be useful, just can’t seem to figure out making the agro type always player. On the other hand, yes I did not think about the “double work” of the function, I do have very very rare occasions where right now only in boss fight on a certain move and how it resolves it will use the player function to do something. Otherwise its only used for the player 95% of the time, should that be in its own runtime function? Seems like a pain and a waste to have its own runtime function for this, as I already have 4 runtime functions always activated.

Yeah if I can figure out to always assume that agro.type is player or for the weapon case (since everything is now numbers) i can just determine is its below the max number of weapons amount it would register and only need 1 check:

ex.

if (agro.type \<= weaponNum and hit.name == "pot\_1")

That way inside that check I can just get the number and determine what to do (like how much damage based on weapon), problem is since I need to know that player or weapon always is agro.type like mentioned above otherwise it will crash because I would be comparing a string. I don’t want to convert agro.type to a number, that would cause new complications. How do I check to make sure it always assumes agro.type is player?