Jump to content
  • Advertisement
Sign in to follow this  
kzar

Problem with my sdl code

This topic is 4836 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

My program should move a ball around and if it collides with the stationary ball it stops. I got it to work except one problem, the time_passed variable seems to be 0 in the collision check function but not in the move_balls function. This meens that if I add a check to return false if theres time_passed <= 0 the move_balls function still moves it and the balls overlap, but if i dont have that check it trys to square root 0 in the collision check stuff and everything goes tits up. I suspect its a problem with mixing floats, #defines and Uint32s but I'm not sure.

/* 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;

Uint32 current_time, last_time, time_passed;

bool collision_check()
{
    float movement_x, movement_y, movement_length, movement_length_squared;
    float normalised_movement_x, normalised_movement_y;
    float distance_x, distance_y, distance_length, distance_length_squared;
    float radius1, radius2, radius_sum, radius_sum_squared;
    float dotproduct, dotproduct_squared;
    float fred, bob, bob_squared, minimum_movement_length;
    
    /* Quick check */
    if (time_passed <= 0)
        return false;
        
    radius1 = ball.radius;
    radius2 = ball2.radius;
    
    radius_sum = radius1 + radius2;
    radius_sum_squared = radius_sum * radius_sum;
    
    movement_x = ball.x_vol * time_passed * DELTA;
    movement_y = ball.y_vol * time_passed * DELTA;
    movement_length_squared = (movement_x * movement_x) + (movement_y * movement_y);
    movement_length = sqrt(movement_length_squared);
    
    normalised_movement_x = movement_x / movement_length;
    normalised_movement_y = movement_y / movement_length;
    
    distance_x = ball.x_pos - ball2.x_pos;
    distance_y = ball.y_pos - ball2.y_pos;
    distance_length_squared = (distance_x * distance_x) + (distance_y * distance_y);
    distance_length = sqrt(distance_length_squared);
    
    /* Quick Check */
    if ((distance_length - radius_sum) > movement_length)
        return false;
    
    dotproduct = (normalised_movement_x * distance_x) + (normalised_movement_y * distance_y);
    dotproduct_squared = dotproduct * dotproduct;
    
    /* Quick Check */
    if (dotproduct <= 0)
        return false;
    
    fred = sqrt(distance_length_squared - dotproduct_squared);
    
    /* Quick check */
    if (fred >= radius_sum)
        return false;    
    
    bob_squared = radius_sum_squared - (fred * fred);
    
    if (bob_squared < 0)
        return false;
    
    bob = sqrt(bob_squared);
    
    minimum_movement_length = dotproduct - bob;
    
    if (minimum_movement_length > movement_length)
        return false;
    
    ball.x_pos += (normalised_movement_x * minimum_movement_length);
    ball.y_pos += (normalised_movement_y * minimum_movement_length);
    /*ball.x_vol = 0;
    ball.y_vol = 0;*/
    
    printf("ball.x_vol: %1.0f, ball.y_vol: %1.0f, time_passed: %d, movement_x: %1.0f, movement_y: %1.0f\n", ball.x_vol, ball.y_vol, time_passed, movement_x, movement_y);
    return true;
}

void move_balls()
{       
    ball.x_pos += (ball.x_vol * time_passed * DELTA);
    ball.y_pos += (ball.y_vol * time_passed * DELTA);
}


Share this post


Link to post
Share on other sites
Advertisement
The "time_passed" variable is modified somewhere in the program where it shouldn't. Check all the places where it is modified between the calls to your two functions, and make sure that what you want to happen actually happens.

Share this post


Link to post
Share on other sites
In the init code current_time is set to SDL_GetTicks() and this is how its updated in the game loop.


void game_loop()
{
/* Update Time stuff */
last_time = current_time;
current_time = SDL_GetTicks();
time_passed = current_time - last_time;

printf("Time_passed: %d\n", time_passed);

get_input();

if (collision_check() == false)
move_balls();

draw_background();
draw_balls();

/* Refresh the screen */
SDL_Flip( screen );
}

