19

我正在编写一个游戏循环,我在下面的示例中找到了代码here。我还研究了其他方法来做一个游戏循环,比如这篇文章。我无法让这些工作中的任何一个工作。所以我保留了第一个链接中的那个。

我想知道的:

  • 我编写游戏循环的方式是实现此目的的好方法吗?
    • 有什么建议么?
  • 我应该Thread.sleep();在我的游戏循环中使用吗?

这是我当前的代码:

public void run(){
    long lastLoopTime = System.nanoTime();
    final int TARGET_FPS = 60;
    final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
    long lastFpsTime = 0;
    while(true){
        long now = System.nanoTime();
        long updateLength = now - lastLoopTime;
        lastLoopTime = now;
        double delta = updateLength / ((double)OPTIMAL_TIME);

        lastFpsTime += updateLength;
        if(lastFpsTime >= 1000000000){
            lastFpsTime = 0;
        }

        this.updateGame(delta);

        this.repaint();

        try{
            Room.gameTime = (lastLoopTime - System.nanoTime() + OPTIMAL_TIME) / 1000000;
            System.out.println(Room.gameTime);
            Thread.sleep(Room.gameTime);
        }catch(Exception e){
        }
    }
4

3 回答 3

21

最终你会想要转向类似LWJGL的东西,但是让我强调一下,继续做你现在正在做的事情。它会教你基础知识。

你的循环做得很好。看起来不错,让我提供一些建议:

  • 重绘不会立即渲染屏幕。它告诉RepaintManager在准备好时进行渲染。改为使用invalidate paintImmediatelypaintImmediately将阻止执行,直到组件被重绘,以便您可以测量渲染时间。

  • Thread.sleep通常有几毫秒的漂移。您应该使用它来防止循环使用过多的 CPU,但请确保您了解如果您睡 10 毫秒,您可能会睡 5 毫秒或睡 20 毫秒。

  • 最后:

    double delta = updateLength / ((double)OPTIMAL_TIME);
    

    如果updateLength小于 OPTIMAL_TIME,则不调用更新。换句话说,如果 delta 小于 1,则不要更新。本教程解释了为什么比我做得更好。

于 2013-08-16T22:57:18.423 回答
7

总的来说,这是一个很好的循环,但是我在经验中发现的最佳循环有一些缺失的方面。

您最终会想要迁移到LWJGL或其他一些 java 游戏 API,但现在,学习游戏循环如何工作的基础知识,以及最适合您需求的内容。

  • 首先,回答你的一个观点,不。远离你会更好

    线程.sleep()

    这可能会偏离您将其设置为睡眠的实际时间。
    例如,如果您将其设置为休眠 10 毫秒,它可以让程序休眠 5 到 20 毫秒。

  • 我立即看到的第二个问题是,您没有任何方法可以停止自定义 stop() 方法的游戏循环。尝试

    布尔运行=真;
    while (running) {
    // 你的代码在这里 //
    }

  • 第三,您可能需要考虑更改使用 delta 变量的方式。下面代码中的方式对您来说可能是更好的使用和构造。

    这是我在程序中使用的游戏循环的示例:

    @Override
    public void run() {
    
    long initialTime = System.nanoTime();
    final double timeU = 1000000000 / UPS;
    final double timeF = 1000000000 / FPS;
    double deltaU = 0, deltaF = 0;
    int frames = 0, ticks = 0;
    long timer = System.currentTimeMillis();
    
        while (running) {
    
            long currentTime = System.nanoTime();
            deltaU += (currentTime - initialTime) / timeU;
            deltaF += (currentTime - initialTime) / timeF;
            initialTime = currentTime;
    
            if (deltaU >= 1) {
                getInput();
                update();
                ticks++;
                deltaU--;
            }
    
            if (deltaF >= 1) {
                render();
                frames++;
                deltaF--;
            }
    
            if (System.currentTimeMillis() - timer > 1000) {
                if (RENDER_TIME) {
                    System.out.println(String.format("UPS: %s, FPS: %s", ticks, frames));
                }
                frames = 0;
                ticks = 0;
                timer += 1000;
            }
        }
    }
    
于 2014-05-17T00:07:27.427 回答
0

刷新重绘的最简单方法可能是这样的:

public class GameLoop extends JPanel {
private final BufferedImage back_buffer;
bool state = true;

public void init() {
        while (state) {
            updatePlayer();
            delay(5);
        }
    }

public void delay(int time) {
        try {
            Thread.sleep(time);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        repaint();
    }

重绘功能是更新所有图形的人

@Override
    public void paint(Graphics g) {
        super.paint(g);
        
        grapicDoble.setColor(Color.white);
        grapicDoble.fillRect(0, 0, 500, 500);
        game.reset();
        
        g.drawImage(back_buffer, 0, 0, this);
    }
于 2021-08-18T02:26:22.597 回答