多人游戏同步化

7

情况:

我想请教在多人在线1:1游戏中使用BT或Web服务器同步对象的最佳逻辑。游戏有两个玩家,每个玩家都有多个枪和子弹,子弹是动态创建的,并在一段时间后消失,玩家可以同时移动物体。

问题:

我在同步方面遇到了真正的问题,因为一个设备上的子弹可能比另一个设备上的快,而且它们可能已经在一个设备上消失或击中了一个物体,而在另一个设备上仍然在空中。

可能性?

在这种情况下,处理同步的最佳方式是什么?所有对象是否应该由充当服务器的一个设备控制,而另一个设备只获取值、位置并进行非常少的思考?还是应该分配控制权,让每个设备创建、销毁和移动自己的对象,然后通过同步告诉另一个设备。

如何处理传输延迟?因为BT可能比通过网络播放更快。

最好提供一个可工作的示例 - 非常感谢!

2个回答

10

您似乎已经开始考虑同步的好方法,但有可能您遇到了两个问题,导致它们重叠在一起:游戏时钟的同步和游戏状态的同步。

(1) 同步游戏时钟 对于您的游戏,您需要一些表示“游戏时间”的方式。对于两个玩家的游戏,简单地指定一个人为权威是非常合理的。

所以,在权威客户端上:

OnUpdate()
  gameTime = GetClockTime();
  msg.gameTime = gameTime
  SendGameTimeMessage(msg);

在另一端,客户端可能是这样的:

OnReceivGameTimeeMessage(msg)
 lastGameTimeFromNetwork = msg.gameTime;
 lastClockTimeOfGameTimeMessage = GetClockTime();

OnUpdate()
 gameTime = lastGameTimeFromNetwork + GetClockTime() - lastClockTimeOfGameTimeMessage;

还有一些复杂情况,比如跳过/滑动(例如从网络获取的时间前进/后退太多),需要进一步处理,但希望你能理解。如果需要,请提出另一个问题。

注意:此示例不区分“刻”和“秒”,也不与您的网络协议或游戏运行的设备类型相关联(除了要求“设备具有本地时钟”)。

(2)同步游戏状态

在获得一致的游戏时钟之后,您仍然需要解决如何一致地模拟和传播游戏状态的问题。同步游戏状态有几种选择:

异步

  • 每个游戏状态单元都由一个进程“拥有”。只允许该进程更改该游戏状态。这些更改传播到所有其他进程。
  • 如果所有内容都由单个进程拥有,则通常称为“客户端/服务器”游戏。
  • 请注意,使用此模型,每个客户端在任何时间都会有不同的游戏世界视图。
  • 示例游戏:quake、魔兽世界

为了优化带宽和隐藏延迟,您通常可以对高频更新字段进行一些本地模拟。例如:

drawPosition = lastSyncPostion + (currentTime - lastSyncTime) * lastSyncVelocity
当然,你需要将新信息与模拟版本协调一致。
同步:
- 每个游戏状态单位在所有进程中都是相同的。 - 每个进程的命令都会在它们期望的启动时间(将来的某个时刻)传播到彼此。 - 在其最简单的形式中,一个进程(通常称为主机)发送特殊消息表示何时推进游戏时间。当每个人都收到该消息时,他们可以模拟游戏到该点。 - “将来”的要求导致输入命令和游戏状态更改之间的延迟很高。 - 在类似文明这样的非实时游戏中,这是可以接受的。在像星际争霸这样的游戏中,通常发出确认输入的声音立即响起,但实际游戏状态产生影响的行动会有所延迟。这种方式不适合需要时间敏感动作(在约100毫秒的尺度上)的射击游戏等。
同步重演:
- 每个游戏状态单位在所有进程中都是相同的。 - 每个进程都会将其输入与当前时间戳发送给所有其他进程。此外,定期发送“没有发生任何事情”的消息。 - 每个进程都有两份游戏状态副本。 - 游戏状态副本1会传播到它从所有其他客户端收到的“最早消息”的时间点。这相当于同步模型,但其缺点是它代表了“一段时间以前”的游戏状态。 - 游戏状态副本2是副本1加上所有剩余的消息。它是当前客户端上游戏状态在当前时间的预测,假设不会发生任何新的事情。 - 玩家与两种游戏状态之一进行交互(理想情况下是100%的副本2,但必须考虑一些因素来避免新消息的出现)。 - 例如的游戏:《街头霸王4》(网络对战)。
根据你的描述,选项(1)和(3)似乎适合你的问题。如果有进一步的问题或需要更多细节,请提出跟进问题。

游戏时钟的解释对我来说很清楚。如果我理解正确,你基本上是将服务器时间发送到客户端,以便客户端相应地调整其游戏时间。如果这发生在蓝牙或本地网络上,则可以忽略同步消息从服务器到客户端所需的时间。例如,如果服务器的时间为123->发送到客户端->客户端也可以将自己的时间设置为123(如果所有操作都在同一方法中完成,则可以忽略接收服务器时间和更新自己时间之间的延迟)。这是正确的吗? - user387184
我的剩下的问题是,这个能在苹果的GameCenter上运行吗?从苹果GameCenter的介绍中,我了解到他们有一个版本的GKtank可以通过GameCenter运行。但是如果两个玩家之间的消息需要更长时间才能同步,他们如何进行同步呢?游戏会暂停吗?再次感谢。 - user387184

1
由于不同设备上的子弹速度可能会有所不同,如果游戏架构得当,这种情况是不应该发生的。如今大多数游戏(尤其是多人游戏)都基于小时间片段进行操作。每个系统在计算一次时间片段中发生了什么时,应该得到 完全相同 的结果,而不会出现“在某台机器上子弹移动得比另一台机器上更快”的问题。
然后就可以更简单地确保每个系统为每个玩家提供相同的输入(需要向其他每个玩家广播每个玩家的输入以及输入在哪个时间片段中注册),并确保每个系统以相同的速率计算时间片段。

不幸的是,使用ticks并不能消除同步的要求。即使是GKTank和punchball这两个示例也需要同步它们的2个对象 - 如果没有同步调用,它们很容易失去同步。但是,扩展那里使用的方法在我的情况下不起作用,因为我有太多的对象... - user387184

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接