Hi.
I figure there must be a few well established ways to go about this, but some research turned up nothing that I needed. I'm trying to make a game in c# using XNA, but this part is generic enough to be the same in just about any language, and I want to make collision detection work so that an Actor (class with a Rectangle for it's collision box and a Vector2 for it's velocity) can't pass through a block that is kept in a 2d array.
So I looked up how to do this, and it seemed simple enough. Ended up with the following code.
Code:
internal virtual void Collide(Actor actor, int x, int y)
{
Rectangle collideBox = new Rectangle(x * GameConstants.BlockSize, y * GameConstants.BlockSize, GameConstants.BlockSize, GameConstants.BlockSize);
if (actor.FutureLocation.Intersects(collideBox))
{
if (actor.Location.Right <= collideBox.Left)
{
leftCollide(actor, collideBox);
}
if (actor.Location.Left >= collideBox.Right)
{
rightCollide(actor, collideBox);
}
if (actor.Location.Bottom <= collideBox.Top)
{
topCollide(actor, collideBox);
}
if (actor.Location.Top >= collideBox.Bottom)
{
bottemCollide(actor, collideBox);
}
}
}
protected virtual void leftCollide(Actor actor, Rectangle collideBox)
{
actor.SpeedX = collideBox.Left - actor.Location.Right;
}
protected virtual void rightCollide(Actor actor, Rectangle collideBox)
{
actor.SpeedX = collideBox.Right - actor.Location.Left;
}
protected virtual void topCollide(Actor actor, Rectangle collideBox)
{
actor.SpeedY = collideBox.Top - actor.Location.Bottom;
}
protected virtual void bottemCollide(Actor actor, Rectangle collideBox)
{
actor.SpeedY = collideBox.Bottom - actor.Location.Top;
}
The block needs an x and y coord because its location is dictated by it's index in the array held by a level, unlike an actor that stores it's own location.
actor.Location is an XNA rectangle that represents the actors collision box.
actor.FutureLocationis an XNA rectangle that represents where the actor is trying to move to.
If there is anything else that needs to be cleared up, just ask.
I made separate functions for each type of collision (Top, bottom, left and right) so that other classes that extend block can override these functions for other effects, E.G. if I made a class called platform that overrides leftCollide, rightCollide and bottemCollide with empty functions, then you would be able to jump through platforms and then land on them.
Now the problem here is that although the actor will collide with a box, it can not 'slide' along the side of one. If you are trying to go left, the gravity is pulling you down, then the future location will be down and to the left, and collides with a box, so you will collide with the ground and not be able to move left, when it should only be blocked going down.
I think that to solve this problem, I need to figure out what the actor collides with first, the top/bottem or the sides. Right now it knows if there is a collision, but doesn't know the cause. For example.

Red square: The actor's location.
Pink square: The actor's future location.
Blue Square: The block that the actor is colliding with.
Green Square: Where the actor
should be if it hits the top first.
Orange square: Where the actor would be if it hit the left side first.
So in the above example, because it collides with the top (As shown by the black arrow intersecting the top) Velocity initial Y (ViY should be set to Velocity final Y (VfY) and Velocity initial X should remain unchanged.\
Instead, it is doing both collisions for green and orange and setting both ViY and ViX to VfY and VfX respectively.
Anybody have any idea how I would fix this? I need to find what side the actor collides with, but don't know how to do that.
Code dump would be truly awesome, but an explanation or link to an article would be legendary.
