【问题标题】:Unity: How to destroy a gameobject through network?Unity:如何通过网络销毁游戏对象?
【发布时间】:2019-04-10 00:30:55
【问题描述】:

我们正在 Unity 上构建实时战略游戏,并尝试通过网络破坏服务器和客户端上的游戏对象。 目前玩家可以随时销毁自己的物品,服务器可以销毁所有物品。但是,当客户端尝试销毁服务器(或其他客户端)的对象时,它只会在该客户端上被销毁。 (因为客户端既没有权限也没有对象是LocalPlayer)

我们尝试了不同的方法:

1。使用 Destroy(gameObject)

这显然行不通,因为它只会在本地被销毁。

2。使用 NetworkServer.Destroy(gameObject)

这失败了,因为我们没有权限。

3。使用命令销毁对象

当我们尝试在我们销毁对象的服务器上调用命令时也会失败。由于权限检查:

试图在没有权限的情况下为对象发送命令。

4。首先分配权限

我们试图通过 GetComponent<NetworkIdentity>().AssignClientAuthority(connectionToClient); 但得到错误消息:

AssignClientAuthority 只能在服务器上调用生成对象。

由于第 3 点,尝试在命令中执行此操作将失败。

还有其他方法可以销毁游戏对象吗? 销毁游戏对象的方法是什么?

编辑:我们在运行时(在命令中)通过NetworkServer.SpawnWithClientAuthorityNetworkServer.Spawn 生成了大部分对象

【问题讨论】:

  • 您是否使用NetworkServer.Spawn 创建您要删除的对象?
  • 告诉服务器销毁任何东西。实际上,这个问题是我不喜欢 UNet 的原因之一,也是 Unity 弃用它并重新开始的原因之一。
  • @Draco18s Unity 真的弃用 uNet?
  • 不知道。就在我真正学习它的过程中,它被弃用了……对于 OP,我建议你使用 Photon。它已经存在很长时间了,我认为它不会很快消失。

标签: unity3d multiplayer game-development


【解决方案1】:

如何使用 (1) 并将每个客户端设置为对自己的游戏对象具有权限?那么您需要确保的就是让服务器在特定事件上通知每个客户端。

Here 是一个关于多人游戏的开放式问题,描述了它如何手动工作。通过让客户端监听服务器消息/RPC。

【讨论】:

    【解决方案2】:

    尽管UNet is going to end 很快(正如 Draco18s 已经提到的那样)到目前为止我会这样做:

    1. NetworkIdentity 添加到您希望能够通过网络销毁/识别的GameObject

    2. 如果它是您生成的预制件,请确保将其添加到 NetworkManager 中的可生成预制件中

    3. 由于本地玩家对象始终拥有对其自身和附加组件的权限,因此将[Command] 调用添加到本地玩家对象(而不是目标游戏对象)上的组件并使用@ 987654322@ 例如像

      public class NetworkObjectDestroyer : NetworkBehaviour
      {
          // Called by the Player
          [Client]
          public void TellServerToDestroyObject(GameObject obj)
          {
              CmdDestroyObject(obj);
          }
      
          // Executed only on the server
          [Command]
          private void CmdDestroyObject(GameObject obj)
          {
              // It is very unlikely but due to the network delay
              // possisble that the other player also tries to
              // destroy exactly the same object beofre the server
              // can tell him that this object was already destroyed.
              // So in that case just do nothing.
              if(!obj) return;
      
              NetworkServer.Destroy(obj);
          }
      }
      

      提示:您也可以添加它以便于访问,因为您确定您只需要访问其中一个组件(即您的本地播放器):

      public static NetworkObjectDestroyer Instance;
      
      private void Awake()
      {
          // skip if not the local player
          if(!isLocalPlayer) return;
      
          // set the static instance
          Instance = this;
      }
      
    4. 稍后在需要执行破坏的其他脚本中的某个地方执行类似的操作

      // that you would have to get somewhere if not anyway 
      // calling from a component of the local player object
      GameObject playerObject;
      
      // wherever you get your target object from
      GameObject targetObject;
      
      playerObject.GetComponent<NetworkObjectDestroyer>().TellServerToDestroyObject(targetObject);
      

      如果你之前添加了静态实例会更容易。比你可以简单地使用

      NetworkObjectDestroyer.Instance.TellServerToDestroyObject(targetObject);
      

      无需先获取参考资料。

    【讨论】:

    • 这实际上不是我们希望的答案。但是使用另一个 SyncVar,我们能够成功地实施这种方法。
    【解决方案3】:

    直接来自统一文档:

    地方当局 本地权限(有时称为客户端权限)意味着本地客户端对特定的联网游戏对象具有权威控制。这与服务器对联网游戏对象具有权威控制的默认状态形成对比。

    除了isLocalPlayer****,你可以选择让玩家GameObjects拥有“本地权限”。这意味着其所有者客户端上的玩家 GameObject 对其自身负责(或对其拥有权限)。这对于控制运动特别有用;这意味着每个客户端都有权控制自己的玩家 GameObject 的控制方式。

    要在 GameObject 上启用本地玩家权限,请勾选 Network Identity 组件 的本地玩家权限复选框。 Network Transform 组件使用此“权限”设置,如果设置了此设置,则将移动信息从客户端发送到其他客户端。

    请参阅有关 NetworkIdentity 的脚本 API 参考文档 和 localPlayerAuthority 获取有关通过脚本实现本地玩家权限的信息。

    see here

    您只需要设置一些东西就可以了!

    【讨论】:

      猜你喜欢
      • 2018-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-30
      • 1970-01-01
      相关资源
      最近更新 更多