• Advertisement
Sign in to follow this  

reaction on collision with wall

This topic is 4427 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

hello detecing collisions isn't sa hard as the reaction on them! i was thinking about collision with wall, that is not parallel to any axis. i think i would use well-known equation of straight. but how to react on the collision? i would like to do something standard reaction like in all fpp games

Share this post


Link to post
Share on other sites
Advertisement
Guest Anonymous Poster
Personally, when I walk into a wall I stop moving then double over on the floor in pain.

So for an FPS, a good reaction is to have the player stop all motion. Lose 5 health points. and stay crouching till you press the jump key to get back up.
Maybe even have a timer where you stay stunned for a few seconds before youre allowed to move again.

Share this post


Link to post
Share on other sites
Possibilities are

1) to stop the motion and shift the avatar back from where it comes until the collision doesn't exist any more; that looks like the avatar has stopped just before collision

2) like 1) but to reflect the avatar's new position over the normal of the wall; that looks like the avatar has stopped after a collision, so the happened collision will be "visible"; however, this could be interesting in corners...

3) don't stop the avatar but let it slide along the wall (if it wasn't collided just frontal); perhaps make the sliding conditional of the angle of collision, so that the avatar is stopped if run more or less frontal on a wall

4) like 3) but re-orientate the avatar along the wall in direction of the original motion

In FPSs 3) or 4) may be more senseful since the avatar remains in motion. In RPGs possibly 1) and 2) are more senseful.

You could take into account to display a collision by some "Ouch!" animation, of course.

Share this post


Link to post
Share on other sites
basic FPS response (Quake, Half Life, ect...), it's the good old reflection algorithm.

V -= (1 + CoR) * ((V . N) / (N . N)) * N

V is the velocity vector of the player
N is the normal of the wall (not necessary normalised in this example).
CoR is a scalar, and represents the coefficient of restitution (a float in range [0, 1]).
the operator '.' is a vector dot product.

It's all simple vector equations, and will make the player bounce / slide (if CoR is = 0) or get pushed hard away from a wall (think force field, CoR > 1).

Share this post


Link to post
Share on other sites
http://www.gamedev.net/reference/articles/article1832.asp

basic vector maths.

for dot product, it's simply

V . N = V.x * N.x + V.y * N.y + V.z * N.z

vector scalar operations... (k is a float)

V * k = k * V = vector(V.x * k, V.y * k, V.z * k)
V / k = V * (1 / k) = vector(V.x / k, V.y / k, V.z / k)

vector additions, subtractions

A + B = B + A = vector(A.x + B.x, A.y + B.y, A.z + B.z)
A - B = vector(A.x - B.x, A.y - B.y, A.z - B.z)
-A = vector(-A.x, -A.y, -A.z)

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Personally, when I walk into a wall I stop moving then double over on the floor in pain.

So for an FPS, a good reaction is to have the player stop all motion. Lose 5 health points. and stay crouching till you press the jump key to get back up.
Maybe even have a timer where you stay stunned for a few seconds before youre allowed to move again.
Perhaps you meant to be sarcastic, but in case you didn't: the reason no single game does what you're suggesting is that it results in horrible gameplay.

In general, realistic behavior is hardly ever fun in a game. For example, in the first Tony Hawk's Pro Skater game, we set the gravity differently in the air and on the ground to facilitate better air time and the skaters can get some insane air. With realistic gravity, the game would have been no fun at all.

Same thing with wall collision detection and reaction. No one deliberately walks into a wall in real life (perhaps unless drunk or on a dare). Thus, it's safe to assume the player didn't really mean to walk into the wall. Therefore the collision response should be such to help the player get away from the wall, i.e. letting the player slide against the wall, and perhaps also angle the player away from the wall.

You'll find that most if not all games have a lot of hacks to deal with collision reaction with walls and doorways to aid the player as much as possible.

Share this post


Link to post
Share on other sites
oliii... c'mon.. i was thinking about more complicated formulas ;) not about well-known things :D
for example i found very interesting formula on calculating the reflected vector:

rV = V - 2N * (V . N)

rV - reflected (output) vector
V - input vector
N - normal of the wall
. - dot product

