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