在 Java 游戏中渲染比更新更快有啥好处?

Posted

技术标签:

【中文标题】在 Java 游戏中渲染比更新更快有啥好处?【英文标题】:What are the benifits of rendering faster than updating in a Java game?在 Java 游戏中渲染比更新更快有什么好处? 【发布时间】:2014-03-09 19:17:30 【问题描述】:

ANSWER: 第一个循环会持续渲染,即使 update() 没有被调用,所以除非你有其他线程影响变量而不是调用 update() 的那个,它会渲染相同的东西几次直到它再次更新。主循环以最大速度运行,导致 CPU 使用率较高。

第二个循环更新、渲染,然后休眠一段时间,让主线程完全空闲。如果其他线程影响变量,您必须等到调用render() 的线程完成休眠并使用update() 进行更新,以便render() 最终可以根据其他线程如何影响它来渲染新屏幕。

如果您正在制作包含多线程的大型游戏,则第一个循环更好,第二个循环更适合仅使用一个线程运行整个游戏的游戏(因此更新变量和渲染它们之间没有延迟,因为一个线程游戏只在一个线程上更新,更新后立即渲染触发器。


我见过各种不同的循环。我的问题是这两个循环之间有什么区别:(所有参考变量都不需要,但例如给出)

long starttime = System.nanoTime();
int onesec = 1000000000;
int fps = 60;
double difference = 0;
double updatechecker;

while(true) 
     long currenttime = System.nanoTime();
     difference = (currenttime - starttime);
     updatechecker = difference/(onesec/fps);

     while(updatechecker >= 1) 
          //update() here
          updatechecker = 0;
     
     //render() here

     starttime = currenttime;

我知道,对于像这样更复杂的循环,您可以执行诸如查看是否有时间在再次更新之前渲染另一个屏幕等操作。

我的问题是渲染比更新更快有什么意义?为什么这样的事情不会更有效率:

while(running) 
    long starttime = System.currentTimeMillis();
    //update() here
    //render() here
    long endtime = System.currentTimeMillis();

    try 
        Thread.sleep((1000/60) + (starttime - endtime));
     catch(InterruptedException e) 
        e.printStackTrace();
    


我知道在第一个循环中,您可以在更新之前检查是否有时间再次渲染,但是在同一时间和不同时间更新/渲染真的有很大区别吗? (您也可以只使用第一个循环并将渲染方法放在更新所在的位置)

我发现使用 Thread.sleep 方法会使我的 cpu 使用率下降很多。我通常在第一个循环中平均 23-26% cpu(尽可能快地渲染),我在第二个循环中平均 2-4% cpu。更好的方法是什么? (优点和缺点?)

【问题讨论】:

【参考方案1】:

第一组代码的重点不是渲染比更新更频繁,而是允许更新比渲染更频繁。例如,如果更新需要 1/80 秒,而渲染需要 1/80 秒,那么您就没有时间为每 1/60 秒的帧进行更新和渲染。第一组代码将允许更新以预期的速度发生——每一帧——同时在有时间的时候渲染——在这种情况下,每三帧一次。帧速率下降,但动作以正常的预期速度继续。

使用相同的参数 - 更新需要 1/80 秒,渲染需要 1/80 秒 - 第二种情况会越来越落后于操作,每 1/ 需要 1/40 秒60 第二帧。您的游戏会像慢动作一样运行。

现在,第一组代码确实使用了更多 CPU。可以通过在处理 >= 1 案例之前更改 updatechecker 以检查零来改进它。如果计算出的updatechecker 为零,那么您可以休眠直到下一次更新的时间 - difference % (onesec/fps) / 1000000 毫秒。

【讨论】:

【参考方案2】:

标准软件工程可能不适用于游戏开发,但一般来说,您的目标是 MVC。 Controller改变Model,View渲染Model。如果可以选择,您还需要事件驱动代码,但看起来您是在轮询而不是使用回调。

因此,如果这是 pong,您的控制器正在输入 'up',在 update() 中,您将 'y' 变量增加 1,然后 render() 将其绘制高一个像素。

所以简单地考虑一下,你会期望它是这样的......而且我认为基于轮询机制你不会变得更好。

while(running) 
    if (pollTime) update();
    render();    

让一个偶尔在后台休眠的线程不会改变任何事情。

【讨论】:

是的,我有这样的系统(更新会影响我的对象,渲染看到它并渲染它)。我的问题是巨大的 CPU 使用率差异。使用Thread.sleep(#) 方法为我节省了大量的 CPU,而第一个循环平均占用了 25%。即使同时渲染/更新(使用第一个循环),也需要大量 CPU。第二个循环会给我带来什么问题吗?如果我要同时更新/渲染,它会导致与某些东西发生冲突吗?由于我节省了多少 CPU,我宁愿使用第二个循环 嗯,让我快速检查一下...我不认为让后台线程休眠应该有任何积极的影响。 如果你愿意,我会为两者写一个演示并将其发布在我的问题上,你可以测试(节省你的时间) 好吧,这很可能没有必要......如果你取出你的睡眠线程,你的 CPU 使用率将回到 25%。我认为,由于您的线程处于休眠状态,您的 CPU 只是有时间处于空闲状态并且没有工作效率。 方法一和方法二的主要区别只是第一个有轮询时间,而第二个的轮询时间设置为“渲染完成后”。

以上是关于在 Java 游戏中渲染比更新更快有啥好处?的主要内容,如果未能解决你的问题,请参考以下文章

游戏循环帧独立

有没有比使用 Console.Clear() 更好的方法来制作控制台游戏?

作图显卡和游戏显卡有啥不同吗?

比快更快 | 努比亚红魔开启王者荣耀渲染多线程技术

CPU支持SSE3有啥作用?对游戏有好处吗?

在线游戏,或者比 ajax 更快的东西来发送/接收数据