Java 主游戏循环

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18283199/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 00:01:55  来源:igfitidea点击:

Java Main Game Loop

javagame-engine

提问by Get Off My Lawn

I am writing a game loop, I found the code in the example below here. I have also looked at other ways to do a game loop, such as from this article. I couldn't get any of those ones working though. So I kept with the one from the first link.

我写一个游戏循环,我发现在例如下面的代码在这里。我还研究了执行游戏循环的其他方法,例如这篇文章。不过,我无法让其中任何一个工作。所以我保留了第一个链接中的那个。

What I would like to know:

我想知道的是:

  • Is the way I wrote my game loop a good way to do this?
    • Any suggestions?
  • Should I be using Thread.sleep();in my game loop?
  • 我编写游戏循环的方式是实现此目的的好方法吗?
    • 有什么建议?
  • 我应该Thread.sleep();在我的游戏循环中使用吗?

Here is my current code:

这是我当前的代码:

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){
        }
    }

采纳答案by William Morrison

Eventually you'll want to move to something like LWJGL, but let me stress, keep doing what you're doing here for now. It will teach you fundamentals.

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

Good job on your loop. Looks nice, let me offer a few pointers:

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

  • Repaint will not render the screen immediately. It tells the RepaintManagerto render when its ready. Use invalidatepaintImmediatelyinstead. paintImmediatelywill block execution until the component has been redrawn so you can measure rendering time.

  • Thread.sleeptypically has a few milliseconds drift. You should be using it to keep your loop from using too much CPU, but make sure you understand if you sleep 10 milliseconds you might sleep 5 milliseconds or you might sleep 20.

  • Lastly:

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

    If updateLengthis less than OPTIMAL_TIME, don't call update. In other words, if delta is less than one, don't update. This tutorialexplains why better than I ever could.

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

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

  • 最后:

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

    如果updateLength小于 OPTIMAL_TIME,则不调用更新。换句话说,如果 delta 小于 1,则不更新。本教程解释了为什么比我以往任何时候都好。

回答by Robert E Fry

Overall, it is a good loop, but there are a few missing aspects to what I have found in experience to be the best loop.

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

You will eventually want to move to LWJGLor some other java game API, but for now, learn the basics of how game-loops work, and what best suits your needs.

您最终会想要转向LWJGL或其他一些 Java 游戏 API,但现在,学习游戏循环如何工作的基础知识,以及什么最适合您的需求。

  • Firstly, in answer to one of your points, no. You will do better staying away from

    Thread.sleep()

    this can stray from the real amount of time you set it to sleep.
    e.g. if you set it to sleep for 10 milliseconds, it could sleep the program for 5 to 20 milliseconds.

  • The second problem I cam immediately see is that you do not have any way to stop the game-loop for a custom stop() method. Try

    boolean running = true;
    while (running) {
    // Your Code Here //
    }

  • Thirdly, you may want to consider changing how you use your delta variable. The way in the code below may be a better use and construction for you.

    This is an example of my game-loop that I use in my programs:

    @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;
            }
        }
    }
    
  • 首先,回答你的一个观点,不。你会做得更好远离

    线程.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;
            }
        }
    }