but thank for link; i'll look at it

Christer: could you try to publish this book in poland? :) i would buy it with pleasure but importing foreign books to poland is horribly costly!

and i have some problem with the formula
V -= (1 + CoR) * ((V . N) / (N . N)) * N
i mean.. it works.. but.. if i want it to work correctly i have to include into calculations angle of player. maybe i do some's wrong. i would really be thankful if anyone could peek at the source http://maxest.fm.interia.pl/wall_collision.zip and tell me what should be changed. i think that my code is well organised

Share this post


Link to post
Share on other sites
it's working. you just have some logic problems, and be careful of teh operator precedence.


void Engine()
{
if (keys[VK_LEFT])
angle-=5.0f;
if (keys[VK_RIGHT])
angle+=5.0f;

if (angle<0.0f)
angle+=360.0f;
if (angle>360.0f)
angle-=360.0f;

if (keys[VK_UP])
{
player.x=+sinf(deg2rad(angle));
player.y=-cosf(deg2rad(angle));
}
if (keys[VK_DOWN])
{
player.x=-sinf(deg2rad(angle));
player.y=+cosf(deg2rad(angle));
}

if (posy<50.0f/* && (angle<90 || angle>270)*/)
{
posy = 50.0f;
float cor = 1.0f;
float j = ((player%normal)/(normal%normal));

player-= ((1.0f + cor) * j) * normal;
}

posx+=2*player.x;
posy+=2*player.y;
}

Share this post


Link to post
Share on other sites
my mistake was missing:
posy = 50.0f;

but even with this the collision is not excatly as i imagined. the "hero" twitches when it tries to cross the wall. even if cor is set on 0. BUT i found some way to eliminate twitching. that's my solution:


void Engine()
{
if (keys[VK_LEFT])
angle-=5.0f;
if (keys[VK_RIGHT])
angle+=5.0f;

if (angle<0.0f)
angle=360.0f;
if (angle>360.0f)
angle=0.0f;

if (keys[VK_UP])
{
player.x=+sinf(deg2rad(angle));
player.y=-cosf(deg2rad(angle));
}
if (keys[VK_DOWN])
{
player.x=-sinf(deg2rad(angle));
player.y=+cosf(deg2rad(angle));
}

float angle_between=45;

if (keys[VK_UP])
{
if (posy<-posx+250 && (angle<90-angle_between || angle>270-angle_between))
{
player-=(player%normal)/(normal%normal)*normal;
}
}
else
if (keys[VK_DOWN])
{
if (posy<-posx+250 && (angle>90-angle_between && angle<270-angle_between))
{
player-=(player%normal)/(normal%normal)*normal;
}
}

if (keys[VK_UP] || keys[VK_DOWN])
{
posx+=2*player.x;
posy+=2*player.y;
}
}





maybe it will beuseful to someone. but unfortunately it requires to find the angle between the wall and x-axis

for (;;)
printf("THX FOR EVERYTHING :)\n");

Share this post


Link to post
Share on other sites
really, what you ought to do is this

instead of

if (posy <= 50.0f)
{
// do the reflection code here...
}

if (posy <= 50.0f && (player % normal) < 1.0f)
{
// do the reflection code here...
}

that will work for any inclines. So, you reflect the velocity only of the player is moving TOWARDS the wall. That's what I usually do, to avoid being stuck in a collision (due to numerical innacuracies).

Share this post


Link to post
Share on other sites
another think you can do is to de-couple the direction the player is aiming, and the direction he is travelling towards. So, kinda like introducing physics, and use controls to create forces, instead of directly assigning the player's movement to the controls.

or, you can use a cor of 0.0f, avoid having the player jitter against a wall.

Really, if you want to be able to use some cool stuff like that, you should learn a bit about vector maths, planes, projections.

in your example, to collide with the top plane (n = (0, 1), y = 50), it would look like this.


// plane setup :
vector n = vector(0, 1); // normal of the plane
vector p = vector(0, 50); // arbitrary point on the plane

// player
vector pos = vector(300, 300); // position of player
vector dir = vector(0.1f, -1.0f); // direction of player

// coefficient of restitution
float cor = 0.3f;