Share this post


Link to post
Share on other sites
It really depends on how you're setting the time_passed variable.

Something with low precision like GetTickCount() will give you zero sometimes, BUT, in the long run it will give just about the correct amount of time that's gone by.

This means your balls will appear to move correctly, even if in some frames time_passed is zero, thus screwing up the collision checking.

The method you're using currently (with the quick check) should be fine, or you could use a higher precision counter like QueryPerformanceCounter that will be less likely to give you zero time passed.

Edit: I see from your reply you're using SDL_GetTicks(), and I'm not sure exactly how that works, but you could still see if there are any other options.

Share this post


Link to post
Share on other sites
Quote:
Original post by bjle
It really depends on how you're setting the time_passed variable.

Something with low precision like GetTickCount() will give you zero sometimes, BUT, in the long run it will give just about the correct amount of time that's gone by.

This means your balls will appear to move correctly, even if in some frames time_passed is zero, thus screwing up the collision checking.

The method you're using currently (with the quick check) should be fine, or you could use a higher precision counter like QueryPerformanceCounter that will be less likely to give you zero time passed.

Edit: I see from your reply you're using SDL_GetTicks(), and I'm not sure exactly how that works, but you could still see if there are any other options.


Thats the problem though, with the quick check it then goes to move_balls which seems to move it even though time_passed must be 0 and hence shouldn't move it at all :o

Share this post


