Unity:如何通过网络销毁游戏对象?

Posted

技术标签:

【中文标题】Unity:如何通过网络销毁游戏对象?【英文标题】:Unity: How to destroy a gameobject through network? 【发布时间】: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? @Programmer 是的。 support.unity3d.com/hc/en-us/articles/… 不知道。就在我真正学习它的过程中,它被弃用了……对于 OP,我建议你使用 Photon。它已经存在很长时间了,我认为它不会很快消失。 【参考方案1】:

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

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

【讨论】:

【参考方案2】:

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

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

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

    由于本地玩家对象始终拥有对其自身和附加组件的权限,因此将[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;
    
    

    稍后在需要执行破坏的其他脚本中的某个地方执行类似的操作

    // 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

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

【讨论】:

以上是关于Unity:如何通过网络销毁游戏对象?的主要内容,如果未能解决你的问题,请参考以下文章

unity3d通过代码动态创建销毁游戏对象

Unity (C#) - 如何在销毁/重生系统中挑选出被 Raycast 检测到的 GameObject

(统一)销毁当前场景中的游戏对象并在加载当前场景后使其永久销毁?

unity_实用小技巧(避免游戏对象被销毁时声音消失)

unity_小功能实现(避免游戏对象被销毁时声音消失)

Unity3D 对象池思想 在游戏开发中的运用