player.transform.childCount 返回 3,但应该返回 4

问题描述 投票:0回答:1

我正在制作多人游戏,并在代码中制作拾取和放置物品。我遇到错误,在我在player下添加另一个孩子后,player.transform.childCount立即返回3。

我尝试添加一些debug.log,输出在客户端“3:1”和“3”,在主机端输出“4:0”,所以在主机端是everiting好的,但在客户端它返回错误的值

感谢您的回答

    public void AddItem(ItemData itemData)
    {
        if(itemData == null)
            return;

        this.itemData = itemData;

        icon.sprite = itemData.icon;
        icon.enabled = true;

        if (player == null)
            player = NetworkManager.Singleton.SpawnManager.GetLocalPlayerObject().gameObject;

        if (player != null)
        {
            NetworkObject networkObject = player.GetComponent<NetworkObject>();

            if (networkObject != null)
            {
                Debug.Log(player.transform.childCount + ": 1");
                AddItemToHandServerRpc(itemData.index, networkObject.NetworkObjectId);
                Debug.Log(player.transform.childCount);
                if (player.transform.childCount == 4)
                {
                    GameObject item = player.transform.GetChild(player.transform.childCount - 1).gameObject;
                    item.GetComponent<SetPossionToHand>().enabled = true;
                    item.transform.localScale = new Vector3(.01f, .01f, .01f);
                }
                else
                {
                    Debug.Log("fsjfhshuyferh");
                }
            }
            else
                Debug.Log("none");
        }
        else
        {
            Debug.LogError("Hand object is not properly initialized or is disabled.");
        }
    }

    public void ClearSlot(bool delete)
    {
        itemData = null;

        icon.sprite = null;
        icon.enabled = false;

        if (player.transform.childCount == 4 && delete)
        {
            if (player == null)
                player = NetworkManager.Singleton.SpawnManager.GetLocalPlayerObject().gameObject;
            GameObject item = player.transform.GetChild(player.transform.childCount - 1).gameObject;
            DespawnObjectServerRpc(item.GetComponent<NetworkObject>().NetworkObjectId);
        }
    }

    [ServerRpc]
    void AddItemToHandServerRpc(int index, ulong handId)
    {
        GameObject item = list.prefabs[index];
        var instance = Instantiate(item);
        var instanceNetworkObject = instance.GetComponent<NetworkObject>();

        Transform player = NetworkManager.Singleton.SpawnManager.SpawnedObjects[handId].gameObject.transform;

        instanceNetworkObject.SpawnWithOwnership(handId);

        instanceNetworkObject.TrySetParent(player, false);

        Debug.Log(player.transform.childCount + ": 0");
    }
unity-game-engine rpc multiplayer netcode
1个回答
0
投票

就像@Risord在评论中提到的那样,RPC调用并不是真正的方法调用。网络库使它看起来像一个普通的方法,但事实并非如此。当您在客户端调用

AddItemToHandServerRpc
方法时,您实际上向服务器发送了一条网络消息。这需要时间。一旦服务器收到该消息,就会在服务器上调用实际的方法。服务器将实例化他这边的对象并将其作为子对象添加到玩家对象中。

然而,这里还发生了额外的隐藏魔法。 A

NetworkObject
当它被实例化时,它会自动向所有客户端发送 RPC 调用,使它们也在自己的一侧创建模拟对象。此外,
TrySetParent
调用还将向所有客户端发送另一个 RPC,以告诉他们父级更改。只有当来自服务器的 RPC 到达并被客户端处理后,实际对象才会成为玩家的子对象。

客户端的代码不会等待服务器的潜在答案。一旦 RPC 排队,您的

AddItem
方法将在 RPC 调用后继续。此时客户端上还没有创建任何对象,因为服务器很可能还没有收到 RPC。

如果您有重要的代码需要发生特定的事件序列,您可以让服务器向客户端发送自定义 RPC,以便在创建对象后继续您想要执行的任何操作。

可能可以创建一些异步构造来调用 RPC 并等待您的返回/确认 RPC,以便在客户端上继续。但据我所知,目前 Netcode 中还没有内置任何内容。

也许您可以使用一些通用的“响应”RPC,并使用某种“票号”来标识已完成的事件。这样就可以创建一个通用的“回调”RPC,服务器可以调用它来完成/确认任务的完成,并且可能还返回一些通用的返回值。如此处所述,您可以使用

ClientRpcParams
仅向一个客户端发送
ClientRPC

© www.soinside.com 2019 - 2024. All rights reserved.