Dev_anon101
Dev_anon101

Reputation: 107

game Loop performance issue

I am making a bomberman game in Java, the game seems to be slowing the PC overloading the processors and CPU. I have used the loop in another game and it worked fine without causing any performance problem. However I did notice that by simply commenting out the gameloop() will cause major performance issue

The game loop I'm using:

public void start() {
    window.setVisible(true);
    running = true;
    int fps = 60;
    double timePerTick = 1e9 / fps;
    double delta = 0;
    long now;
    long lastTime = System.nanoTime();

    while (running) {
        now = System.nanoTime();
        delta += (now - lastTime) / timePerTick;
        lastTime = now;
        if (delta >= 1) {
            gameLoop(); /* commenting this out will cause major performance
                         * problem to the PC */
            delta--;
        }
    }
}

@Override
public void gameLoop() {
    if(!gameover){
        run();
        gui.repaint();
    }
}

Is there any problem with this loop which could be causing problem, or is there a better method which will reduce the performance issues

[EDIT] I changed the loop to do a similar task with timer, it works fine and does not cause any performance issues, anything still wrong with this method (long term issue)??

public void start(int fps){
   window.setVisible(true);
   running = true;
   gameTimer.scheduleAtFixedRate(new GameTimer(), 0, 1000/fps);
}

private class GameTimer extends TimerTask{

   @Override
   public void run(){
      gameLoop();
   }
}

Upvotes: 0

Views: 1156

Answers (2)

Durandal
Durandal

Reputation: 20059

You are busy looping, which will keep one thread permanently busy. This inevitably takes away CPU resources, making less available for anything else.

Instead of constantly taking the nanoTime() and calling gameloop() when enough time has elapsed, you should predict at which time the next call to gameloop() shall take place and call Thread.sleep() to pause the thread until that time arrives. For many purposes its accurate enough to just calculate the millisecond timestamp when the next tick is due, subtract the current time and sleep that amount:

long lastTick = System.currentTimeMillis();
long ticksPerFrame = 1000 / fps;
while (true) {
    long nextTick = lastTick + ticksPerFrame;
    long sleep = nextTick - System.currentTimeMillis();
    if (sleep > 0) {
        try {
            Thread.sleep(sleep);
        } catch (InterruptedException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }
    lastTick = nextTick;
    gameloop();
}

(Code not tested, only meant to demonstrate the general approach)

This will be only be as accurate as the system timer resolution plus/minus sleep variation. For most systems that means an average few ms of variation, acceptable for many scenarios, especially if you use AWT/Swing for rendering anyway. A repaint may be skipped by Swing if you place repaint() calls faster than the EDT can handle them, this is in most cases desirable as it allows the repaint queue to catch up when delayed.

Upvotes: 0

Nicolas Filotto
Nicolas Filotto

Reputation: 44985

Your are making an infinite loop without any pauses which consumes 100% of your CPU, in your case according to your needs, you should define your frame rate and set the length of time to sleep accordingly as next:

    run();
    gui.repaint();
    // Make the current thread sleeps 1 000 milliseconds which means 1 frame per sec
    Thread.sleep(1000L);

Upvotes: 1

Related Questions