Advertisement

Trouble with 2D collisions

Started by November 06, 2014 06:21 PM
5 comments, last by lightxbulb 10 years, 2 months ago

Hello, I am programming a 2D tile based platformer game and I am having trouble with the collisions. First, here is how I am planning to make them:

1. Update the position of everything

2. Detect Collisions

3. Adjust the collisions

4. Draw & Display

Example:

1415297844-collision.png

I am fine with the collision detecting, there are tutorials all around internet about that, but they don't explain what to do after. So here is my problem: how do you adjust the position of an element that is colliding with another one ?

Thanks.

(If I am not clear enough and that you are having trouble understanding what I am asking, don't hesitate to ask)

Initially position the character in a non-collision state (position). Following that, a very simplistic approach is, during update, move the character to a temporary position, and test for collision at that temporary position. If there is a collision, don't move the character (i.e., do not update the position). If there is no collision, set the character's position to the temporary position. Continue. That approach ensures the character is always in a non-collision state.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

Advertisement
I am fine with the collision detecting, there are tutorials all around internet about that, but they don't explain what to do after.

Because it depends on what you want to happen after that. The effect most people are looking for is probably just to stop right before "entering" the object. Or you could be sliding along the object (more common). Basically if you have your movement vector v, you can alter it so that you do not enter the object. Example: sphere to box. Let's say that you move towards the box and hit it at some point (let the box be aligned with the main axes) by moving (Vx,0,Vz). If the box is exactly in front of you, you should alter your vector, so you do not enter the box - the easiest is to remove the Vz component, or somehow even add some part of it to Vx. And here's where the collision normals come into play. Let's say you collide into a triangle. This triangle has a normal facing out of it - what you could do is remove all contribution from your movement vector in the opposite direction of the normal. That is done by new_V = V + n*dot(-n,V)/(length(n)) (unless I m writing bs tongue.png - happens pretty often to me).

Or you could make it so you bounce off the triangle - new_V = 2*(n*dot(n,-V)/length(n))-V

P.S. Seems I did write some bs yesterday - fixed - the new_V should be correct now.

Edit: Everything I said for 3d apart the triangle part can be applied to 2d(the triangle was just an example) - sphere and box translate directly to circle and rectangle. On the other hand I fail to see anything that complicated in my post (maybe it's just me - in which case I apologize) - I tried my best to write all the math so it would be ready for use "right out of the box"(I wrote it so it would be helpful to me, and I deem myself a beginner). I suppose you're using vectors to move things around in the scene - so when you move an object and you get a collision, if you want a sliding result you can alter your movement vector to: new_V = V + n*dot(-n,V)/(length(n)), if you want a bouncing result you can alter your vector to: new_V = 2*(n*dot(n,-V)/length(n))-V. Try as I might I cannot simplify bouncing and sliding effects any more (which are the results you most often get when you collide in games).

I am fine with the collision detecting, there are tutorials all around internet about that, but they don't explain what to do after.

Because it depends on what you want to happen after that. The effect most people are looking for is probably just to stop right before "entering" the object. Or you could be sliding along the object (more common). Basically if you have your movement vector v, you can alter it so that you do not enter the object. Example: sphere to box. Let's say that you move towards the box and hit it at some point (let the box be aligned with the main axes) by moving (Vx,0,Vz). If the box is exactly in front of you, you should alter your vector, so you do not enter the box - the easiest is to remove the Vz component, or somehow even add some part of it to Vx. And here's where the collision normals come into play. Let's say you collide into a triangle. This triangle has a normal facing out of it - what you could do is remove all contribution from your movement vector in the opposite direction of the normal. That is done by new_V = V + n*dot(-n,V)/(length(n)) (unless I m writing bs tongue.png - happens pretty often to me).

Or you could make it so you bounce off the triangle - new_V = 2*(n*dot(n,-V)/length(n))-V

P.S. Seems I did write some bs yesterday - fixed - the new_V should be correct now.

This is not a very helpful response IMO. The OP is asking for a 2D solution for a tile based game, and the OP is asking in a beginner's forum. You're response is for 3D objects (sphere and box), and covering subjects that are going to be way over his head.

Unless prompted, in the "For Beginner's", I suggest following the KISS principle (Keep It Simple Stupid).

OP, I would follow what Buckeye suggested. Move your objects, then test for collision. In fact, to help determine which direction the collision occurred, I would suggest moving along each axis and checking collisions, and just revert the axis movement if collision occurs.

This allows you to do things like jump and slide up against a wall, instead of just stopping all movement (vertical and horizontal) if you're jumping up and right, and hit a wall on the right.

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

To add to BeerNutts' answer ( I think that's the proper grammar for the possessive form of BeerNutts ;) ), a great many physics engines actually do this in all at once.

Often there will be something like checkCollide(obj1,obj2, onCollideCallback, testCollideCallback), where the callback testCollideCallback will evaluate if a collision occurs or not, so as part of the evaluation of HOW to move, it determines IF to move.


