游戏逻辑的异步屏幕更新,C++
Posted
技术标签:
【中文标题】游戏逻辑的异步屏幕更新,C++【英文标题】:Asynchronous screen update to gameplay logic, C++ 【发布时间】:2009-05-28 13:24:42 【问题描述】:我正在使用 Visual C++ 2008 Express 和 Ogre3D sdk 编写游戏。
我的核心游戏逻辑设计为每秒运行 100 次。为简单起见,我会说这是一个名为“gamelogic()”的方法。它不是基于时间的,这意味着如果我想“提前”游戏时间 1 秒,我必须调用 'gamelogic()' 100 次。 'gamelogic()' 与游戏的屏幕渲染相比是轻量级的。
Ogre 有一个“侦听器”逻辑,当它即将绘制一个框架以及何时完成绘制一个框架时,它会通知您的代码。如果我只是在帧渲染之前调用'gamelogic()',那么游戏玩法会受到屏幕渲染速度的很大影响,屏幕渲染速度可能从5fps到120fps不等。
想到的简单解决方案是:计算自上一帧渲染以来经过的时间,并在下一帧之前多次调用“gamelogic()”:100 * timeElapsedInSeconds
但是,我认为“正确”的方法是使用多线程;有一个单独的线程运行 'gamelogic()' 100 次/秒。
问题是,我如何实现这一点以及当 2 个独立线程之间存在冲突时可以做什么:gamelogic 更改屏幕内容(3d 对象坐标),而 Ogre 同时渲染屏幕。
非常感谢。
【问题讨论】:
【参考方案1】:如果这是您的第一个游戏应用程序,那么使用多线程来实现您的结果可能比您在第一个游戏中真正应该处理的工作要多。在不同的线程中同步一个游戏循环和渲染循环并不是一个容易解决的问题。
正如您正确指出的那样,渲染时间会极大地影响游戏的“速度”。我建议你不要让你的游戏逻辑依赖于设定的时间片(即 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 秒)。在前一帧时间运行它足够接近以获得所需的结果。使用那个时间框架运行你的游戏循环,然后渲染你的东西。您可能需要更改游戏循环中的逻辑以不假定固定的时间间隔,但通常这些修复非常容易。
异步游戏/渲染循环可能是您最终需要的东西,但这是一个难以解决的问题。它涉及获取对象及其相关数据的快照,将这些快照放入缓冲区,然后将缓冲区传递给渲染引擎。该内存缓冲区必须围绕关键部分正确分区,以避免在渲染循环正在读取它时让游戏循环写入它。在传递给渲染循环之前,您必须注意确保将所有相关数据复制到缓冲区中。此外,您必须编写逻辑来停止游戏或渲染循环,同时等待其中一个或另一个完成。
这种复杂性是我建议首先以更连续的方式编写它的原因(除非你有经验,你可能会这样做)。原因是首先以“简单”的方式进行操作会迫使您了解代码的工作原理,渲染引擎的工作原理,渲染引擎需要什么样的数据等。复杂的游戏开发肯定需要多线程知识这些天来,但要知道如何做好它需要深入了解游戏系统如何相互交互。
【讨论】:
不久前,游戏从固定渲染速率假设切换到跟踪帧时间 - 他们过去依赖于知道处理器以 8 Hz 运行。当他们推出 16Hz 机器时,他们包括一个“涡轮按钮”,可以将处理器从 16Hz 切换到 8Hz,这样游戏仍然可以以正确的速度运行。有趣的事实。 确实!甚至有一些小型应用程序被编写来“减慢”你的处理器,以便旧游戏可以在新机器上以可接受的帧速率运行。我想一个叫“MOslo”。我记得我所有的旧 Ultima 游戏在我拥有的新电脑上运行速度都太快了。 使用 turbo pascal 运行时效果更好,在快速机器上运行时会产生整数溢出,从而导致一切崩溃。 附议..不要按照您描述的方式做,按照这个答案的方式做!使用线程和固定时间是否有任何实际理由?【参考方案2】:你的核心游戏逻辑运行速度快于玩家的响应速度并没有太多好处。唯一真正有用的是物理模拟,在这种情况下以快速、固定的时间步长运行可以使模拟的行为更加一致。
除此之外,只需每帧更新一次游戏循环,并传入一个可变的时间增量,而不是依赖于固定的时间增量。与成本相比,您从多线程中获得的好处是微乎其微的,尤其是如果这是您的第一个游戏。
【讨论】:
【参考方案3】:双缓冲可渲染对象是您可以探索的一种方法。意思是,渲染组件正在使用 1 个缓冲区,当所有游戏动作都更新了第 2 个缓冲区中的相关对象时,该缓冲区就会更新。
但我个人不喜欢它,我会(并且经常)采用 Mark 的方法。
【讨论】:
以上是关于游戏逻辑的异步屏幕更新,C++的主要内容,如果未能解决你的问题,请参考以下文章