Confused about circle colisions

Started by
8 comments, last by kzar 18 years, 8 months ago
Hi again, in my game I need circles to bounce off each other. I have printed off http://www.gamedev.net/community/forums/topic.asp?topic_id=334112 and http://freespace.virgin.net/hugo.elias/models to read at lunch today and I tried to understand it but was still lost. One of the main things I don't understand is how you can have the velocity as a single variable when surely you need a x velocity and a y velocity? (Same with distance) Also I didn't understand how it didnt include pie surely without it, it would just check for squares? Anyway if someone knows a simpler explanation to help me understand it would be really handy. Thanks, David
Advertisement
I always found Gamasutra's article entitled Pool Hall Lessons a wonderful source for learning circle-circle collisions. Ever read it before?

Velocity is both speed and direction. I don't know what exactly you are referring to, but it might be possible that the author used speed and velocity interchangeably -- a common mistake unfortunately. As for including pi (you meant pi, not pie, right?), it's not necessary unless you are working with angles. Vector math is sufficient here.
....[size="1"]Brent Gunning
These values are probably 2D vectors. Of course, they contain individual x and y coordinates.
Quote:Original post by skittleo
I always found Gamasutra's article entitled Pool Hall Lessons a wonderful source for learning circle-circle collisions. Ever read it before?

Velocity is both speed and direction. I don't know what exactly you are referring to, but it might be possible that the author used speed and velocity interchangeably -- a common mistake unfortunately. As for including pi (you meant pi, not pie, right?), it's not necessary unless you are working with angles. Vector math is sufficient here.


Thanks I have set that to print :) (yes I ment pi, oops!)
I am getting closer but I still don't understand what the articles meen by normalise, and their example code always just uses some function to normalise without showing you how to do it.

edit: Seems you divide the x and y by the length so does this look good?

void normalize(float *x_vol, float *y_vol){    float x_vol_squared, y_vol_squared, length;       x_vol_squared = (*x_vol * *x_vol);    y_vol_squared = (*y_vol * *y_vol);    length = x_vol_squared + y_vol_squared;    *x_vol = x_vol_squared / length;    *y_vol = y_vol_squared / length;}




[Edited by - kzar on August 14, 2005 7:12:05 AM]
Well I still don't totaly understand the article but I tried to implement it to the point that theres a moving ball and a still one, and when the moving ball crashes into the still one it should stop it moving. Unfortunately it seems to only stop it moving when the ball is totaly covered by the other one.

I am a bit stuck as to why this happens as I'm still trying to understand some of the maths, so if someone could have a quick look it would be really handy. Here is the relevant code so far:

/* Object Structure */struct Sball{    float x_pos, y_pos;    float x_pos_center, y_pos_center;    float x_vol, y_vol;    int radius;};    struct Sball ball;struct Sball ball2;void game_loop(){    /* Update Time stuff */    last_time = current_time;    current_time = SDL_GetTicks();    time_passed = current_time - last_time;        get_input();        if (collision_check() == false)        move_balls();    draw_background();    draw_balls();        /* Refresh the screen */    SDL_Flip( screen );    }bool collision_check(){    float movement_vector;    float normalised_x_vol, normalised_y_vol;    float x_distance, y_distance;    float radius_sum, dotproduct;    float F, T;    float distance, minimum_travel_distance;        ball.x_pos_center = ball.x_pos + ball.radius;    ball.y_pos_center = ball.y_pos + ball.radius;        ball2.x_pos_center = ball2.x_pos + ball.radius;    ball2.y_pos_center = ball2.y_pos + ball.radius;        /* Find the distance (squared) between the two circles */    x_distance = ball.x_pos_center - ball2.x_pos_center;    y_distance = ball.y_pos_center - ball2.y_pos_center;    distance = (x_distance * x_distance + y_distance * y_distance);        /* Find the magnitude of the traveled vector (squared) */    movement_vector = (ball.x_vol * ball.x_vol + ball.y_vol * ball.y_vol);            /* Find the normalised movement vector */    normalised_x_vol = ball.x_vol;    normalised_y_vol = ball.y_vol;    normalise(&normalised_x_vol, &normalised_y_vol);        /* Find the length of the two radius's (squared) */    radius_sum = (ball.radius + ball2.radius) * (ball.radius + ball2.radius);        /* Get the dotproduct of the distance and volocity */    dotproduct = (x_distance * normalised_x_vol + y_distance * normalised_y_vol);        /* Quick check to rule out collision */    if ((distance - radius_sum) > movement_vector)        return false;        /* Another quick check to rule out collision */    if (dotproduct <= 0)        return false;        F = (distance * distance) - (dotproduct * dotproduct);        /* Another quick check */    if (F >= radius_sum)        return false;        T = radius_sum - F;        /* Another check */    if (T < 0)        return false;            minimum_travel_distance = dotproduct - sqrt(T);        /* One last check */    if (minimum_travel_distance > distance)        return false;        /* Move the ball to just touch */    ball.x_pos_center += (normalised_x_vol * minimum_travel_distance);    ball.y_pos_center += (normalised_y_vol * minimum_travel_distance);    ball.x_pos = ball.x_pos_center - ball.radius;    ball.y_pos = ball.y_pos_center - ball.radius;        ball.x_vol = 0;    ball.y_vol = 0;    return true;}void move_balls(){        ball.x_pos += (ball.x_vol * time_passed * DELTA);    ball.y_pos += (ball.y_vol * time_passed * DELTA);}void normalise(float *x_vol, float *y_vol){    float x_vol_squared, y_vol_squared, length;       x_vol_squared = (*x_vol * *x_vol);    y_vol_squared = (*y_vol * *y_vol);    length = x_vol_squared + y_vol_squared;    *x_vol = x_vol_squared / length;    *y_vol = y_vol_squared / length;}


