The Collider Class.
Last week I worked on the collider class. Mostly I worked on the class’ overlap methods. Each object in the game that’s capable of colliding with something has its own collider as a member.
It is the Collider that determines the actual position of the object it is a member of.
The Collider has a position in the form of a pair of coordinates on the x-axis and the y-axis. The Collider also has a pair of values that determines how far from the position coordinates it extends along both axes.
Example, if the Collider is a box and has the coordinates (x: 100, y: 100), then that position is the upper left corner of the box.
If it extends 50 units on both axis, in other words have the extension (x: 50, y: 50), then:
The upper right corner of the box is (x: 150, y: 100).
The lower right corner of the box is (x: 150, y: 150).
The lower left corner of the box is (x: 100, y: 150).
The extension is increased on both axes because in SFML the coordinate system is:
Right = +X, Left = -X, Up = -Y, Down = +Y.
However if the Collider is a circle things look a bit different. Then you first need to determine the center of the Collider circle. This is done by adding half of the values of the extensions to the position.
You will then get the central point of a Collider that has the form of a circle. The circle will be just big enough to fit into a box that is defined from the Colliders’ position and extension.
Then you will need to determine a radius for the circle to determine how big it is. This can either be done by just assigning a value to a member variable for the Collider. Alternatively, it can be defined by taking the extension on one axis and divide it by 2.
Which type of Collider shape you choose should depend on the object it is bound to. For example, in out game the view if top down, so people should have circle Colliders. People may not be shaped as circles when viewed from above, but a circle is certainly closer than a box.
The Collider class does not only have a position and a shape though, it also has methods for checking if it overlaps with other Colliders.
I choose to divide this into three different methods to make it easier to work with.
One for Box vs Box overlap.
One of Circle vs Circle overlap.
One for Circle vs Box overlap.
I also added a member value to the Collider class call “ColliderCircle”, which is a Boolean, meaning it can only have the values “true” or “false”.
This value is set depending on what object the Collider is a member of. For example, if the Collider belongs to the player then I want it to have the shape of a circle, so the “ColliderCircle” is set to “true”. If I want the Collider to be a box, I set the “ColliderCircle” to false;
When the game then checks for collisions it will call on the Colliders “ColliderCircle”.
If two Colliders give “false” when calling the “ColliderCircle” then the Box vs Box overlap method is used to check if the two objects overlap.
If they both return “true” however, the Circle vs Circle overlap method is used and if they return different values (one true and one false) then then Circle vs Box overlap method is used.
I started with the Box vs Box overlap and the Circle vs Circle overlap because I had done methods for that before while I only had a conceptual idea on how to make the box vs circle collision. The box vs circle overlap was therefore postponed.
The following image is the code for the circle vs circle overlap:
The overlap methods I made did not just check for overlap however, but also returned an offset. The offset is a set of values (x and y) that show how much and in which direction a collided objects position needs to be adjusted on collision.
I will illustrate the reason why this is needed with an example:
Say two box-shaped Colliders are positioned so that one of them is only two pixels to the right of the other.
The first box is then moved to the left by 5 pixels in the next game loop while the second box stays still.
The first box is now overlapping 3 pixels into the second box; therefore its position needs to be adjusted by three pixels (5-2) to the right, because the objects are not supposed to go into each other. The offset in this situation is (3, 0).
In order to get the right offset on overlap I needed the program to first check if the overlap was largest on the x-axis or the y-axis.
If the overlap is larger on the x-axis the correction of position will happen on the y-axis and vice versa.
Once that is established I will need to check if the offset is going to be positive or negative.
In this situation the red square has a higher value on its x-position and therefore its offset will have a positive x-value.
In this situation the opposite holds true.
In this situation the offset for the red square will have a negative y-value because it needs to be moved up to correct its position.
The point of doing all this to return an offset value is that once it is done you only need to add the offset value to the position to get a proper correction.
I did, however, run into some problems with this method. As it turns out though, the problem was that instead of comparing position to position when the offset was determined I accidentally made the overlap method compare the objects position with the other objects extension, which meant that the offset always had the same value. This meant that no matter which side an object collided from it was offset downwards.
Like this:
Once I had finally sorted this out the circle vs circle overlap method worked properly but not the box vs box. I then decided to scrap box vs box and box vs circle overlap because we really only needed those for one object in the game and that object was non-essential, so all our Colliders will be circles.
The offset on the circle vs circle overlap works fine except for edge cases (when edge collide with edge, see below) where the objects vibrate somewhat against one another.
This is probably due to the computers calculation of float values (values with a decimal) being somewhat uncertain so the offset might be calculated inaccurately by a pixel or so every loop.