1
\$\begingroup\$

I have a big problem with my Java games. In every game I make the movement of the player and objects just looks awfull. The framerate is 60 fps without any problems. But the movement looks extremly unsmooth. I tried several things but nothing worked. The game code is too long and unstructured to show the hole one but here are some parts that may cause the problem:

this.repaint();

//Framerate
try {
    Thread.sleep(15);
} catch (InterruptedException e) {
    e.printStackTrace();
}

and that's how I tested the framerate:

 //FPS anzeigen

    if(RaumNr >= 0){

        FPSCount += timesincelastframe;
        howoften ++;
        if(FPSCount > 1){
            FPSCount = 0;
            FPS = howoften;
            howoften = 0;
            System.out.println(FPS);
        }
    }

That's how my delta time system works:

 while(true){

        long thisframe = System.currentTimeMillis();
        timesincelastframe = ((float) (lastframe - thisframe)) / -1000f;
        lastframe = thisframe;


        if(!M.hasFocus())
            M.requestFocus();

and so on.

    super.paintComponent(g);

    Graphics2D g2d = (Graphics2D) g;

    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    g2d.scale(BreiteMulti, HöheMulti);

And that's how I move the player for example:

 x -= 350 * timesincelastframe * speed;

I hope you have any ideas wht the problem might be. If you need more code examples please tell me.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ What do you mean by "The framerate is 60 fps without any problems."? You did some tests and your timesincelastframe is constantly at 0.0166666667 seconds? Also a picture is worth a thousand words, you might want to use a tool such as gifcam or screentogif to upload an animated screenshot to your question so that it helps us see the issue. \$\endgroup\$
    – Vaillancourt
    Commented Sep 24, 2018 at 0:42

1 Answer 1

2
\$\begingroup\$

There are three problems here:

  • When you call Thread.sleep(15) you forget to account for the time it took to calculate and render the previous frame. Before you suspend the thread, check how long it took to process the last frame, and subtract that number.
  • Thread.sleep(15) does not mean "pause for exactly 15ms" it means "tell the OS thread scheduler to suspend the thread for at least 15ms and then unsuspend it as soon as it has the time". Also, unsuspending a thread is a costly operation which might take non-negligible time in itself. The result is that sleep might "oversleep" occasionally and pause a bit longer than you intended it to. A good way to deal with that is calculate the timecode where the next frame is supposed to start before you put the thread to sleep.
  • System.currentTimeMillis(); is not the most precise method to obtain a timestamp. Use System.nanoTime(); instead. It returns the time in nanoseconds, not milliseconds. So you need to divide it by 1000000 to convert it to milliseconds.

To fix these three problems, you game loop might look like this:

    public static final long NANOSECONDS_PER_MILLISECOND = 1000000;
    public static final long MS_PER_FRAME;

    private long frameStart = System.nanoTime();

    while(gameIsRunning) {
         updateAndRenderTheGame();
         elapsedTime = (System.nanoTime() - frameStart) / NANOSECONDS_PER_MILLISECOND;             
         frameStart = System.nanoTime() + MS_PER_FRAME * NANOSECONDS_PER_MILLISECOND;
         Thread.sleep(15 - elapsedTime);
    }

A fourth problem you might encounter is if you are using a variable timestep but handle your game mechanics with integers. If you do this, you will get a lot of jitter due to rounding errors. Use float's or double's instead. When you pass coordinates to the drawing API, then you might want to round them to integers to avoid blurring. But do not use the rounded values afterwards.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ System.nanoTime is awful on some systems as it requires communication between various parts of the motherboard (see here). On my personal setup for instance it goes in the "takes milliseconds" category \$\endgroup\$
    – Bálint
    Commented Sep 24, 2018 at 9:50

You must log in to answer this question.

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