将游戏服务器线程循环限制为 30FPS,而无需游戏引擎/渲染窗口

Limit a Game Server Thread loop to 30FPS without a game engine/rendering window

本文关键字:游戏 引擎 窗口 30FPS 循环 线程 服务器      更新时间:2023-10-16

我会尽量轻松地解释这一点。

我基本上有一个举办多场比赛的游戏。服务器上的所有比赛都由服务器处理,没有玩家通过端口转发在他们的计算机上托管比赛,这一切都由服务器完成,所以他们不必这样做。

当玩家请求进行匹配时,将在服务器上创建具有线程的匹配对象。这工作正常。每个比赛对象都有自己的玩家列表。但是,游戏客户端以 30FPS 运行,并且需要与服务器同步,因此仅更新线程循环中的所有玩家是行不通的,因为它不以 30FPS 运行。

我现在正在做的是我使用一个游戏引擎:SFML,它在其窗口循环中遍历服务器中的所有玩家,并以 30FPS 的速度运行它们的更新代码。但是,这很好,当有一天他们可能是一大块人时,最好通过匹配线程更新玩家,以免在一个渲染循环中完成所有操作来减慢处理速度。

我想知道的是,如何在比赛的线程循环中模拟 30FPS?基本上,每个玩家的 update() 函数都可以在 30FPS 的时间范围内调用,而不必使用 SFML 等渲染引擎来限制代码的运行速度?代码在后台运行,输出显示在控制台上,不需要在服务器上呈现。

或者简单地说,如何在没有游戏引擎的情况下将 while 循环代码限制为 30FPS 运行?

似乎有点像X Y问题:您尝试通过服务器"FPS"限制同步播放器。服务器端并不是那样工作的。

服务器通过向客户端

传递每个包上的服务器时间或通过特定包(换句话说,所有客户端只有服务器的时间)在时间方面与客户端同步。

但是关于游戏的服务器端实现:

这个问题比你提到的要广泛一些。我将发布一些指南,希望对您的研究有所帮助。

首先,在服务器上你不需要渲染,所以FPS是无关紧要的(需要30 fps才能给我们的眼睛带来流动性的感觉)。服务器通常处理逻辑,例如各种事件(例如有人发射火箭,或生成新的敌人)。如您所见,事件不需要 FPS,它们是随机触发的。

在服务器上完成的其他操作是物理(或其他玩家-玩家或玩家-环境交互)。冲突是使用固定的更新步骤完成的。例如,物理通常以 20 FPS 计算。移动物体获得胶囊碰撞器,以便正确模拟交互。换句话说,服务器虽然不渲染任何东西,但负责移动/碰撞(这意味着如果您没有连接到服务器,您将不会移动/穿过墙壁等 - 取决于实现)。

现代游戏也有预测,以减少滞后(毕竟,在你给你的角色任何输入之后,输入需要首先到达服务器,被处理并被接收回来,以便对客户端产生任何影响)。这意味着当您在客户端上有输入时(让我们以移动为例),客户端开始在预期中进行操作,并且当服务器响应到来时(对于我们的示例新位置),它将被视为更正。这就是为什么有时在游戏中,当您有滞后时,您会感觉到自己正在朝着某个方向移动,然后突然之间,您就完全不同了。

关于您的问题:

在你的 while 循环中,创建一个 deltaT ,如果该 deltaT 小于 33 毫秒,请使用 sleep(33-deltaT)。

根据您的要求,我发布了 deltaT 代码的示例:

 while (gameIsRunning)
 {
      double time = GetTickCount();
      UpdateGame();
      double deltaT = GetTickCount()-time;
      if (deltaT < 33 )
      {
          sleep(33- deltaT);
      }
 }

其中gameIsRunning是全局布尔值,UpdateGame是你的游戏更新函数。

请注意,上面的代码适用于Windows。对于 linux,您将需要其他函数而不是 GetTicksCount 和睡眠。