Detecting Multiple Collisions per Frame

[lua] local function collisionEvent(event)
  if event.phase == “began” then
   local obj1 = event.object1;
   local obj2 = event.object2;
   
   if ((obj1.type == “player”) and (obj2.type == “wall”)) or ((obj1.type == “wall”) and (obj2.type == “player”)) and (instance.isAligned) then
    local other;

    if obj1.type == “player” then
     other = obj2;
    else
     other = obj1;
    end

    if (other.x == instance.x) and (other.y < instance.y) then
     instance.collides[DIR_UP] = true;
     print(“collides above”);
    end
    
    if (other.y == instance.y) and (other.x > instance.x) then
     instance.collides[DIR_RIGHT] = true;
     print(“collides right”);
    end
    
    if (other.x == instance.x) and (other.y > instance.y) then
     instance.collides[DIR_DOWN] = true;
     print(“collides below”);
    end
    
    if (other.y == instance.y) and (other.x < instance.x) then
     instance.collides[DIR_LEFT] = true;
     print(“collides left”);
    end
   end
  end
 end[/lua]

The above code is what I am using to detect collisions of a dynamic physics body and a bunch of static sensor walls in a maze game. However, each frame when a collision occurs, it seems to be only detecting the first collision that occurs. For example, in a corner only one of the two collisions is actually picked up. What’s the best way to allow detection of multiple collisions at once in this case?

Hi @danielbeer1376,

If the walls are distinct objects, you should be getting a collision with each contact. There is a way to “average” collision points, but that’s not the default so unless you set that command somewhere by accident, you should be getting a response each time.

Brent

Yeah I’m definitely not averaging them but still can’t figure out how to make it work.

Could anyone maybe explain what the best way to check for collisions in this kind of situation is (basically whenever the player is aligned to the 32x32 grid, which I have a check for and seems to be working, check to see if they’re colliding with any blocks that are touching). Right now I’m using Tiled for my levels (exported as a .json file) and all of the wall tiles have type = “wall” as an identifier.

Any ideas or explanations would be great. Just need to know what the best way to perform these checks is.

Also btw I have all of my static elements (wall, floor, etc.) with isSensor = true to avoid any physics since the mechanic I’m using needs that to happen.

Thanks.

EDIT: Also, are there better ways to format maps without using Tiled? My boards for this game are in fact relatively simple (literally just made up of the player object, the walls, the floors, and coins) and only 10x10 so I’m wondering if what I’m doing right now is just overkill

Perhaps your and (instance.isAligned) conditional check is causing some kind of filtering? I don’t see any reason in your code why collisions would be limited to just one when the player collides with two distinct “wall” objects… everything you’re doing looks essentially correct, but I think your addition of several conditional exceptions (".isAligned", comparing “other.x” to “instance.x”, etc.) is causing some limitation of the responses you’re getting back.

Brent

Hm. Tried a few things (such as remove instance.isAligned) but still have had no success. The reason I check if it’s aligned is because the player can only turn when aligned to the 32x32 grid so there seems to be no reason to check otherwise. The coord checks are also to check the position of the colliding tiles and since they too are aligned to the 32x32 grid I don’t see any reason why they would cause problems. I also then realized that the one collision it detects is the same as the player’s direction, despite the fact that I never perform any checks related to it.

EDIT: I think I’m going to try a queue table just to see if that works or not and test within the code I have to change direction

So I did some more work on this and discovered that when colliding with a corner, it’s actually detecting the following tiles:

19:50:29.287 x=304, y=144

19:50:29.287 x=304, y=112

19:50:29.287 x=304, y=80

So basically if the following is a corner with the “O” being the player and each “[]” a tile with the arrow indicating the player’s direction:

        []

–>O []

    [] []

Only collisions with the three tiles on the right are detected, not the one underneath. So now I’m completely lost as to how I can even figure out that that tile is there before the player literally goes right through it.

If it helps here’s my new code with the queue system:

[lua]local function collisionEvent(event)
  local obj1 = event.object1;
  local obj2 = event.object2;

  local other;

  if obj1.type == “player” then
   other = obj2;
  else
   other = obj1;
  end

  if (event.phase == “began”) and (instance.isAligned) and (other.type == “wall”) then

   table.insert(collidingTiles, other);
  end
 end
 
 local function frameEvent(event)  
  if instance.direction > DIR_NONE then  
   for _, v in pairs(collidingTiles) do   
    if (v.x == instance.x) and (v.y <= instance.y) then
     instance.collides[DIR_UP] = true;
    end
    
    if (v.y == instance.y) and (v.x >= instance.x) then
     instance.collides[DIR_RIGHT] = true; 
    end
    
    if (v.x == instance.x) and (v.y >= instance.y) then
     instance.collides[DIR_DOWN] = true; 
    end
    
    if (v.y == instance.y) and (v.x <= instance.x) then
     instance.collides[DIR_LEFT] = true;
    end
   end
  
   if (instance.isAligned) and (not instance.collides[instance.desiredDirection]) then
    instance.direction = instance.desiredDirection;
   end
   
   if not instance.collides[instance.direction] then
    if (instance.direction == DIR_UP) then
     instance.y = instance.y - 2;
    elseif (instance.direction == DIR_RIGHT) then
     instance.x = instance.x + 2;
    elseif (instance.direction == DIR_DOWN) then
     instance.y = instance.y + 2;
    else
     instance.x = instance.x - 2;
    end

    collidingTiles = {};

   end
  end

  if ((instance.x - 16)%32 == 0) and ((instance.y - 16)%32 == 0) then
   instance.isAligned = true;
  else
   instance.isAligned = false;
  end
 end[/lua]

