异步屏幕更新到游戏逻辑,C ++

时间:2009-05-28 13:24:42

标签: c++ multithreading asynchronous ogre3d

我正在使用Visual C ++ 2008 Express和Ogre3D sdk编写游戏。

我的核心游戏玩法逻辑设计为100次/秒。为简单起见,我会说这是一种叫做“gamelogic()”的方法。它不是基于时间的,这意味着如果我想将游戏时间“提前”1秒,我必须将'gamelogic()'称为100次。与游戏的屏幕渲染相比,'gamelogic()'是轻量级的。

Ogre有一个“监听器”逻辑,可以在代码绘制框架时以及完成绘制框架时通知代码。如果我只是在帧渲染之前调用'gamelogic()',那么游戏玩法将受到屏幕渲染速度的极大影响,从5fps到120fps不等。

想到的简单解决方案是:计算自上次渲染帧以来经过的时间,并在下一帧之前多次调用'gamelogic()':100 * timeElapsedInSeconds

然而,我认为“正确”的做法是多线程;有一个单独的线程运行'gamelogic()'100次/秒。

问题是,当两个独立的线程之间存在冲突时,我如何实现这一点以及可以做些什么:当Ogre同时渲染屏幕时,游戏逻辑改变屏幕内容(3d对象坐标)。

非常感谢提前。

3 个答案:

答案 0 :(得分:6)

如果这是您的第一个游戏应用程序,使用多线程来实现您的结果可能比您应该在第一个游戏中真正解决的工作更多。在不同的线程中同步游戏循环和渲染循环并不是一个容易解决的问题。

正如您所指出的那样,渲染时间会极大地影响游戏的“速度”。我建议你不要让你的游戏逻辑依赖于设定的时间片(即1/100秒)。使其依赖于当前帧时间(以及最后一帧时间,因为您不知道当前帧将渲染多长时间。)

通常我会写下面的内容(我写的是极大简化):

float Frametime = 1.0f / 30.0f;
while(1) {
    game_loop(Frametime);      // maniuplate objects, etc.
    render_loop();             // render the frame
    calculate_new_frametime();
}

其中Frametime是当前帧所采用的计算帧时间。当您处理游戏循环时,您正在使用前一帧的帧时间(因此将初始值设置为合理的值,例如1/30或1/15秒)。在前一个帧时间运行它足够接近,可以获得所需的结果。使用该时间范围运行游戏循环,然后渲染您的东西。您可能必须更改游戏循环中的逻辑以不假设固定的时间间隔,但通常这些类型的修复非常简单。

异步游戏/渲染循环可能是您最终需要的东西,但这是一个难以解决的问题。它涉及对象及其相关数据的快照,将这些快照放入缓冲区,然后将缓冲区传递给渲染引擎。该内存缓冲区必须在关键部分周围正确分区,以避免在渲染循环从中读取时游戏循环写入它。在传递给渲染循环之前,您必须注意确保将所有相关数据复制到缓冲区中。此外,您还必须编写逻辑来停止游戏或渲染循环,同时等待其中一个完成。

这种复杂性是我建议首先以更连续的方式编写它的原因(除非您有经验,否则可能)。原因是首先以“简单”的方式进行操作将迫使您了解代码的工作原理,渲染引擎的工作原理,渲染引擎需要的数据类型等。复杂的游戏开发中绝对需要多线程知识如今,但知道如何做好,需要深入了解游戏系统如何相互作用。

答案 1 :(得分:1)

核心游戏逻辑的运行速度远远低于玩家可以响应的速度。关于它唯一真正有用的时间是物理模拟,在快速,固定的时间步长运行可以使SIM表现得更加一致。

除此之外,只需每帧更新一次游戏循环,并传入可变时间增量而不是依赖于固定时间。与成本相比,您在多线程中获得的好处很小,特别是如果这是您的第一场比赛。

答案 2 :(得分:0)

双重缓冲可渲染对象是您可以探索的方法。意思是,渲染组件使用1个缓冲区,当所有游戏操作都更新了第二个缓冲区中的相关对象时,该缓冲区会更新。

但就我个人而言,我不喜欢它,而且(经常)采用马克的方法。