PUN2:这是否推荐用于刚体同步状态和碰撞?

PUN2: is this recommended for a rigidbody sync state and collision?

我已经很好地同步了我的 ridigbodies 但我只是注意到当一个客户端(不是主人)与一个它不会移动的碰撞时,它被锁定了,在网上阅读时我有一个想法什么时候对象与刚体碰撞 我只是暂时将该对象的所有权转移给该客户端,以便该客户端处理碰撞(我已经测试过它并且它工作得非常好,两个客户端完美同步)

这是推荐的吗?性能方面和 security/cheating 方面?

谢谢!

简答:

当客户端需要控制和更新对象数据时,将 GameObject 的所有权转让给客户端是可以的。在检测作弊可能性的情况下,始终让一个客户端(通常是主客户端或专用服务器)验证、更正并将数据同步到所有客户端。

我不会做任何假设。根据您对问题的解释,您的 GameObject Rigidbody IsKinematic 似乎没有同步,导致冲突在每个客户端产生不同的影响。但如果这可能不是问题,我有一个更长的答案,希望它能对这种情况或其他情况有所帮助。


更长的版本:

通过网络同步 Rigidibody 数据,这些数据基本上需要出现在客户端 GameObject 上。 Rigidbody 数据的其余部分可以在每个客户端上单独创建/计算/模拟:

  • 这样,您将确保 Rigidbody 的所有参数都是正确的(例如 isKinematic 在所有客户端上都是正确的 enabled/disabled)
  • 您的游戏将始终具有 create/simulate 其余事件和效果正常所需的最少数据,从而减少网络延迟并提高性能。
  • 在需要数据验证的地方,主客户将始终验证非主客户数据,做出重要的调整和决策,并在必要时为所有客户更新房间数据。这减少了玩家作弊的机会。
  • 当应该在每个客户端上发生的事件与预期不一致时,开发人员会更容易发现错误。这在多个事件应该同时发生在每个客户端上的场景中更常见。

更长的版本:

当我在我的游戏中的 GameObject 上使用 PUN2 时,我只同步 Rigidbody 那些 GameObject 要求 Rigidbody 值出现在客户端上执行特定任务的碰撞(例如,使用速度或方向进行动态 sound/visual 效果),或者当主服务器正在验证和纠正非主客户端所需的数据时(由于网络延迟或 cheat/hack 篡改客户端数据)。

使用 PUN2 时(截至目前),我会根据需要更新其 class 内部代码。例如,PhotonRigidbodyView 尚未同步 Rigidbodykinematic 状态。当我在游戏中需要这个时,我可以用 CustomPhotonRigidbodyView class 覆盖 class (and/or 稍微更新 PhotonRigidbodyView)。

使用PhotonRigidbodyView会影响性能吗? ,如果不小心使用,当有太多对象同时通过网络同步时,它确实会降低它。客户会看到锯齿状的运动。

是否允许作弊者利用这些数据,操纵它并将其发送给客户? ,如果游戏容易受到基本作弊的攻击。话又说回来,security/cheat检测的话题相当广泛,所以每个游戏对"basic"作弊的定义都是不同的。

暂时转让所有权以在客户端处理是个好主意吗? 在某些情况下是,其他情况下不:

  • 如果做这个瞬间转移是你做这件事的唯一地方并且它解决了你所有的问题(作弊除外),那么使用它这样你就不会花太多时间以不同的方式修复这一部分。
  • 如果 RigidbodyTransform 数据正在验证 and/or 由一个客户端持续或定期同步(以防止作弊或在关键时刻正确同步客户端数据)次),那么暂时转移也可以。
  • 我通常会转移所有权,当对象数据必须由客户端更改时(例如抓取/拖拽/射击/投掷)并且一旦执行了操作,所有权将返回给主控以进行验证和同步对于所有客户(包括刚刚转让所有权的客户)。这样可以将更多时间花在测试、捕获不需要的(可能是看不见的)错误上,并减少作弊的可能性。

如果开发您的游戏的开发人员尚未正确优化每个 GameObjectCollider and/or Rigidbody 组件,请确保您已经这样做了在通过网络同步他们的数据之前。 Unity 文档中的此页面可能是检查您的 GameObject 是否需要静态碰撞器或动态碰撞器的很好参考:

一旦识别出需要 Rigidbody 组件的 GameObject,您就可以决定哪些需要通过网络完全同步或部分同步 and/or 它们的所有权已转移需要时。

我希望我的回答不会让任何读者感到困惑。如果有什么不明白的地方,请在评论中指出,我会为您改进我的回答。



更新:2019-05-10(回复第2条评论):

对于涉及这么多 GameObject 个台球游戏,我不会将 所有 个对象的所有权转让给客户。我会:

  • 创建一个 struct 保存必要的信息,例如:
    • ball_id:表示台球棒正在击中哪个球
    • hit_info: a Vector3 表示击球杆击球的位置(在球面上)和方向。
    • hit_force: 施加到被击球杆击中的球的 Rigidbody 所需的力。
    • 以及当玩家用棍子击球时我可能需要的任何其他信息。
    • 然后我可以结合这些信息,将它们传递给球的RigidbodyAddForceAtPosition方法。
  • 将此 struct 发送到房间,供所有客户接收。
  • 一旦每个客户端(包括发送者)收到此消息(在 OnEvent 作为 EventData 包含 Phton Event Data),它会将此信息应用到正确的球并创建它自己的物理版本(每个客户端之间会注意到细微的差异)。

这样:

  • 我通过网络传递的信息量最少,可以在所有客户端上进行模拟
  • 通过避免解析和应用不必要的 Rigidbody 数据提高了游戏性能
  • 减少了客户在 table 周围或将不应该移动的任何其他球移动到彩池中的作弊可能性。

为了提高安全性并确保所有客户端上的球都在它们应该在的位置,例如主客户端将发送另一个 struct,指示确切位置(和旋转) 池中每个球 table(或底池中)。

我会定期(以预定义的时间间隔或根据游戏状态在我选择的特定时刻)将球位置同步给所有客户端,以克服游戏中任何时刻的任何错误位置。这种定期同步可以由主客户端或专用服务器完成。