SFML community forums

Help => Graphics => Topic started by: Cadisol87 on February 26, 2014, 09:30:13 pm

Title: [Beginner] Help with fixed Timestep
Post by: Cadisol87 on February 26, 2014, 09:30:13 pm
Here am I again! :)

So here's my second question that I have (If you don't know of what I'm talking about, see here (http://en.sfml-dev.org/forums/index.php?topic=14286.0))

So my problem is, that sometimes the circles are bouncing in the window and hit another circle, they "glitch" and stick to each other. So I got a possible solution from Golden Eagle, he said that I should read this (http://gafferongames.com/game-physics/fix-your-timestep/) Article, so I read it and tried to understand it.

So, I assume that what I have to do is to save the state of the program , and if the 'accummulator' is bigger than the delta time, set the old state before collision to the new, and then adjust the time?( I hope you can understand what I'm trying to say with my bad english ;)  ) Please correct my if I'm wrong!

But would that method be efficient? Because while the game is 'lagging' I have to update the game, which would be very complicated if you have a look at my code... And it wouldn't be good for the performance to save a lot of states in the loop...

Does anybody have an idea how to solve this more efficiently, without re-writing nearly all my code?
(Maybe I just misunderstood the article.. :) )

Any help is appreciated!

Title: Re: [Beginner] Help with fixed delta time
Post by: Hapax on February 28, 2014, 12:38:25 am
I assume that what I have to do is to save the state of the program
I believe that "state" as used in that article refers to the current state of the objects. e.g. current positions and velocities.

Also, if you're using fixed delta time, you don't need an accumulator.
Title: Re: [Beginner] Help with fixed Timestep
Post by: Cadisol87 on February 28, 2014, 04:16:52 pm
I believe that "state" as used in that article refers to the current state of the objects. e.g. current positions and velocities.
Yes, I know. Sorry for the confusion, I meant the state of the objects, not of the program.

Also, if you're using fixed delta time, you don't need an accumulator.

And again, Sorry... I meant the last examle at the Article under the heading "The final touch"
Title: Re: [Beginner] Help with fixed Timestep
Post by: Hapax on February 28, 2014, 08:28:14 pm
I believe that "state" as used in that article refers to the current state of the objects. e.g. current positions and velocities.
Yes, I know. Sorry for the confusion, I meant the state of the objects, not of the program.
Then, you'll just need the variables that you store those details. It'd be better practice to store them as objects of a class, but it's not necessary.

Also, if you're using fixed delta time, you don't need an accumulator.
And again, Sorry... I meant the last examle at the Article under the heading "The final touch"
You're separating the physics? I doubt that'll be necessary for a simple circle bouncing animation that will be running on your own computer. The first fixed delta should easily suffice. However, learning those techniques will indeed be useful overall. I must admit that I didn't get as far as separating them in the practice game I was doing when reading that and have not needed it since (yet).
If you do end up going for that, storing everything as objects should make it easier.
Title: Re: [Beginner] Help with fixed Timestep
Post by: Cadisol87 on February 28, 2014, 11:33:39 pm
The first fixed delta should easily suffice.

I tried it, but it still glitches... I used 1/60th of a second and VSYNC turned on, fraps shows me 60 FPS.

Maybe my update loop doesn't take less than one frame?
Title: Re: [Beginner] Help with fixed Timestep
Post by: Jesper Juhl on March 01, 2014, 03:10:38 am
Stop just trying random things.
Read up on maths.
Read up on physics.
Read up on C++.
Seriously; the problems you are having are not hard. Do your basic research.
Title: Re: [Beginner] Help with fixed Timestep
Post by: Hapax on March 01, 2014, 11:55:02 am
The source you provided seems to work quite well. They only seem to glitch when they start on top of each other. They should be all in their own space initially.
Title: Re: [Beginner] Help with fixed Timestep
Post by: Cadisol87 on March 01, 2014, 02:02:28 pm
The source you provided seems to work quite well. They only seem to glitch when they start on top of each other. They should be all in their own space initially.

Well that's weird! I don't see any glitches as well now... 
But im 100 percent sure that it glitched when I opened the thread :o

Is it pure coincidence? I still believe that there must be something wrong with the timestep.

(Updated code as attachment)

Title: Re: [Beginner] Help with fixed Timestep
Post by: Cadisol87 on March 01, 2014, 09:36:26 pm
Yep, problem is still there, sometimes it glitches :(

BTW, I implemented three new features:

-Add circles with the left mouse button at the cursor position ( Not fully completed, creates circles even if it will overlap another circle)

-Remove circles with the right mouse button
-Clear all circles with space
Title: Re: [Beginner] Help with fixed Timestep
Post by: Nexus on March 02, 2014, 11:37:18 am
Please stop attaching source files and follow the rules stated here (http://en.sfml-dev.org/forums/index.php?topic=5559.msg36368#msg36368). Instead of adding more features that further complicate the code and make it more difficult for everyone to find the original problem, you should reduce your code as much as possible.
Title: Re: [Beginner] Help with fixed Timestep
Post by: Cadisol87 on March 02, 2014, 03:36:35 pm
Please stop attaching source files and follow the rules stated here (http://en.sfml-dev.org/forums/index.php?topic=5559.msg36368#msg36368). Instead of adding more features that further complicate the code and make it more difficult for everyone to find the original problem, you should reduce your code as much as possible.

Okay, I reduced the code:
// #include...

int width =  GetSystemMetrics(SM_CXSCREEN); // Get the Screen-Width
int height =  GetSystemMetrics(SM_CYSCREEN); //Get the Screen-Height
int ballradius = 50;
int mass = ballradius;
int ballcount = 10;


// ... some functions ...


int main()

{

//...

    vector <sf::CircleShape> Ball(10);
    for(int i = 0; i < ballcount; i++  )
    {
        Ball[i].setRadius(ballradius);
        Ball[i].setPointCount(100);
        Ball[i].setFillColor(sf::Color(rgb(engine) ,rgb(engine)  ,rgb(engine)));
        Ball[i].setOutlineThickness(0);
        Ball[i].setOutlineColor(sf::Color(88, 97, 97));
        Ball[i].setPosition( i * 140 , i * 70);
    }

    sf::Clock clock;

    sf::ContextSettings settings;
    settings.antialiasingLevel = 8;

    sf::RenderWindow window(sf::VideoMode(width, height), "Bouncing Balls", sf::Style::Fullscreen, settings);

    window.setVerticalSyncEnabled(true);
    window.setMouseCursorVisible(true);

    while (window.isOpen())
    {

        //...event handling...

        auto dt = clock.restart().asSeconds();
        window.clear(sf::Color::White);
        for(int i = 0; i < ballcount; i++  )

        {
            Ball[i].move(xSpeed[i] * dt, ySpeed[i] * dt );

        }

        for(int i = 0; i < ballcount; i++  )
        {
            window.draw(Ball[i]);
        }

        window.display();

//...Checking and handling Wall-Collisions here...

//Here's the ball to ball collision detection and handling code:
        for (int i = 0; i < ballcount; i++)
        {
            for (int j = i + 1; j < ballcount; j++)
            {
                if (Collision(Ball[i].getPosition(), Ball[j].getPosition()))
                {

                    sf::Vector2f v1(xSpeed[i], ySpeed[i]);
                    sf::Vector2f v2(xSpeed[j], ySpeed[j]);

                    sf::Vector2f n = Ball[i].getPosition() - Ball[j].getPosition();
                    n = Normalize(n);

                    float a1 = dotProduct(v1, n);
                    float a2 = dotProduct(v2, n);
                    float optimizedP = (2.0 * (a1 - a2)) / (mass + mass);

                    v1 = v1 - optimizedP * mass * n;
                    v2 = v2 + optimizedP * mass * n;

                    xSpeed[i] = v1.x;
                    ySpeed[i] = v1.y;

                    xSpeed[j] = v2.x;
                    ySpeed[j] = v2.y;


                    Ball[i].move(xSpeed[i] * dt, ySpeed[i] * dt);
                    Ball[j].move(xSpeed[j] * dt, ySpeed[j] * dt);

                }
            }
        }
    }
    return 0;
}
 

I hope the code is more readable now! :)
If you want to compile it, just download the code from the post I made before.
Title: Re: [Beginner] Help with fixed Timestep
Post by: Cadisol87 on March 03, 2014, 01:39:53 pm
Yesterday I bought the SFML Game Development book, and I don't regret that I've done it :)

So, In the book there also is an Article about fixed time steps. I put the event handling, the rendering and the updating of the game into voids (but I didn't make a game class like in the book) and implemented the timestep-code from here. (https://github.com/SFML/SFML-Game-Development-Book/blob/master/01_Intro/Source/Game.cpp)

But it still glitches, and sometimes you see some micro-lags.

So what did I do wrong?
Title: Re: [Beginner] Help with fixed Timestep
Post by: Cadisol87 on March 04, 2014, 10:59:36 pm
Does somebody have an idea? Because the timestep shouldn't be the problem anymore.

Here's my loop:
while (window.isOpen())
    {

        sf::Time elapsedTime = clock.restart();
        timeSinceLastUpdate += elapsedTime;
        while (timeSinceLastUpdate > TimePerFrame)
                {
                        timeSinceLastUpdate -= TimePerFrame;

                        processEvents();
                        update(TimePerFrame);
                }

            render();


    }
 

I did implement it like it's shown in the code-example. Or did I do something wrong? I really don't know how to solve this problem...  :(
Title: Re: [Beginner] Help with fixed Timestep
Post by: zsbzsb on March 05, 2014, 02:34:34 am
Well your time step is correct, but since I'm not sure why you are having so much trouble with bouncing circles I decided to write an example. I wrote it in C#, but it is very easily ported to C++. Currently when circles collide they receive a new angle from a random generator. However if you wish, feel free add an algorithm that properly calculates the reflection angle. And I also used my NetEXT library, but all the classes that I used from it are available in Thor (http://www.bromeon.ch/thor).

You can find the source here (https://bitbucket.org/zsbzsb/bouncing-circles/src). The entire code is less than 200 lines in length and all resides in the "Program.cs" file. Oh and I commented it so you should have no issue following it. I have tested it with extremely high speeds and never have never had the circles stick to each other.  :)

All in all, it took me about 1 hour to do.  ;D

On a side note, looking at your code it seems as if the sticking problem stems from the fact that you move your circles before checking for collision, you should do collision with the new position first and then move if nothing is colliding with the new
position. ;)

(http://i.imgur.com/xtMzb11.png)
Title: Re: [Beginner] Help with fixed Timestep
Post by: Cadisol87 on March 05, 2014, 08:03:27 pm
Wow zsbzsb, thank you! I really appreciate your help and work!  :)
 
But I (as always  ::) ) have a little question:
On a side note, looking at your code it seems as if the sticking problem stems from the fact that you move your circles before checking for collision, you should do collision with the new position first and then move if nothing is colliding with the new
position. ;)

So you mean I should check if the circles collide if I would move them, and if they don't; move them. Or did I misunderstand you?
Title: Re: [Beginner] Help with fixed Timestep
Post by: zsbzsb on March 05, 2014, 08:12:43 pm
Yes that is what I meant. Check the for collisions against the new position, then if any collisions happen you can change the angle of the circle, else no collisions happened just move the circle to the new position. To keep it simple if a collision occurs don't bother trying to move the circle again in that physics update.  ;)
Title: Re: [Beginner] Help with fixed Timestep
Post by: Cadisol87 on March 05, 2014, 11:24:02 pm
Okay, so now my calculate-collisions part of my code looks like this:
for (int i = 0; i < ballcount; i++)
{
    for (int j = i + 1; j < ballcount; j++)
    {
        sf::Vector2f newPosI(xSpeed[i] * dt.asSeconds(), ySpeed[i] * dt.asSeconds());
        sf::Vector2f newPosJ(xSpeed[j] * dt.asSeconds(), ySpeed[j] * dt.asSeconds());

        if (Collision(Ball[i].getPosition() + newPosI , Ball[j].getPosition() + newPosJ))
        {
            //Calculate and set the new Velocities
            haveCollided = true;
        }
        else haveCollided = false;

    }
}
if(!haveCollided)
{
    for(int i = 0; i < ballcount; i++  )

    {
        Ball[i].move(xSpeed[i] * dt.asSeconds(), ySpeed[i] * dt.asSeconds() );

    }
}
 

And this seems to work quite well!
I hope I did everything right, didn't I? :)

Now I'm going to spend one hour watching bouncing circles bounce around my screen and see if the circles still stick together sometimes  ;D
Title: Re: [Beginner] Help with fixed Timestep
Post by: zsbzsb on March 06, 2014, 02:37:20 am
Don't stop all movement just because one circle collided. Check my logic (https://bitbucket.org/zsbzsb/bouncing-circles/src/85695b64a1df996a1b22ecce5fe738dccc1f2d7c/BouncingCircles/Program.cs?at=master#cl-73) and see how it is done.

Only do collision detection for a single circle at a time using only that single circles new position. If that single circle's new position collides with any of the other circle's old position then simply don't move that single circle.

else haveCollided = false;

Don't set it to false, it should already start with a value of false outside your inner loop (but still inside your outer loop  :)). And if a collision happens within your inner loop call break to avoid checking for any other collision.

for (int j = i + 1; j < ballcount; j++)

You inner loop still needs to loop over every single circle, not just the circles that come after the one that collision is currently being preformed on. Just add a single check inside the inner loop to avoid checking for collision against the same circle. A simple if (i == j) continue; will work (same as in my code).  ;)


On a side note, if you hop on IRC (http://en.sfml-dev.org/forums/index.php?topic=2997.0) I would be glad to help get you straightened out (with this or any other problems).  ;D
Title: Re: [Beginner] Help with fixed Timestep
Post by: Cadisol87 on March 06, 2014, 03:36:37 pm
Thanks zsbzsb!

Problem is finally solved  :)