5

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

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

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

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

但是,我认为“正确”的方法是使用多线程。有一个单独的线程运行 'gamelogic()' 100 次/秒。

问题是,我如何实现这一点以及当 2 个单独的线程之间存在冲突时可以做什么:gamelogic 更改屏幕内容(3d 对象坐标),而 Ogre 同时渲染屏幕。

提前谢谢了。

4

3 回答 3

7

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

正如您正确指出的那样,渲染时间会极大地影响游戏的“速度”。我建议你不要让你的游戏逻辑依赖于设定的时间片(即 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 秒)。在前一帧时间运行它足够接近以获得所需的结果。使用那个时间框架运行你的游戏循环,然后渲染你的东西。您可能必须更改游戏循环中的逻辑以不假定固定的时间间隔,但通常这些修复非常容易。

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

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

于 2009-05-28T14:16:54.880 回答
1

您的核心游戏逻辑运行速度快于玩家的响应速度并没有太多好处。唯一真正有用的是物理模拟,以快速、固定的时间步长运行可以使模拟的行为更加一致。

除此之外,只需每帧更新一次游戏循环,并传入可变时间增量,而不是依赖固定时间增量。与成本相比,您从多线程中获得的好处是微乎其微的,尤其是如果这是您的第一款游戏。

于 2009-09-05T09:13:45.377 回答
0

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

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

于 2009-09-05T09:05:35.503 回答