-1

I want to create a start menue for a Pong clone where the ball in the background bounces off the edges. However the game loop updates to fast so the Coordinates of the ball are already out of the JFrame before you can see it and it moves to fast. I found that through sysouts.

I guess it has something to do with threads but I am not sure. The main class calls this Class as a thread but the important part is in the class BackgroundBallMovement

package main;

public class BackgroundBallMovement implements Runnable{

    private boolean running = true;


    @Override
    public void run() {

        long lastTime = System.nanoTime();
        final double ns = 1000000000.0 / 60;        
        double delta = 0;

        while(running) {
            long now = System.nanoTime();
            delta += (now - lastTime) / ns;
            while(delta >= 1) {
                update();
                delta = 0;
                System.out.println("X-Koordinate " + Var.ballX + " " + "Y-Koordinate " + Var.ballY);
            }
            render();
        }
    }

        //Spiellogik updaten
        private synchronized void update() {
            Var.ballX += 1;
            Var.ballY += 1;

        }

        //Objekte zeichnen
        private synchronized void render() {
             Var.drawStartMenue.repaint();
        }

}
Nicky
  • 121
  • 1
  • 7

3 Answers3

1

You're not using Thread.sleep(). Instead you are waiting until System.nanoTime() changed. This means that the CPU is running all the time (not good).

Also this loop:

while(delta >= 1) {
    ...
    delta = 0;
    ...
}

doesn't make sense because it could be replaced by an if.

Then you are never updating the lastTime variable. So this line:

delta += (now - lastTime) / ns;

will result in a quadratic function because it will result in something like this (each loop execution):

delta += 0.1;
delta += 0.2;
delta += 0.3;
...

Then because you are never updating the lastTime variable after 1s the condition

while(delta >= 1)

will always be met and your ball will move incredibly fast.

Your first approach could be something like this:

@Override
public void run()
{
    while(running)
    {
        update();
        render()
        System.out.println("X-Koordinate " + Var.ballX + " " + "Y-Koordinate " + Var.ballY);
        Thread.sleep(1000L/60L);
    }
}
zomega
  • 1,538
  • 8
  • 26
0

That's because your math sucks ;-)

Yes, (now - lastTime) / ns is the amount of frames that should have been rendered since the engine started. Therefore your code simplifies to:

while (true) {
    delta = framesSinceStart();
    while (delta >= 1) {
        renderFrame();
        delta = 0;        
    }
}

which is equivalent to

while (true) {
    if (framesSinceStart() >= 1) {
        renderFrame();
    }
}

That is, your code correctly waits to render the first frame, but doesn't record that it has rendered that frame, and therefore always thinks it is late, and never waits anymore.

Instead, you might try something like:

while (true) {
    if (framesSinceStart() - framesRendered >= 1) {
        renderFrame();
        framesRendered++;
    }
}

Btw, simply staying in an endless loop to spend time is not very power efficient. It would be better to use something like Thread.sleep() to wait - but calculating the time it should be waiting by hand is a little hairy. Fortunately, the Java API comes with nice helper classes to use:

ThreadPoolExecutor executor = Executors.newSingleThreadExecutor();
executor.scheduleAtFixedRate(() -> renderFrame(), 0, 1000 / 60, TimeUnit.ms);
meriton
  • 68,356
  • 14
  • 108
  • 175
  • I am sorry. I don't understand. delta = framesSinceStart()? I don't know what you want to achieve with that. Also where should I wait? I want to render as much as frames as possible to get a fluent or don't I? – Nicky Aug 10 '19 at 14:44
  • I wanted to show you where you went wrong by summarizing away unnecessary details. The key problem is that your math is wrong. When deciding to update, you are checking whether the *first* update should have happened by now, rather than checking that *less* updates have happened than the frame rate dictates. And no, you don't want to render() more often than update(), because that amounts to repainting the same picture on screen over and over again, which makes to visible difference, but needlessly wastes CPU and GPU time. – meriton Aug 10 '19 at 14:52
0

Try Thread.sleep(long millis)

while(running) {
        long now = System.nanoTime();
        delta += (now - lastTime) / ns;
        while(delta >= 1) {
            update();
            delta = 0;

            try{
                Thread.sleep(1000);
            } catch(Exception e) { }

            System.out.println("X-Koordinate " + Var.ballX + " " + "Y-Koordinate " + Var.ballY);
        }
        render();
    }

another thing you can try is reducing the ball speed.

private synchronized void update() {
        Var.ballX += 0.01;
        Var.ballY += 0.01;

    }
nishantc1527
  • 376
  • 1
  • 12