What Sir Nutts said is bang on, the only exception you need to watch out for is "Moving Very Very Fast Syndrome"(tm). In which you are moving very very fast, to the point that when you perform your test you've actually already passed THROUGH the object you should have collided in. That said, if you arent moving very very fast, it's not an issue you have to deal with yet, and when you do have to deal with it, it's not entirely difficult, just another layer of complication.

What you're talking about is collision resolution(or response) a topic that can have as many "what should I do!" answers as detecting collisions in the first place.

In a generic sense it kinda depends what you're colliding with, if we take a simplistic 2d example like a game like super mario, most of the time you'll be colliding with terrain. Terrain for instance would center around trying to "nudge" the character back out of the collision and be colliding correctly with a wall, this becomes a lot more visible in 3d games if you've ever seen something like a prop or a ragdoll get partially caught in a wall, they might bounce around in a spazzy way because the engine can't figure out how to get it out of the wall.

In 2d its usually just square bounding boxes and you basically want to determine which side the sprite intersected the other on and move it away in that direction until its free of the obstruction.

Of course going back to the mario example if you collide with something like an enemy you may not want to move the character back at all, you might want the collision to damage mario and put him in invincibility frames for a short time. There isn't really a one size fits all solution. Physics engines are generally just concerned with pushing objects back out of each other if they collide and then you can tag on extra code to handle specific game logic related to collisions.

Advertisement

I don't know if you've got this part down, but I'll explain it just in case. Before getting to sliding and bouncing, maybe I should have started with stopping exactly at the point of collision. Here's a circle to circle implementation(vectors are in bold):

Say you have two circles, one of them is moving(let's call it circle1 and the non-moving one circle2) - let circle1 have coordinates p = (p0x,p0y) and radius r1 and let it's movement vector have coordinates m = (mx,my) - then if we translate circle1 by this vector it will have coordinates p1=(p1x,p1y), where p1x = p0x+mx and p1y = p0y + my, now let the second circle have coordinates q = (q0x, q0y) and radius r2. I won't go through the mathematical derivation - if you want it though, just say.

Let's say circle1 and circle2 are not in a state of collision. What we need to find is where circle1 needs to be after the movement vector is applied. If it doesn't collide with circle2 it will just be translated by the movement vector, however if it does collide we need to find where it should be in that case.

Let:


A = dot((p1-p0),(p1-p0)) = (p1x-p0x)*(p1x-p0x) + (p1y-p0y)*(p1y-p0y)
B = dot((p0-q),(p1-p0)) =  (p0x-qx)*(p1x-p0x) + (p0y-qy)*(p1y-p0y)
C = dot((p0-q),(p0-q)) - (r1+r2)*(r1+r2) = (p0x-qx)*(p0x-qx) + (p0y-qy)*(p0y-qy) - (r1+r2)*(r1+r2)
D = B*B - A*C

If D<0 then there is no collision and you just translate circle1 with m without a care in the world.

If D>=0 then here's how we calculate our answer:


t1 = -(B + sqrt(D))/A

And if 0<= t1 and t1<=1 then there's a collision, otherwise there is no collision and we can just translate circle1 with m without a care in the world.

In the case there is a collision, the new coordinates of your circle when it collides would be:


newX = p0x + mx*t1
newY = p0y + mz*t1

To illustrate all of this I've made a little program (I hope it doesn't crash on your PC), w,a,s,d to move the camera, left mouse button to choose where you want to move the sphere, space to actually start moving the sphere:

http://www.mediafire.com/download/oouhkxydcw91d2w/ss_coll.7z

P.S. "Moving Very Very Fast Syndrome"™ doesn't apply in this case, because the solution is analytical and not iterative.

After you are in a state of collision you can apply sliding for example so you won't enter the object(if you are not in a state of collision do not apply sliding or you'll get an effect you don't really want), but just slide on it (the normal of circle2 at the point of collisions would be n = (nx,ny), where nx = (newX - qx)/sqrt((newX - qx)*(newX - qx) + (newY - qy)* (newY - qy)), ny = (newY - qy)/sqrt((newX - qx)*(newX - qx) + (newY - qy)* (newY - qy)) .

Also, in the case you are testing for collision against many objects - get the smallest t1.

Another thing to note is that you can optimize collisions a lot by just ignoring all the objects that are at a distance > length(m)+r1+r2 (r2 being the radius of the object you're currently looking whether to perform collisions tests on). Even faster would be the case of squared distance, or even a rectangle with sides length(m)+r1+r2. But these are optimizations so you can disregard them for now, I'm just saying it so you would know there are possibilities for optimizations.

P.S. If you want something simpler, you need to give more specifics about how you handle physics in your platformer - for example how you handle movement, because what I wrote is a really general case that should work in pretty much all 2d cases, while I believe that this could be really simplified depending on the restrictions imposed by the fact that it's a tile based platformer.

This topic is closed to new replies.

Advertisement