Question

for personal practice, I am remaking Flappy bird for desktop with Java, I have managed to get all the pillars generating, screen, bg moving done, but now I have one problem, which is performance.

I sometimes feel that the game isn't moving as fast, and sometimes gets stuck for 0.5 secs or something, but that's not the case, when I move my bird, it's moving a bit weird, looks like its moving too much forward & then to the back, watch the gif in MP4 format:

http://gyazo.com/d7e94c0b772192e5a5dd1d2b61b8c529

What could be causing that? could this be my game loop or the way I draw the graphics? I don't use double buffering, I render simply by calling .repaint in jframe which repaints the JPanel I added.

Game loop:

private void gameLoop() {
    new Thread() {
        private long last;
        private long start;
        private int wait;
        public void run() {
            while(game) {
                long now = System.nanoTime();
                long length = now - lastLoop;
                lastLoop = now;
                double delta = length / ((double) Constants.OPTIMAL);
                lastFps += length;
                fps++;
                if (lastFps >= 1000000000) {
                    System.out.println("FPS: " + fps);
                    lastFps = 0;
                    fps = 0;
                }
                update(delta);
                render();
                this.sleep
            }
        }
        private void sleep() {
            try {
                Thread.sleep((this.last - System.nanoTime() + Constants.OPTIMAL) / 1000000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }.start();
}

My drawing area:

public void paintComponent(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;
    int translateAmount = this.game.getLevel().getTranslate();
    g.translate(-translateAmount, 0);
    this.background.render(g2d);        
    this.game.getLevel().renderLevel(g2d);
    g.translate(0, 0);
    this.game.getBird().render(g2d);

}

The way I render the backgrounds is this: I add backgrounds one after one, and if a background is outside of the frame, i won't render it.

public void render(Graphics2D g) {
    Iterator<RepeatedBackground> itr = this.repeats.iterator();
    while (itr.hasNext()) {
        RepeatedBackground b = itr.next();
        if (this.game.getLevel().getTranslate() - b.getX() >= 300) {
            itr.remove();
            continue;
        }
        if (b.getX() - this.game.getLevel().getTranslate() < Constants.WIDTH) {
            b.render(g);
        }
    }
}

This is how I move my bird (i dont use delta, used some tutorial on this):

private void update(double delta) {
    if (System.currentTimeMillis() - this.level.getTime() >= Constants.TRANSLATE_SPEED) {

        // move background
        this.level.updateTranslate();
        this.level.setTime();

        // move bird
        this.getBird().move();
    }
}

public void move() {
    this.x += 2 / 1.10;
}

What could be causing lag to the bird or the background? Is there something wrong with my rendering ways or game loop?

Fps always printing this:

FPS: 1724172
FPS: 1551857
FPS: 1494378
FPS: 1471987
FPS: 1434095
FPS: 1629905
Was it helpful?

Solution

Your game loop confuses me - but that's not hard ;)

Basically, as I understand these things, it should work something like...

while (gamming) {
    now = get current time;
    update game state
    delta = get current time - now
    delay = desired delay - delta
    wait for delay
}

You don't seem to be taking into account the amount of time that the render and update methods "might" take to execute and calculating the time to wait based those requirements...

Now, I'm not sure what your delta values is suppose to be...the time through the current second?? So I've left it out of my example...

The following example gives me a constant 25fps, even with the random delays in the update and render methods

Now, forgive me, I typically work in milli seconds, it's just simpler on my poor, feeble mind.

import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

public class TestGameLoop {

    public static void main(String[] args) {
        new TestGameLoop();
    }

    public TestGameLoop() {
        gameLoop();
    }

    public static class Constants {

        public static final double OPTIMAL = 25; // fps...

    }

    private boolean game = true;
    private long lastLoop;
    private long lastFps;
    private long fps;

    private void gameLoop() {
        new Thread() {

            private long last;
            private long start;
            private int wait;

            public void run() {

                // Calculate the optimal/maximum delay time
                // This is converted to nanos so it can be 
                // used to calculate the actual delay...
                long millisPerSecond = TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS);
                long optimalDelay =  Math.round(millisPerSecond / Constants.OPTIMAL);

                optimalDelay = TimeUnit.MILLISECONDS.toNanos(optimalDelay);

                // Last start of a "second" loop                    
                long loop = System.nanoTime();
                // While gaming...
                while (game) {
                    // Start of this cycle...
                    long now = System.nanoTime();

                    // Update the state and render the 
                    // current frame...
                    update();
                    render();

                    // How long did that update take??
                    long timeTaken = System.nanoTime();
                    long delta = timeTaken - now;

                    // Subtract the delay from the maximum delay
                    long delay = optimalDelay - delta;
                    if (delay > 0) {
                        try {
                            // Sleep expects milliseconds...
                            delay = TimeUnit.NANOSECONDS.toMillis(delay);
                            Thread.sleep(delay);
                        } catch (InterruptedException ex) {
                            ex.printStackTrace();
                        }
                    }

                    // Calculate if we've being running for a second yet...
                    long loopDelay = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - loop);
                    // If the loop has been cycling for a second...
                    if (loopDelay >= 1) {
                        // Reset the loop time
                        loop = System.nanoTime();
                        System.out.println("FPS = " + fps);
                        fps = 0;
                    } else {
                        // Add another frame to the pile...
                        fps++;
                    }
                }
            }
        }.start();
    }

    public void update() {
        try {
            Thread.sleep(Math.round(Math.random() * 20));
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }

    public void render() {
        try {
            Thread.sleep(Math.round(Math.random() * 20));
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }

}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top