//-----------------------------------------
// player on plane if...
// (pos - p) . n = 0
//
// if player hits the plane...
// dir -= ((1 + cor) * (dir . n) / (n . n)) * n
//-----------------------------------------
void CollideWithPlane(vector& pos, vector& dir, const vector& n, const vector& p)
{
// distance of the particle to the plane
float dist = (pos - p) % n;

// we are 'in front' of the plane. no collision
if(dist > 0.0f)
{
return;
}

// hey! we ended up behind the plane!

// direction of the impact
float delta = (dir % n);

// particle is 'entering' the plane. reflect the particle.
if (delta < 0.0f)
{
// apply impulse
dir -= ((1 + cor) * (delta / (n % n)) * n;
}

// move particle to the plane surface, 'maybe' (not always wanted behaviour).
pos -= n * dist;
}





then, you can collide with any kind of planes, provided you know their normal, and a point on the plane.

for example, say you have segment [A, B], where A = vector(10, 10), and B = vector(230, 123).

the corresponding plane will be,
vector D = B - A;
vector n = vector(-D.y, D.x); // normal of plane passing through segment [A, B]
vector p = A; // arbitrary point on plane passing through segment [A, B]

but n could also be n = vector(D.y, -D.x), depending which way you want the plane facing.

And p can also be p = B, or P = (A + B) * 0.5f (the midpoint of the segment), that will not change any results.

Share this post


Link to post
Share on other sites
whoa!
nice algorithms :)
but this:
if (posy <= 50.0f && (player % normal) < 1.0f)
works only if i replace 1.0f on 0.25f:
if (posy <= 50.0f && (player % normal) < 0.25f)

i have one more problem to solver. for example, i have some vector V=[0.71,0.71] in 2D. i need to find a vector U that is perpendicular to V. i tried some trick with cross product. i added a thitrd, helper vector W which's coords are [0,0,1]. and i think this works, but i heard that there is a way to find a perpendicular vector with dot product and not using any helper vector. how can i do that?

Share this post


Link to post
Share on other sites
To get a vector perpendicular to a 2d vector, just swap the components and negate one of them. Which to negate is up to you, but (-y,x) is common.

Share this post


Link to post
Share on other sites
Quote:

Original post by Maxest
[...]but i heard that there is a way to find a perpendicular vector with dot product and not using any helper vector. how can i do that?


Perpendicularity in arbitrary number of dimensions, is defined as the dot product of two vectors being zero.
Two vectors, of arbitrary dimension, are perpendicular if and only if their dot product is zero.

Therefore, in 2d, the vectors {x,y} and {y,-x} are perpendicular since xy-yx==0.
The same holds for {x,y} and {-y,x}

In 3d, any vector is normal to an infinite number of vectors, that all lie on the same plane. For instance, if you have the 3d vector {1,2,3}, all vectors {x,y,z} that all normal to it, must satisfy the equation
{1,2,3}.{x,y,z} = 0 <=> x+2y+3z=0
Naturally, this will be the equation of the plane that is normal to {1,2,3} and passes through the origin of the system.

Generally you can rotate any vector {x,y} by an angle phi around the origin, using the formula

{x'}= [cos(phi) -sin(phi)]*{x}
{y'} [sin(phi) cos(phi)] {y}

or

x' = cos(phi)*x - sin(phi)*y
y' = sin(phi)*x + cos(phi)*y

(note that you get {-y,x} and {y,-x} for angle pi/2 and -pi/2 respectively)

I just thought I'd mention these because they are quite useful to know

Share this post


Link to post
Share on other sites
if (posy <= 50.0f && (player % normal) < 1.0f)

that's meant to be

if (posy <= 50.0f && (player % normal) < 0.0f)

it's basically the sign of the direction compared to the wall normal. you obviously have to go 'towards' the wall to reflect the vector, else it will get weird.

Share this post


Link to post
Share on other sites
and using that algorithm I present, the step to do sphere-segment collision and response is simplified.

Share this post


Link to post
Share on other sites
geez... guys.. i don't know how to thank you for all of the alghoritms you have shown. i think i'm starting to understand what really are vectors. THX to you all!

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement