你如何将游戏逻辑与显示分开?

19 algorithm

如何使每秒显示帧独立于游戏逻辑?这样,无论视频卡呈现多快,游戏逻辑都以相同的速度运行.

Ada*_*dam 30

我认为这个问题揭示了对如何设计游戏引擎的一些误解.这是完全可以的,因为它们是非常复杂的东西,很难得到正确的;)

您的正确印象是您想要所谓的帧速率独立性.但这不仅涉及渲染帧.

单线程游戏引擎中的帧通常被称为Tick.每个Tick都处理输入,处理游戏逻辑,并根据处理结果渲染帧.

您想要做的是能够以任何FPS(每秒帧数)处理您的游戏逻辑并获得确定性结果.

在以下情况下,这会成为问题:

检查输入: - 输入是键:'W'表示我们将玩家角色向前移动10个单位:

playerPosition + = 10;

既然你每帧都这样做,如果你以30 FPS的速度运行,你将每秒移动300个单位.

但如果你以10 FPS的速度运行,你每秒只能移动100个单位.因此,您的游戏逻辑不是帧率独立的.

令人高兴的是,解决这个问题并让你的游戏玩逻辑独立帧速率是一项相当简单的任务.

首先,您需要一个计时器来计算每帧渲染所需的时间.以秒为单位的这个数字(完成一个Tick的0.001秒)然后乘以你想要的帧速率无关的数字.所以在这种情况下:

拿着'W'时

playerPosition + = 10*frameTimeDelta;

(Delta是"改变某事"的一个奇特的词)

因此,你的玩家将在一个Tick中移动10分之一,在完整的Ticks后,你将移动全部10个单位.

然而,当涉及变化率也随时间变化的属性时,例如加速车辆,这将会下降.这可以通过使用更高级的集成器来解决,例如"Verlet".

多线程方法

如果你仍然对你的问题的答案感兴趣(因为我没有回答它但提出了替代方案),现在就是这样.将游戏逻辑和渲染分成不同的线程.它有它的缺点.足以使绝大多数游戏引擎保持单线程.

这并不是说在所谓的单线程引擎中只运行一个线程.但是所有重要的任务通常都在一个中心线程中.像碰撞检测这样的东西可能是多线程的,但通常Tick的碰撞阶段会阻塞,直到所有线程都返回,并且引擎返回到单个执行线程.

多线程提出了一整套非常大的问题,甚至是一些性能问题,因为所有东西,甚至是容器,都必须是线程安全的.游戏引擎是一个非常复杂的程序,所以很少值得增加多线程的复杂性.

固定时间步骤方法

最后,正如另一位评论者指出的那样,拥有固定大小的时间步长,以及控制游戏逻辑"步进"的频率也可以是一种非常有效的方法来处理这一点并带来很多好处.

链接在这里是为了完整性,但另一位评论者也链接到它: 修复你的时间步骤


Rya*_*Fox 8

Koen Witters有一篇关于不同游戏循环设置的非常详细的文章.

他介绍:

  • FPS依赖于恒定游戏速度
  • 游戏速度取决于可变FPS
  • 具有最大FPS的恒定游戏速度
  • 恒定游戏速度独立于可变FPS

(这些是从文章中提取的标题,按顺序排列.)


Jes*_*der 4

你可以让你的游戏循环看起来像:

int lastTime = GetCurrentTime();
while(1) {
    // how long is it since we last updated?
    int currentTime = GetCurrentTime();
    int dt = currentTime - lastTime;
    lastTime = currentTime;

    // now do the game logic
    Update(dt);

    // and you can render
    Draw();
}
Run Code Online (Sandbox Code Playgroud)

然后你只需要编写你的Update()函数来考虑时间差异;例如,如果您有一个对象以某种速度移动v,则每帧更新其位置v * dt