UNET客户端加入时触发‘未将对象引用设置到对象实例’错误求助
解决UNet客户端相机设置的空引用问题
嘿,刚上手UNet确实容易踩网络同步的坑,我来帮你拆解这个Object reference not set to an instance of an object的问题~
问题根源分析
从你描述的情况来看,服务器端运行正常,但客户端加入时触发空引用,大概率是这两个原因:
- 服务器发送
RpcSetCamera的时机太早,客户端的Player预制体还没完成网络同步,导致你代码里的go对象在客户端是null; - 相机对象的同步逻辑有问题——相机是本地视角资源,没必要让服务器同步给所有客户端,强行同步反而容易出现引用丢失。
针对性解决方案
我给你整理了几个靠谱的修复步骤,按顺序来:
1. 调整客户端逻辑触发时机,依赖生命周期更可靠
服务器不要在生成Player后立刻发RPC,而是利用UNet的客户端生命周期函数,等Player在本地同步完成后再执行相机设置:
// Player脚本中的客户端生命周期函数 public override void OnStartClient() { base.OnStartClient(); // 只有当前客户端的本地玩家才执行相机设置 if (isLocalPlayer) { SetupPlayerCamera(); } }
2. 客户端本地生成相机,彻底避免同步问题
相机是每个客户端独有的视角资源,完全可以在客户端本地创建,不用依赖服务器同步,这能从根源杜绝空引用:
// 客户端本地执行的相机设置函数 void SetupPlayerCamera() { // 当前对象就是本地玩家,直接使用即可(OnStartClient触发时对象已完成同步) GameObject localPlayer = gameObject; // 实例化相机预制体(注意:相机预制体不要加NetworkIdentity组件,不需要同步) GameObject playerCamera = Instantiate(CameraPrefab); // 设置相机为玩家子对象并调整位置角度 playerCamera.transform.SetParent(localPlayer.transform); playerCamera.transform.localPosition = new Vector3(0, 2.5f, -6f); // 根据你的需求调整 playerCamera.transform.localEulerAngles = new Vector3(15f, 0, 0); // 启用玩家相机并关闭场景默认相机 playerCamera.GetComponent<Camera>().enabled = true; if (Camera.main != null) Camera.main.enabled = false; }
3. 若必须用RPC触发,一定要加空引用防护与重试
如果业务需求必须通过RPC触发相机设置,一定要加空判断和重试逻辑,防止客户端对象未同步完成:
[ClientRpc] void RpcSetCamera() { // 通过NetworkClient获取本地玩家对象,不要直接用服务器传来的引用 GameObject localPlayer = NetworkClient.connection?.playerController?.gameObject; if (localPlayer == null) { Debug.LogWarning("本地玩家未同步完成,100ms后重试相机设置"); Invoke(nameof(RpcSetCamera), 0.1f); return; } // 后续相机挂载逻辑 GameObject camera = Instantiate(CameraPrefab); camera.transform.SetParent(localPlayer.transform); // ...其他相机参数设置 }
关键注意点
- 确保Player预制体的
NetworkIdentity组件勾选了Local Player Authority,这样客户端才能正确获取本地玩家的控制权; - 相机预制体不要添加
NetworkIdentity组件,它是客户端本地资源,不需要同步给其他玩家; - 优先使用UNet的生命周期函数触发客户端逻辑,比手动发送RPC更稳定可靠。
内容的提问来源于stack exchange,提问作者Oham
相关产品推荐
相关产品推荐

