Log In  


I've struggled with collision for a long time, but I've discovered/learned two collision types that can be implemented into just about any game genre.

This is my first time writing a tutorial so please any advice or mistakes a must.

Some background:

What is an object? An object can be something as simple as you having to make a tabel/array of said thing.

And what is a tile? A tile refers to what you place down in the tile-map which is the brick icon at the top.

A flag is something you can set in the sprite creator. It's the row of 8 buttons underneath the color palette.
The reason for these buttons is for easier management of sprites, if you want to have a block that damages the player you can set a flag for that. Or in this context for a solid wall.

PROBLEMS AND SOLUTIONS OF THESE COLLISIONS WILL BE LOCATED AT THE BOTTOM

OBJECT-TO-OBJECT COLLISION

This collision type involves four to eight parameters.

  • A first X value (x1)
  • A first Y value (y1)
  • A second X value (x2)
  • A second Y value (y2)

Optionally

  • A first Width value (w1)
  • A first Height value (h1)
  • A second Width value (w2)
  • A second Height value (h2)

As you may of guessed x1, y1 is related to w1, h1,
and x2, y2 is related to w2, h2.

-- Collision error found by Soupster
function object_to_object(x1, y1, x2, y2, w1, h1, w2, h2)
 return x1 + w1 >= x2 and
        y1 + h1 >= y2 and
        x1 <= x2 + w2 and
        y1 <= y2 + h2
end

OBJECT-TO-TILE COLLISION

This collision type involves two to three parameters.

  • A X value (x)
  • A Y value (y)

Optionally

  • A Flag value (flag)
function object_to_tile(x, y, flag)
 local x1 = x / 8
 local y1 = y / 8
 local x2 = (x + 7) / 8
 local y2 = (y + 7) / 8

 return fget(mget(x1, y1), flag) or 
        fget(mget(x1, y2), flag) or 
        fget(mget(x2, y2), flag) or 
        fget(mget(x2, y1), flag)
end

What's next?

After you made one of these collisions go into the _update() function or a function that's connected to the _update() and make two local variables.

local lastX = object.x
local lastY = object.y

After this make an if statement and call the collision function and enter the parameters.

if myCollision(/* parameters */) then

end

Once you're done with this all you need to do is just call the object.x and equal it to the lastX.
And object.y is equaled with lastY.

if myCollision(/* parameters */) then
 object.x = lastX
 object.y = lastY
end

Problems and Solutions

If you've made these collisions, you may notice that when colliding with a block, and you continue to hold the key that is putting the player in the direction of the block, try pressing left or right, up or down. You may notice that you're unable to move until you let go of the key putting you into that predicament. This can really mess up flow of the players, so how do we fix it? All you need to do is separate the collision function into two.

So for example:

This is object-to-object collision without the extra parameters:

if myCollision(object.x, lastY, object1.x, object1.y) then
 object.x = lastX
end

if myCollision(lastX, object.y, object1.x, object1.y) then
 object.y = lastY
end

Warning: Do not put lastX or lastY for every parameter that mentions X or Y only do it with the object that has the movement code i.e the player

This is object-to-tile collision:

if myCollision(object.x, lastY) then
 object.x = lastX
end

if myCollision(lastX, object.y) then
 object.y = lastY
end

The top warning does not apply to object-to-tile collsion

1


I think you made an error in your object to object collision (a.k.a AABB, axis aligned bounding box collision), x2 + w2 >= x2 and y2 + h2 >= y2 will always evaluate to true.

This should work better:

function object_to_object(x1, y1, x2, y2, w1, h1, w2, h2)
 return x1 + w1 >= x2 and
        y1 + h1 >= y2 and
        x1 <= x2 + w2 and
        y1 <= y2 + h2
end

Oh sorry you're right, based off further testing somehow the one I typed up also works but that is the more formal way which I will be changing.


1

This is good enough if your movement is grid-based or if your objects have a maximum speed of 1 pixel. However, most games I've seen don't use those limitations. If you just place the object at its last x and y position on collision without those limitations, then you may run into issues. The main one that comes to mind is a character falling in a platformer, where a maximum fall speed above 1 would stop the object from hitting the ground

If you're going to use that simple of collision detection, I would recommend adding a loop for each axis to move the object 1 pixel at a time (or 1 cell size in the case of grid-based movement that allows more than 1 cell for speed) until the object is actually touching the thing that is in the way.

Also, it'd be good to mention that when doing object to object collisions, the width and height should be 1 less than the width and height of the sprites used for those objects.

There's a couple other common cases that might be difficult with these methods, but those are more in-depth than this tutorial merits I guess. Instead, the last thing I think would be good to mention is that using the map for tile-based collisions isn't always a good idea. That ties the level geometry to the visuals which can often be a hindrance. It also makes it so the game's grid must be a specific size and must use a specific portion of the engine's memory. In those cases using either a 2d table or a flat table with 2d-array indexing to store the relevant information works better.


There are multiple work arounds when using a method such as storing the last position, it works good not just for grid-based games or moving at one pixel per frame. I'm using both of these collision examples in my actual game and they work beautifully. My game also runs at 60 FPS with physics, and is a platformer. These collisions honestly depend on how computationally expensive your program is. I am also completely aware that there are issues with these collision types, but if you're just making a platformer all the way to a ray-caster, you should be completely fine.



[Please log in to post a comment]