使用简单的Java Game Loop,CPU使用率非常高

时间:2016-09-06 00:00:43

标签: java cpu

我一直在学习游戏设计的原理,并在许多教程的帮助下使用Java进行游戏循环。它现在所做的就是将草图渲染到JFrame:

public class Game extends JPanel implements Runnable {

String title;
int height;
int width;

boolean ps;

private int ticks;  
private JPanel p;
private BufferStrategy bs;
private Graphics g;
private boolean running = false;
private Thread thread;  
private Frame frame;
private KeyHandler keyHandler;

public Game(String title, int width, int height){
    this.width = width;
    this.height = height;
    this.title = title;
    keyHandler = new KeyHandler();
}

private void init() {
    TileHandler.init();
    frame = new Frame(title, height, width);
    frame.getFrame().addKeyListener(keyHandler);
}

private void tick() {
    // KeyHandler.tick();

    // updates game logic       
}

private void render() {
    render(g);      
}

private void render (Graphics g) {  
    bs = frame.getCanvas().getBufferStrategy();
    if(bs == null){
        frame.getCanvas().createBufferStrategy(3);
        return;
    }
    g = bs.getDrawGraphics();
    g.clearRect(0, 0, width, height);   

    g.drawImage(TileHandler.grass, keyHandler.getPlayerX(), 
    keyHandler.getPlayerY(), null);

    bs.show();
    g.dispose();
}

@Override
public void run() {

    int x = 4;
    init();
    int fps = 60;  // target
    double tickTime = 1000000000 / fps; // time per 1 frame
    double delta = 0;   
    long timer = 0;

    long startTime = System.nanoTime();
    long endTime;

    while (x == 4) {
        endTime = System.nanoTime();
        delta += (endTime - startTime) / tickTime;
        timer += endTime - startTime;
        startTime = endTime;

        if (delta >= 1) {
            ticks++;
            render();
            delta--;
        }
        if(timer >= 1000000000){
            ticks = 0;
            timer = 0;
        }
    }
}

public int getTicks() {
    return ticks;
}

public synchronized void startThread() {
    // Start the thread
    if (!running) {             // if not already 

        running, you can begin
        running = true;
        thread = new Thread(this); //Run THIS class on a 

        new thread
        thread.start();
    }
    else {  // safety measure
        return;
    }
}

public void stopThread() {
    if (!running) {
        return;
    }
    running = false;
    try {
        thread.join(); //Method stops the thread
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}

}

它运行良好,我可以让它以稳定的60 FPS运行,唯一的问题是它占用了这么多的CPU。平均而言,它使用了大约50%的CPU,并减慢了我电脑的其余部分 - 我的笔记本电脑上使用的Minecraft大致相同!我知道问题在于上面代码中的游戏循环。

所以我只是想了解导致这种情况发生的原因。我确实尝试使用分析器,但我仍然无法解决导致问题的原因。

1 个答案:

答案 0 :(得分:2)

好的是给出最简单的答案:你的循环运行速度与CPU可以处理的速度一样快。我假设你有一个带有两个内核的CPU,所以主循环线程正在使用它可以尽可能快地通过循环运行的每一点计算能力,从而阻止你的两个核心之一(50%)。

一种解决方案是计算每次迭代所花费的时间并休眠一段时间,直到下一次迭代开始。这是一个伪代码:

while(running) {
    long startTime = getTime();

    update();
    render();

    long endTime = getTime();
    long elapsedTime = endTime - startTime;
    Thread.sleep(TARGET_FRAME_TIME - elapsedTime); //sleep to yield unneeded CPU usage
}

如果你没有使用像LWJGL或JOGL这样的OpenGL库,你也不会有很好的表现。我不知道你的比赛会是什么,但是60fps可能是挥杆的上限。

我建议您学习JavaFX游戏,因为它使用硬件加速进行渲染,并且可以为相对复杂的应用程序处理120fps +。它还为游戏循环设计提供了TimelineAnimationTimer类。