Unity Netcode ServerRpc仅在客户端执行?销毁对象报错排查
问题分析与解决方案
首先纠正你的误解:TestServerRpc绝对是在服务器端执行的,不是客户端。报错的核心原因是:服务器端对应的PlayerController实例里的spawnedObjectTransform变量根本没被赋值。
为什么会出现这个问题?
- 当主机(同时是服务器+客户端)按空格时,是在服务器端的
PlayerController里执行Instantiate并给spawnedObjectTransform赋值,所以后续调用TestServerRpc时,服务器能拿到这个引用销毁对象。 - 当客户端按空格时,你是在客户端本地的
PlayerController实例里执行Instantiate,然后通过Spawn(true)同步对象到服务器,但服务器端对应的PlayerController实例的spawnedObjectTransform并没有被设置——客户端的Update逻辑只在本地运行,服务器端的PlayerController不会执行客户端的输入代码。 - 当客户端按Y键调用
TestServerRpc,这个Rpc跑到服务器端执行时,服务器端的spawnedObjectTransform是空的,自然会报未实例化的错误。
正确的修改方案
要让服务器端能持有生成对象的引用,同时同步给客户端,推荐让服务器负责生成逻辑,再同步引用到客户端:
public class PlayerController : NetworkBehaviour { public GameObject spawnPrefab; private NetworkObject _spawnedObject; void Update() { if (!IsOwner) return; if (Input.GetKeyDown(KeyCode.Space)) { // 让服务器生成对象 SpawnObjectServerRpc(); } if (Input.GetKeyDown(KeyCode.Y)) { // 先判断本地引用是否存在,避免无效调用 if (_spawnedObject != null) { DestroyObjectServerRpc(); } } } [ServerRpc(RequireOwnership = false)] private void SpawnObjectServerRpc() { GameObject newObj = Instantiate(spawnPrefab); _spawnedObject = newObj.GetComponent<NetworkObject>(); _spawnedObject.Spawn(true); // 把生成的对象同步给所有客户端的PlayerController SyncSpawnedObjectClientRpc(_spawnedObject); } [ClientRpc] private void SyncSpawnedObjectClientRpc(NetworkObject obj) { _spawnedObject = obj; } [ServerRpc(RequireOwnership = false)] private void DestroyObjectServerRpc() { if (_spawnedObject != null) { Destroy(_spawnedObject.gameObject); _spawnedObject = null; // 同步清空客户端的引用 ClearSpawnedObjectClientRpc(); } } [ClientRpc] private void ClearSpawnedObjectClientRpc() { _spawnedObject = null; } }
方案说明
- 客户端按空格时,不再本地生成对象,而是调用
SpawnObjectServerRpc让服务器负责实例化,确保服务器端的_spawnedObject能拿到引用。 - 服务器生成对象后,通过
SyncSpawnedObjectClientRpc把对象的NetworkObject同步给所有客户端,让客户端的PlayerController也持有有效引用。 - 销毁时,客户端调用
DestroyObjectServerRpc,服务器用自己持有的引用销毁对象,再同步清空客户端的引用,避免后续无效调用。
内容的提问来源于stack exchange,提问作者agentsmith200
相关产品推荐
相关产品推荐

