1
\$\begingroup\$

Currently I'm using a variable time step and when the FPS drops by even a small amount you can easily notice a slight lurch forward of the player. I'm making a platformer and I'm wondering whether I should use a fixed timestep instead, however I'm confused as to why my movement doesn't look smooth, because the various articles I've read all say that a variable timestep is meant to make movement look much smoother.

So my question: Is a fixed timestep the better option for a 2D platformer, and why would anyone even use a variable timestep if your sprite appears to jump forward every 2-3 seconds?

private static final int UPDATE_RATE = 90;
private static final long UPDATE_PERIOD = 1000000000L / UPDATE_RATE;

private void mainLoop() {   
    long beginTime, timeTaken, timeLeft;
    while (state == State.PLAYING) {
        beginTime = System.nanoTime();

        update();
        repaint();

        timeTaken = System.nanoTime() - beginTime;
        timeLeft = (UPDATE_PERIOD - timeTaken) / 1000000L;
        if (timeLeft < 10)
            timeLeft = 10;
        try {
            Thread.sleep(timeLeft);
        } catch (InterruptedException ex) { }
    }
}

Delta time is calculated every time repaint is called.

long currentTime = System.nanoTime();
        deltaTime = (currentTime - previousTick) / 1000000L;
        previousTick = currentTime;

This is how I pass the delta time into the player class.

public void move(float deltaTime) {
    if(left && !right)
        xPos -= 250*(deltaTime/1000);
    if(right && !left)
        xPos += 250*(deltaTime/1000);
}
\$\endgroup\$
  • \$\begingroup\$ Share some more details of your implementation, otherwise it's going to be difficult to pinpoint the problem. \$\endgroup\$ – bornander Oct 10 '13 at 14:22
  • \$\begingroup\$ I've edited it to include my main loop. \$\endgroup\$ – Troubleshoot Oct 10 '13 at 14:29
  • \$\begingroup\$ You should be calculating delta time and passing it to the update function. Otherwise how will it know that one frame is shorter or longer than the others?? \$\endgroup\$ – MickLH Oct 10 '13 at 14:38
  • \$\begingroup\$ Sorry I forgot to include how I'm calculating my delta time. I'll edit it. \$\endgroup\$ – Troubleshoot Oct 10 '13 at 14:42
6
\$\begingroup\$

Get rid of the Sleep call.

Sleep is fine for reducing CPU usage, but it is not fine for controlling framerate, and these two are not the same thing.

  • Sleep can have poor precision, in the order of ~16 milliseconds.
  • Sleep guarantees that the thread will resume at some arbitrary time after the Sleep interval has elapsed, not at the exact Sleep interval.

Since this is tagged Java, I'm going to refer you to http://docs.oracle.com/javase/tutorial/essential/concurrency/sleep.html and quote:

these sleep times are not guaranteed to be precise ... you cannot assume that invoking sleep will suspend the thread for precisely the time period specified

If nothing else, this is completely messing up your timestep. Given the poor granularity of Sleep calls, if you go even a little above one Sleep interval you're now Sleeping for two intervals - and as I said, a default Sleep interval can have a granularity of ~16 milliseconds.

If you want (or need) to reduce CPU usage, you can keep a count of time elapsed since the previous frame, and if it's not yet time to run a frame, Sleep for one millisecond, otherwise run the frame. Combine this with a method of improving the precision of Sleep (I don't know Java so I can't advise what's appropriate here) and your program will be a succession of Sleep (1) calls with the occasional frame interspersed.

But either way, the point remains: do not use Sleep for controlling framerate.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thanks for the answer and the great explanation, but I'm confused as to why if I do what you suggest my movement speed becomes nearly 3x as fast. Could my delta time calculation be wrong? \$\endgroup\$ – Troubleshoot Oct 11 '13 at 16:32
2
\$\begingroup\$

deltaTime = (float)(currentTime - previousTick) / 1000000.f

It's a simple floating point bug. When you divide an integer by another integer it returns an integer. This truncates all your decimal detail.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Hi there, could you elaborate a bit more? Answers with a snippet of code with no explanation are usually not as great as ones with full explanations. You'll receive more votes and attention if you improve the quality of your answer. \$\endgroup\$ – Vaughan Hilts Oct 10 '13 at 22:12
  • \$\begingroup\$ Oh thanks, I didn't even notice my mistake, but yes this has improved the accuracy of my frame rate a lot. As previously commented though, if you'd provided an explanation this would be a better answer. \$\endgroup\$ – Troubleshoot Oct 11 '13 at 16:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.