我正在制作多人游戏,并在代码中制作拾取和放下物品。我遇到了一个错误,在我为 player 添加子级并添加另一个子级后,player.transform.childCount 返回 3。
我尝试添加一些 debug.log,输出在客户端“3:1”和“3”,在主机端输出“4:0”,因此在主机端一切正常,但在客户端它返回了错误的值
感谢任何答案
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");
}
客户端:
主办方方面:
就像 @Risord 在评论中提到的那样,RPC 调用实际上并不是方法调用。网络库使它看起来像一个普通方法,但事实并非如此。当您
AddItemToHandServerRpc
在客户端调用方法时,您实际上会向服务器发送网络消息。这需要时间。一旦服务器收到该消息,就会在服务器上调用实际方法。服务器将在其端实例化该对象并将其作为子对象添加到玩家对象。然而这里还隐藏着额外的魔法。
NetworkObject
当实例化时,它会自动向所有客户端发送 RPC 调用,让它们也在它们那边创建模拟对象。此外,该TrySetParent
调用还会向所有客户端发送另一个 RPC,告诉它们父级更改。只有当这些来自服务器的 RPC 到达并被客户端处理后,实际对象才会成为玩家的子级。客户端的代码不会等待服务器的潜在答案。一旦 RPC 排队,您的
AddItem
方法将在 RPC 调用后继续。此时客户端上尚未创建任何对象,因为服务器很可能尚未收到 RPC。如果您有重要的代码需要按照特定的事件序列发生,您可以让服务器向客户端发送自定义 RPC,以便在创建对象后继续执行您想要执行的任何操作。
可能可以创建一些异步构造来调用 RPC 并等待您的返回/确认 RPC 以便继续在客户端上运行。但据我所知,目前 Netcode 中还没有内置任何内容。
也许您可以使用一些通用的“响应” RPC,并使用某种“票号”来识别已完成的事件。这样就可以创建一个通用的“回调” RPC,服务器可以调用它来完成/确认任务的完成,并且可能让它也返回一些通用的返回值。正如这里所解释的,您可以使用
ClientRpcParams
它来仅向一个客户端发送ClientRPC
。