I think the problem is in the collision function but I included some other stuff incase you needed it. Thanks, David
Quote:Original post by kzar
Well I still don't totaly understand the article but I tried to implement it to the point that theres a moving ball and a still one, and when the moving ball crashes into the still one it should stop it moving. Unfortunately it seems to only stop it moving when the ball is totaly covered by the other one.


Er, yes, that's what's supposed to happen. (In particular, the squarer the impact, the less velocity retained by the first ball.)
It is supposed to appear to stop the ball at the edge other one, not once they totaly overlap.

Also, does anyone the difference between C and dist in the gamasutra article?

Thanks

[Edited by - kzar on August 14, 2005 12:46:30 PM]
fixed one bug, I squared distance when assigning F even though it was already squared. Now the collision seems to work sometimes but sometimes the ball suddenly vanishes! :o

bool collision_check(){    float movement_vector;    float normalised_x_vol, normalised_y_vol;    float x_distance, y_distance;    float radius_sum, dotproduct;    float F, T;    float distance, minimum_travel_distance;        ball.x_pos_center = ball.x_pos + ball.radius;    ball.y_pos_center = ball.y_pos + ball.radius;        ball2.x_pos_center = ball2.x_pos + ball.radius;    ball2.y_pos_center = ball2.y_pos + ball.radius;        /* Find the distance (squared) between the two circles */    x_distance = ball.x_pos_center - ball2.x_pos_center;    y_distance = ball.y_pos_center - ball2.y_pos_center;    distance = (x_distance * x_distance + y_distance * y_distance);        /* Find the magnitude of the traveled vector (squared) */    movement_vector = (ball.x_vol * ball.x_vol + ball.y_vol * ball.y_vol);            /* Find the normalised movement vector */    normalised_x_vol = ball.x_vol;    normalised_y_vol = ball.y_vol;    normalise(&normalised_x_vol, &normalised_y_vol);        /* Find the length of the two radius's (squared) */    radius_sum = (ball.radius + ball2.radius) * (ball.radius + ball2.radius);        /* Get the dotproduct of the distance and volocity */    dotproduct = (x_distance * normalised_x_vol + y_distance * normalised_y_vol);        /* Quick check to rule out collision */    if ((distance - radius_sum) > movement_vector)        return false;        /* Another quick check to rule out collision */    if (dotproduct <= 0)        return false;        F = distance - (dotproduct * dotproduct);        /* Another quick check */    if (F >= radius_sum)        return false;        T = radius_sum - F;        /* Another check */    if (T < 0)        return false;            minimum_travel_distance = dotproduct - sqrt(T);        /* One last check */    if (minimum_travel_distance > distance)        return false;        /* Move the ball to just touch */    ball.x_pos_center += (normalised_x_vol * minimum_travel_distance);    ball.y_pos_center += (normalised_y_vol * minimum_travel_distance);    ball.x_pos = ball.x_pos_center - ball.radius;    ball.y_pos = ball.y_pos_center - ball.radius;        ball.x_vol = 0;    ball.y_vol = 0;    return true;}


Edit: There seem to be two bugs, the first one is that collision detection only works against one half of the stationary circle. If I then change the distance code the other half of the collision detection works instead. What I meen is that with

x_distance = ball2.x_pos_center - ball.x_pos_center;
y_distance = ball2.y_pos_center - ball.y_pos_center;

the moving ball only "hits" the top and left side of the stationary circle but with

x_distance = ball.x_pos_center - ball2.x_pos_center;
y_distance = ball.y_pos_center - ball2.y_pos_center;

it only hits the bottom and right side of the still circle.

Also I have noticed that with the first the moving ball gets stuck just touching the still circle but with the second it kind of bounces back away. It bounces back further depending on how fast the ball is going.

[Edited by - kzar on August 14, 2005 2:36:03 PM]
I fixed the only working for half of the circle stuff by adding this code to get rid of any minus signs:

if (x_distance <= -1)
x_distance *= -1;
if (y_distance <= -1)
y_distance *= -1;

but the bug which makes it get stuck when hitting the top and left side of the still circle but bouncing away when hitting the bottom and right side of the circle hasn't gone away.

edit: just fixed the normalise function but its actualy made it worse, no idea why but its doing more wierd stuff like getting stuck. anyway here it is:

void normalise(float *x_vol, float *y_vol){    float length;        length = sqrt((*x_vol * *x_vol) + (*y_vol * *y_vol));    *x_vol /= length;    *y_vol /= length;}


[Edited by - kzar on August 14, 2005 4:29:22 PM]

This topic is closed to new replies.

Advertisement