views:

284

answers:

8

I'm working on a 2D Platform game, and I was wondering what's the best (performance-wise) way to implement Surface (Collision) Detection.

So far I'm thinking of constructing a list of level objects constructed of a list of lines, and I draw tiles along the lines.

alt text

I'm thinking every object holds the ID of the surface that he walks on, in order to easily manipulate his y position while walking up/downhill.

Something like this:

//Player/MovableObject class
MoveLeft()
{
    this.Position.Y = Helper.GetSurfaceById(this.SurfaceId).GetYWhenXIs(this.Position.X)
}

So the logic I use to detect "droping/walking on surface" is a simple point (player's lower legs)-touches-line (surface) check (with some safety approximation - let`s say 1-2 pixels over the line).

Is this approach OK? I`ve been having difficulty trying to find reading material for this problem, so feel free to drop links/advice.

A: 

You can try to use one of physics engines, like Box2D or Chipmunk. They have own advanced collision detection systems and a lot of different bonuses. Of course they don't accelerate your game, but they are suitable for most of games on any modern devices

Tiendil
+1  A: 

Check out how it is done in the XNA's Platformer Starter Kit Project. Basically, the tiles have enum for determining if the tile is passable, impassable etc, then on your level you GetBounds of the tiles and then check for intersections with the player and determine what to do.

Mike
Thanks Mike , will get on it. I'm curious as how it handles objects that are rotated.
GamiShini
A: 

It is not that easy to create your own collision detection algorithm. One easy example of a difficulty is: what if your character is moving at a high enough velocity that between two frames it will travel from one side of a line to the other? Then your algorithm won't have had time to run in between, and a collision will never be detected.

I would agree with Tiendil: use a library!

Jordan Lewis
w00t? You check if the two object intersects and not if object bounds 'collides' with the other one.
Mike
If the objects are traveling fast enough that their per-frame velocity is greater than their width, then to your naive collision detection algorithm, there will never have been a collision.
Jordan Lewis
+1 Agreed it's very challenging to do right. I had a small project that involved cars traveling down lanes in a highway, and even in the limited case of only needing to check the position of the cars one ahead and one behind in the same lane and the next lane when a car wanted to change lanes, there were countless hard to debug errors that only showed up occasionally in very specific circumstances. I haven't looked at any of these libraries personally, but if I were to develop a proper collision detection system, I'd absolutely at least peruse existing libraries first.
dimo414
well, in this case, you are right. Sorry I didn't understood your answer the first time... BTW. What about calculation the vectors the object moves?
Mike
Perhaps checking if the line formed of the former and current position , intersects with the surface line + direction of moving is downward. Then the fall is stopped and the object begins standing on the surface.
GamiShini
"at a high enough velocity that between two frames it will travel from one side of a line to the other" Then use SOLID SHAPES instead of lines. It is hard to tunnel through a box, you know.Guys, excuse me but it is TWO DIMENSIONS. You are making problem look more difficult that it is. If you can't handle 2D collision engine, then game development is not for you.
SigTerm
SigTerm - huh? this is still a problem. Say you have two solid 2x2 boxes. Say they are travelling toward each other at 10 units per frame, and start off one unit apart. Then assuming a naive implementation that the poster would most likely use, i.e. new_position = old_position + velocity, the simulation won't detect a collision because there won't be one. If this isn't hard enough for you, imagine two complex shapes that just clip through each other on the top or bottom in this situation. It is nontrivial.
Jordan Lewis
+1  A: 

I've had wonderful fun times dealing with 2D collision detection. What seems like a simple problem can easily become a nightmare if you do not plan it out in advance.

The best way to do this in a OO-sense would be to make a generic object, e.g. classMapObject. This has a position coordinate and slope. From this, you can extend it to include other shapes, etc.

From that, let's work with collisions with a Solid object. Assuming just a block, say 32x32, you can hit it from the left, right, top and bottom. Or, depending on how you code, hit it from the top and from the left at the same time. So how do you determine which way the character should go? For instance, if the character hits the block from the top, to stand on, coded incorrectly you might inadvertently push the character off to the side instead.

So, what should you do? What I did for my 2D game, I looked at the person's prior positioning before deciding how to react to the collision. If the character's Y position + Height is above the block and moving west, then I would check for the top collision first and then the left collision. However, if the Character's Y position + height is below the top of the block, I would check the left collision.

Now let's say you have a block that has incline. The block is 32 pixels wide, 32 pixels tall at x=32, 0 pixels tall at x=0. With this, you MUST assume that the character can only hit and collide with this block from the top to stand on. With this block, you can return a FALSE collision if it is a left/right/bottom collision, but if it is a collision from the top, you can state that if the character is at X=0, return collision point Y=0. If X=16, Y=16 etc.

Of course, this is all relative. You'll be checking against multiple blocks, so what you should do is store all of the possible changes into the character's direction into a temporary variable. So, if the character overlaps a block by 5 in the X direction, subtract 5 from that variable. Accumulate all of the possible changes in the X and Y direction, apply them to the character's current position, and reset them to 0 for the next frame.

Good luck. I could provide more samples later, but I'm on my Mac (my code is on a WinPC) This is the same type of collision detection used in classic Mega Man games IIRC. Here's a video of this in action too : http://www.youtube.com/watch?v=uKQM8vCNUTM

Jeffrey Kern
A: 

I'd recommend Farseer Physics. It's a great and powerful physics engine that should be able to take care of anything you need!

RCIX
Thanks RCIX , But IMO it`s too much for what i`m trying to achieve.
GamiShini
+4  A: 

Having worked with polygon-based 2D platformers for a long time, let me give you some advice:

Make a tile-based platformer.

Now, to directly answer your question about collision-detection:

You need to make your world geometry "solid" (you can get away with making your player object a point, but making it solid is better). By "solid" I mean - you need to detect if the player object is intersecting your world geometry.

I've tried "does the player cross the edge of this world geometry" and in practice is doesn't work (even though it might seem to work on paper - floating point precision issues will not be your only problem).

There are lots of instructions online on how to do intersection tests between various shapes. If you're just starting out I recommend using Axis-Aligned Bounding Boxes (AABBs).

It is much, much, much, much, much easier to make a tile-based platformer than one with arbitrary geometry. So start with tiles, detect intersections with AABBs, and then once you get that working you can add other shapes (such as slopes).

Once you detect an intersection, you have to perform collision response. Again a tile-based platformer is easiest - just move the player just outside the tile that was collided with (do you move above it, or to the side? - it will depend on the collision - I will leave how to do this is an exercise).

(PS: you can get terrific results with just square tiles - look at Knytt Stories, for example.)

Andrew Russell
A: 
SigTerm
A: 

I have used a limited collision detection approach that worked on very different basis so I'll throw it out here in case it helps:

A secondary image that's black and white. Impassible pixels are white. Construct a mask of the character that's simply any pixels currently set. To evaluate a prospective move read the pixels of that mask from the secondary image and see if a white one comes back.

To detect collisions with other objects use the same sort of approach but instead of booleans use enough depth to cover all possible objects. Draw each object to the secondary entirely in the "color" of it's object number. When you read through the mask and get a non-zero pixel the "color" is the object number you hit.

This resolves all possible collisions in O(n) time rather than the O(n^2) of calculating interactions.

Loren Pechtel