Link to post
Share on other sites
That's weird, if you're sure that it is skipping collision and moving the balls at the same frame. (Well, I guess you'd know, if they go through each other!)

What are you using to compile this? You can usually step through your code line-by-line, and watch variables. That would be the next thing I'd try in your situation.

Share this post


Link to post
Share on other sites
Think I see the problem, If i dont set the x and y vol to 0 then it will carry on into the ball. If I do set it to 0, the next check will square root 0 and mess up. Let me just make sure this is the problem, one moment!

edit: Yeah that fixed the disapearing ball.


bool collision_check()
{
float movement_x, movement_y, movement_length, movement_length_squared;
float normalised_movement_x, normalised_movement_y;
float distance_x, distance_y, distance_length, distance_length_squared;
float radius1, radius2, radius_sum, radius_sum_squared;
float dotproduct, dotproduct_squared;
float fred, bob, bob_squared, minimum_movement_length;

movement_x = ball.x_vol * time_passed * DELTA;
movement_y = ball.y_vol * time_passed * DELTA;

/* Quick check (no movement so no collision)*/
if ((time_passed <= 0.0) || ((movement_x == 0) && (movement_y == 0)))
return false;

movement_length_squared = (movement_x * movement_x) + (movement_y * movement_y);
movement_length = sqrt(movement_length_squared);

normalised_movement_x = movement_x / movement_length;
normalised_movement_y = movement_y / movement_length;

radius1 = ball.radius;
radius2 = ball2.radius;

radius_sum = radius1 + radius2;
radius_sum_squared = radius_sum * radius_sum;



distance_x = ball.x_pos - ball2.x_pos;
distance_y = ball.y_pos - ball2.y_pos;
distance_length_squared = (distance_x * distance_x) + (distance_y * distance_y);
distance_length = sqrt(distance_length_squared);

/* Quick Check */
if ((distance_length - radius_sum) > movement_length)
return false;

dotproduct = (normalised_movement_x * distance_x) + (normalised_movement_y * distance_y);
dotproduct_squared = dotproduct * dotproduct;

/* Quick Check */
if (dotproduct <= 0)
return false;

fred = sqrt(distance_length_squared - dotproduct_squared);

/* Quick check */
if (fred >= radius_sum)
return false;

bob_squared = radius_sum_squared - (fred * fred);

if (bob_squared < 0)
return false;

bob = sqrt(bob_squared);

minimum_movement_length = dotproduct - bob;

if (minimum_movement_length > movement_length)
return false;

ball.x_pos += (normalised_movement_x * minimum_movement_length);
ball.y_pos += (normalised_movement_y * minimum_movement_length);
ball.x_vol = 0;
ball.y_vol = 0;

printf("ball.x_vol: %1.0f, ball.y_vol: %1.0f, time_passed: %d, movement_x: %f, movement_y: %f\n", ball.x_vol, ball.y_vol, time_passed, movement_x, movement_y);
return true;
}



Problem is now that when the circle should hit the other one, it carries on untill its hit the oposite edge, and then gets flipped back to the outside of the circle. Then it kind of gets stuck on the other ball, if I move my mouse in the other direction it thinks its coming from the other way and flips it back over to the other side. :(

[Edited by - kzar on August 18, 2005 7:34:45 AM]

Share this post


Link to post
Share on other sites
After alot of hacking about I have found that my program works perfectly if I just invert the dotproduct. Ovbiously this is a hack though so I was wondering if anyone could point out how I should have calculated the dotproduct in the first place? Thanks


bool collision_check()
{
float movement_x, movement_y, movement_length, movement_length_squared;
float normalised_movement_x, normalised_movement_y;
float distance_x, distance_y, distance_length, distance_length_squared;
float radius1, radius2, radius_sum, radius_sum_squared;
float dotproduct, dotproduct_squared;
float fred, bob, bob_squared, minimum_movement_length;

movement_x = ball.x_vol * time_passed * DELTA;
movement_y = ball.y_vol * time_passed * DELTA;

/* Quick check (no movement so no collision)*/
if ((time_passed <= 0.0) || ((movement_x == 0) && (movement_y == 0)))
return false;

movement_length_squared = (movement_x * movement_x) + (movement_y * movement_y);
movement_length = sqrt(movement_length_squared);

normalised_movement_x = movement_x / movement_length;
normalised_movement_y = movement_y / movement_length;

radius1 = ball.radius;
radius2 = ball2.radius;

radius_sum = radius1 + radius2;
radius_sum_squared = radius_sum * radius_sum;

distance_x = ball.x_pos - ball2.x_pos;
distance_y = ball.y_pos - ball2.y_pos;
distance_length_squared = (distance_x * distance_x) + (distance_y * distance_y);
distance_length = sqrt(distance_length_squared);

/* Quick Check */
if ((distance_length - radius_sum) > movement_length)
return false;

dotproduct = (normalised_movement_x * distance_x + normalised_movement_y * distance_y);
dotproduct *= -1;
dotproduct_squared = dotproduct * dotproduct;

/* Quick Check */
if (dotproduct <= 0)
return false;

fred = sqrt(distance_length_squared - dotproduct_squared);

/* Quick check */
if (fred >= radius_sum)
return false;

bob_squared = radius_sum_squared - (fred * fred);

if (bob_squared < 0)
return false;

bob = sqrt(bob_squared);

minimum_movement_length = dotproduct - bob;

if (minimum_movement_length > movement_length)
return false;

ball.x_pos += (normalised_movement_x * minimum_movement_length);
ball.y_pos += (normalised_movement_y * minimum_movement_length);
ball.x_vol = 0;
ball.y_vol = 0;

return true;
}

Share this post


Link to post
Share on other sites
Say ball1 is heading toward ball2 from the left.

When you find distance, you take ball1.x - ball2.x, which will be negative. However, ball1 is moving in the positive x direction. So your dot product will be negative when ball1 is moving towards ball2, which is the opposite of what you want.

Probably the best way to fix it is just make distance ball2-ball1, rather than the other way around.

Share this post


Link to post
Share on other sites
Quote:
Original post by bjle
Say ball1 is heading toward ball2 from the left.

When you find distance, you take ball1.x - ball2.x, which will be negative. However, ball1 is moving in the positive x direction. So your dot product will be negative when ball1 is moving towards ball2, which is the opposite of what you want.

Probably the best way to fix it is just make distance ball2-ball1, rather than the other way around.


That fixed it, thanks.

Share this post


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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!