Hi @danielbeer1376,

I’m a bit confused: if your walls (tiles) are static physics objects, and your player is a dynamic physics object, the player simply won’t be allowed to “pass through” the walls… unless you made the player a sensor object, walls sensor objects, or something else (which I doubt that you did).

Do you want to use some kind of in-advance detection which prevents the player from even turning in a particular direction, if there’s a wall in that direction?

It would be great to have detection in advance if that’s possible. Basically I’m making a maze game and don’t want to the player to go through the walls. And yes, right now the walls are sensors :stuck_out_tongue: since the player was shaking back and forth between the walls earlier and I couldn’t get that to stop. I have a feeling there’s a better way but I couldn’t find one. And yes, the walls are static and the player is dynamic

Hmmm… player was “shaking”? Did you set the “bounce” level of both the player and wall objects to 0?

Yes I did. It still made the player vibrate back and forth and then get stuck about 2px into the walls that were in its path. That’s why I switched to sensors originally

Hmmm… I assume then the vibrate was because you continued putting physical velocity/force on the player even after he collided with a wall?

Does your player “turn” (as in the actual object turns/rotates) to face the direction it’s going?

Right now my player is a one frame circle with no gravity and only its x and y-values being modified (+2 per frame)

OK, if the player will eventually turn to face the direction it’s travelling, I suggest another solution. It’s a tiny bit more work, but it should improve this scenario considerably. Basically, create the player as a 2-element physics body: first element is the main body (circle) and the second element is a smaller “face sensor” which emerges just a few pixels beyond the physical bounds of the player (see attached image).

This guide explains how to properly create multi-element bodies:

https://docs.coronalabs.com/guide/physics/physicsBodies/index.html#multi-element-bodies

The main body can be a non-sensor, but the smaller emerging rect part should be a sensor.

From here, basically, you use per-element collision detection according to this guide:

https://docs.coronalabs.com/guide/physics/collisionDetection/index.html#multi-element-collisions

Now when dealing with sensors overlapping something, you should use the “began” phase of the collision (on just the “face sensor” element!) to detect that point in time when it overlaps or “enters” the object it’s overlapping. Conversely, you can use the “ended” phase of the collision to detect when the face sensor has exited the wall object it’s overlapping.

These two phase aspects are critical because, during the “began” one, you will need to explicity set the player’s linear velocity to 0,0 and code some method to prevent any further application of velocity or force upon the player in the direction of the wall it’s facing.

Now, if we imagine the player has contacted a wall to its right, but there is a clear path above, then you would allow the player to turn (face) upward or something like that. At that point, the “face sensor” has exited the wall to the right, triggering an “ended” phase, which means that you’re clear to apply velocity in the new direction (up).

This probably sounds more complicated than it really is. :slight_smile: Basically, the concept is that you’re using that extra sensor element, which always “leads” in front of the direction the player is going, to detect when it hits a wall. When it does, you know that the player can’t move any further in that direction, so you stop its linear velocity and prevent any further movement in that direction. Other directions are, of course, still allowed, until the sensor contacts another wall, and then you prevent further movement in that direction.

Hope this helps somewhat,

Brent

P.S. - applying a direct linear velocity might be better (smoother looking) than moving the player by 2 pixels in each direction. You’d have to experiment to find what suits your game best.

https://docs.coronalabs.com/api/type/Body/setLinearVelocity.html

Didn’t do that exactly but the suggestion definitely got me on the right track and this is now fixed. Thanks so much

Great to hear! As usual, there’s more than one way to solve almost any issue, and my suggestion was just one. Good to hear it helped you along the way. Any other issues, please just post.

Brent

Hi @danielbeer1376,

If the walls are distinct objects, you should be getting a collision with each contact. There is a way to “average” collision points, but that’s not the default so unless you set that command somewhere by accident, you should be getting a response each time.

Brent

Yeah I’m definitely not averaging them but still can’t figure out how to make it work.

Could anyone maybe explain what the best way to check for collisions in this kind of situation is (basically whenever the player is aligned to the 32x32 grid, which I have a check for and seems to be working, check to see if they’re colliding with any blocks that are touching). Right now I’m using Tiled for my levels (exported as a .json file) and all of the wall tiles have type = “wall” as an identifier.

Any ideas or explanations would be great. Just need to know what the best way to perform these checks is.

Also btw I have all of my static elements (wall, floor, etc.) with isSensor = true to avoid any physics since the mechanic I’m using needs that to happen.

Thanks.

EDIT: Also, are there better ways to format maps without using Tiled? My boards for this game are in fact relatively simple (literally just made up of the player object, the walls, the floors, and coins) and only 10x10 so I’m wondering if what I’m doing right now is just overkill

Perhaps your and (instance.isAligned) conditional check is causing some kind of filtering? I don’t see any reason in your code why collisions would be limited to just one when the player collides with two distinct “wall” objects… everything you’re doing looks essentially correct, but I think your addition of several conditional exceptions (".isAligned", comparing “other.x” to “instance.x”, etc.) is causing some limitation of the responses you’re getting back.

Brent

Hm. Tried a few things (such as remove instance.isAligned) but still have had no success. The reason I check if it’s aligned is because the player can only turn when aligned to the 32x32 grid so there seems to be no reason to check otherwise. The coord checks are also to check the position of the colliding tiles and since they too are aligned to the 32x32 grid I don’t see any reason why they would cause problems. I also then realized that the one collision it detects is the same as the player’s direction, despite the fact that I never perform any checks related to it.

EDIT: I think I’m going to try a queue table just to see if that works or not and test within the code I have to change direction