Simple collision detection for sidescroller

Started by
10 comments, last by Zakwayda 17 years, 4 months ago
Ive been working for awhile on a sidescroller and I was wondering what is the best way to do collision detection. I'm using C# with Managed DirectX, my game is pretty simple. I have a Sprite class, Tiles are just Rectangles and are organized into a List<Tile> variable for a level. I have a static class Collision which has some collision functions. Currently I just have a function SpriteSpriteCollision(Sprite s1, sprite s2) which returns a Direction (ie. the direction that s1 is in terms of s2). My code checks if the SpriteOldRectangle of s1 is on the left, top, right or bottom of s2 and returns a Direction based on that. Of couse I check if the 2 sprites are colliding first. Now I'm not sure if my way of doing the collision detection is right, in fact im sure there is a better way to do it. Also with my way the collision response doesn't work well most of the time. Can someone explain to me the best way to do collision detection (and respose) in a sidescroller game. note i dont want pixel accurate collision detection (at least not yet :) ). Thanks
Advertisement
SAT (separating axis theorem) with MTD (minimum translation distance/vector) would probably work well for this (it would give natural 'sliding' collision response, among other things).

It sounds a little complicated, but for AABBs it's actually quite simple and reduces to just a few lines of code.

You could google using the above terms, but it'd probably be just as easy to figure it out yourself. Draw two overlapping AABBs in any configuration, and then ask the question, what is the shortest distance and (axis-aligned) direction I can move one of the boxes so that the intersection is resolved? This is essentially the question you have to answer (in code, of course) to implement the algorithm.
Like this?

www.sirisian.templarian.com/flash/flashplatform.swf
(click on it and arrow keys)

I wrote it in flash in about 5 minutes for a friend... here's the source, it's C-Syntax shouldn't take long to convert it.

For some reason I used two iterations for the hitdetection. You can easily turn it into one iteration. Here are the simple variables.
this.velocityX is object's velocity for X
this.velocityY is object's velocity for Y
this.vx is the x coord for object
this.vy is the y coord for object
object in this case was a unit. use a nested for loop for iteration through two arrays of objects.
This does what JYK is saying all you have to do is optimize it.
this.vx += this.velocityX;		for (var wallItr = 0; wallItr<wallArray.length; ++wallItr) {			if (this.vx<wallArray[wallItr].vx+wallArray[wallItr].vwidth) {				if (this.vx+this.vwidth>wallArray[wallItr].vx) {					if (this.vy<wallArray[wallItr].vy+wallArray[wallItr].vheight) {						if (this.vy+this.vheight>wallArray[wallItr].vy) {							if (this.velocityX<0) {								this.vx = wallArray[wallItr].vx+wallArray[wallItr].vwidth;								this.velocityX = 0;							} else if (this.velocityX>0) {								this.vx = wallArray[wallItr].vx-this.vwidth;								this.velocityX = 0;							}						}					}				}			}		}		this.vy += this.velocityY;		for (var wallItr = 0; wallItr<wallArray.length; ++wallItr) {			if (this.vx<wallArray[wallItr].vx+wallArray[wallItr].vwidth) {				if (this.vx+this.vwidth>wallArray[wallItr].vx) {					if (this.vy<wallArray[wallItr].vy+wallArray[wallItr].vheight) {						if (this.vy+this.vheight>wallArray[wallItr].vy) {							if (this.velocityY<0) {								this.vy = wallArray[wallItr].vy+wallArray[wallItr].vheight;								this.velocityY = 0;							} else if (this.velocityY>0) {								this.vy = wallArray[wallItr].vy-this.vheight;								this.velocityY = 0;								this.HitGround();							}						}					}				}			}		}
I understand Sirisian's method and I just wrote up a quick GDI test and it works like a charm. I have read on SAT and I dont know if it would be smart to use it in a sidescroller. You think its worth learning and implementing it into a sidescroller?
thanks
it's not very hard, but it depends what you need. For square tiles, it would be very easy. It's basically like doing a ray vs a box intersection test.

Everything is better with Metal.

What is the advantage of using SAT method vs Normal method (the one that Sirisian used)?
Quote:Original post by Diirewolf
I have read on SAT and I dont know if it would be smart to use it in a sidescroller.
Why not? The SAT is perfectly suited for collision detection between convex polygonal objects in 2D (which includes AABBs).

Anyway, the code of Sirisian's that you're using is an SAT test, so the question of whether the SAT is appropriate for this context is pretty much moot :)
Quote:Original post by Diirewolf
What is the advantage of using SAT method vs Normal method (the one that Sirisian used)?
As noted above, Sirisian is using the SAT.
oh thank god it worked... I just tore it out and figured it did something right. I learned SAT like 5 months ago. The MTD still confuses me to no end with convex polygons. Except with AABB it's rather obvious.

Optimize my code though, I'm just glad it worked.

here's an unoptimized SAT for two AABB boxes given x,y,w,h
if(object1.x < object2.x+object2.w && object1.x+object1.w > object2.x && object1.y < object2.y+object2.h && object1.y+object1.h > object2.y){//They are hitting}

that code is good for doing preliminary quick checks with high vertex convex polygons.
The way i'm doing it now is simple SAT only rectangles:

public enum Direction { None, Left, Top, Right, Bottom }

public static class Collision{

public static bool RectsAreColliding(Rectangle r1, Rectangle, r2)
{
return (!((r1.Right < r2.Left) || (r1.Left > r2.Right) || (r1.Bottom < r2.Top) || (r1.Top > r2.Bottom)));
}

public static Direction SpriteRectXCollision(Sprite sprite, Rectangle rect/*probably a tile*/)
{
if (!RectsAreColliding(sprite.SpriteRectangle, rect))
{
return Direction.None;
}

if (sprite.VelocityX > 0)
{
return Direction.Right;
}
else if (sprite.VelocityX < 0)
{
return Direction.Left;
}

return Direction.None;
}

public static Direction SpriteRectYCollision(Sprite sprite, Rectangle rect/*probably a tile*/)
{
if (!RectsAreColliding(sprite.SpriteRectangle, rect))
{
return Direction.None;
}

if (sprite.VelocityY > 0)
{
return Direction.Bottom;
}
else if (sprite.VelocityY < 0)
{
return Direction.Top;
}

return Direction.None;
}

}

Pretty optimized I think and it works perfectly.

This topic is closed to new replies.

Advertisement