2
\$\begingroup\$

Is this the right way, or at least a way that works, for dealing with accelerations in variable time steps evironments?

    // Pseudo-code
    void onUpdate() {
        mySpeed += acceleration * timeElapsed; // More specifically, this part
        myPosition += mySpeed * timeElapsed;
    }

Truth to be said, I'm using a constant timeElapsed defined by (1.0f / FPS_LIMIT), FPS_LIMIT being the value of the framerate at which I want the game to be locked. Speeds and accelerations are defined in the following ways:

    #define FRAME_DURATION (1.0f / FPS_LIMIT)

    #define RUNNING_SPEED 42 * FRAME_DURATION
    #define GRAVITY 42 * FRAME_DURATION

And I have noticed that, the further I increase my FPS_LIMIT, the faster things accelerate. Well, it's obvious (or not) that I'm using flawed logic to define the acceleration constants, but I'd also like to know what then I'm doing wrong and what'd be the right way to calculate these values, because what I'll pretty much be doing through my scripts will be as simple as this:

    void onUpdate() {
        mySpeed += acceleration;
        myPosition += mySpeed;
    }

As if framerate-independence didn't even exist.

If you want to get technical, I'm using simple SFML for the fixed time steps, through a window.setFramerateLimit(FPS_LIMIT) call.

\$\endgroup\$

2 Answers 2

4
\$\begingroup\$

First, your timeElapsed absolutely should not be fixed. Measure the actual frame time. Plenty of articles on it. Even with things like a setFramerateLimit call, the game loop might not run at that exact time every frame.

#define FRAME_DURATION (1.0f / FPS_LIMIT)

#define RUNNING_SPEED 42 * FRAME_DURATION
#define GRAVITY 42 * FRAME_DURATION

This part makes no sense. Why is speed dependent on a time variable? Speed is distance/time. For instance, 1.2 meters/second. You multiply speed by time to get distance.

Take your elapsed frame time and multiply it by the speed to get unit cancellation.

timeElapsed = 7; // milliseconds --> .007 seconds
speed = 1.2; // meters / second
movement = speed * timeElapsed;

Working out that final bit on paper gives us:

movement = 1.2 meters / second * .007 seconds =
movement = (1.2 * .007) * (1 meters * 1 second / 1 second)
movement = .0084 * (1 meters)
movement = .0084 meters

Regarding acceleration, it's the same thing. Acceleration is in meters/(second*second) (meters per second squared). You get velocity (or speed in the mono-dimensional case) with velocity=acceleration*time=meters/(second*second)*second=meters/second.

So yes, the line in question is valid. You're usually dealing with velocity, not speed, though. The difference is direction. Speed says how fast you're going, velocity says how fast you're going on which way you're going. This is important for gravity. Gravity doesn't just make you accelerate; if you're jumping over a pit, the gravity force will cause you to slow down, stop for an instant at the zenith of your arc, then start making you speed up going downwards. You probably understood all this, I'm sure, but be precise with your terminology when you can. It'll avoid problems down the road.

void onUpdate() {
    mySpeed += acceleration;
    myPosition += mySpeed;
}

This makes little sense, and again, terminology. In this case, you're adding speed to another speed value (an acceleration premultipled with time), and then the second line makes no sense at all. Acceleration is the second derivative of position with respect to time, so you need to integrate time twice to properly calculate position. Even if you premultiply your initial speed, the result of adding the premultiplied acceleration will throw it out of whack. You must multiple by time in the second line, and I can almost guarantee that you'll be way better off multiplying acceleration by time in the first line.

\$\endgroup\$
1
\$\begingroup\$

Using Euler integration (which I assume is what you were going for here), your constants should be defined independent of your frame time. This is because you take time into account during your update loop.

So your constants become:

#define FRAME_DURATION (1.0f / FPS_LIMIT)

#define RUNNING_SPEED 42.0f
#define GRAVITY 42.0f

This should fix the inconsistency you're experiencing with the update loop.

However, you'll notice that this causes your objects to accelerate (and run) much faster than they used to. To fix this you could pick an arbitrary frame rate and use that to recalculate your constants:

#define RUNNING_SPEED 0.7f // 42 / 60
#define GRAVITY 0.7f

Though I'd recommend using more realistic values:

#define GRAVITY 9.8f // Earth's gravity in meters per second squared

This means when you go to add new objects to your game, you can base their properties off of real world objects, and you'll instantly have physics that seem consistent - e.g. your player could be 1.6 meters tall, the height of the average human.

I also agree with Sean that you need to be precise with your terminology, and next time your pseudo code should make use of the constants you've defined so we can see exactly what you're trying to achieve.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .