I’m having problems with code that I’ve come up with to detect if the player hits a wall. Currently, I’ve got it set that if the wall and the player collide, it sets the horizontal movement to 0. But then, when i go to move away from the wall, I can’t because I’m still colliding with the wall and the horizontal movement gets set to 0. What do you guys do for wall collisions?
I tend to calculate how far into the wall the player hitbox is on the x axis, then displace it by the negative of that amount instantly, so it never appears inside the wall.
I then repeat this for the y axis, after the x position has been corrected.
I find that this gives the cleanest collisions, that stay working regardless of the framerate in a variable timestep environment. (so long as the framerate isn’t so low that the player can skip right across it)
- The next sprite position gets calculated but not yet applied.
- The calculated position is handed over to the almighty collision master.
- In case of a free way, the sprite is moved.
- In case of collision, movement is cleared, no need to correct any position here.
Collision check points depends on the current heading, there are eight points overall.
If the position delta is too large, the distance is broken into multiple collision checks to prevent wall tunneling.
Additional hints to 65K’s:
- Test collision in both x-y first and if it is OK to move, go ahead
- If not, test collision in the x-direction only (and then y-direction only if it fails). With this extra test, you don’t get the problem that you get stuck if you move diagonally and collide.
Surely this would cause the player to appear to collide with an invisible shield surrounding the wall, because the player would never be able to get close enough to touch it. While at high framerates it probably not be noticeable, at lower framerates or higher speeds, this would look a bit odd to the player…
I spent weeks making a collision/physics system (though it’s mostly collision)
if player is moving right
- check if player’s destination collides with anything
– if true, snap player just short of the collision - if false
– just move the player
etc
This method won’t work if you move faster than the width of the collidable object (that’s a whole other problem…)
I like Ciaran54’s solution the best so far. Minosa’s has the problem that if the object is very close to begin with and is moving very fast, it will seem to have suddenly (momentarily) lost its velocity as the move gets cut short at the wall rather than rebounding.
I have to confess, I’ve tended to use 65k’s method (easier to code)–but I haven’t done anything particularly critical.
An idea I want to try for 2d collision detection is to “draw” object movements like brush strokes (The canvas being a byte buffer, and the “color” the object’s id), then “cut” out the walls from the canvas and see where the stroke ends, or where it crosses other strokes.
It’s a visually interesting idea that might end up being a resource hog (specially when dealing with several moving objects colliding with each other), though, but at least it should help with static wall collisions.
I just make a detection box around the player (just a box around the player that’s a bit wider and taller on all 4 sides) -
when the detection box collides into the wall you stop - so there’s ~1 pixel space (hacky solution, you probably shouldn’t use this)
1 pixel is unnoticeable, anyways…
Regarding your sticky wall issue, you need to find out the wall’s “normal”, that is, the vector it uses to push back against the player, and use it to only nullify the movement components that push it, not the rest.
As a conceptual example, in an axis-aligned environment (All walls are 90º from each other, as if drawn on an square grid) where +X is right and +Y is up, a right facing wall would nullify -X movement, but not the rest.
In the following off the top of my head code, colliding with the wall sets the appropriate isColliding* flag to true based on the orientation of the wall, so when the player attempts to move:
void movePlayer(int newXvelocity, int newYvelocity)
{
if( (newXvelocity > 0 && isCollidingRight()) || (newXvelocity < 0 && isCollidingLeft()) )
{
playerXvelocity = 0;
} else
{
playerXvelocity = newXvelocity;
}
if( (newYvelocity > 0 && isCollidingUp()) || (newYvelocity < 0 && isCollidingDown()) )
{
playerYvelocity = 0;
} else
{
playerYvelocity = newYvelocity;
}
}
You should really take a look at vector arithmetic, though, specially if you don’t want axis-aligned walls.