如何在Unity中使用MLAPI为本地、远程客户端生成不同prefab?
现有代码的核心问题
- 执行上下文逻辑错误:
ApprovalCheck是仅在服务端运行的回调,执行时对应clientId的客户端还未完成连接流程,NetworkManager.Singleton.ConnectedClients[clientId].PlayerObject尚未初始化,直接访问会触发空引用异常,也不可能通过IsLocalPlayer判断属性。 - 字节数组比较逻辑错误:直接用
==比较两个字节数组是对比内存地址而非存储内容,即使连接数据确实传输了xd,该判断也会永远返回false,导致所有连接被拒绝。 - 重复生成玩家对象:手动调用
SpawnAsPlayerObject生成玩家的同时,callback中的createPlayerObject参数传了true,会导致MLAPI额外生成一个默认玩家预制体,出现重复玩家对象问题。 - 判断逻辑因果倒置:
IsLocalPlayer是玩家对象成功生成后才会赋值的属性,在生成玩家之前就调用该属性判断要使用的预制,逻辑完全不成立。 - 设计思路误区:MLAPI的网络对象是全局同步的,服务端生成的对象会同步到所有客户端,无法在服务端为不同客户端生成不同的玩家预制,该区分逻辑需要放在客户端侧执行。
正确实现方案
推荐采用「服务端统一生成基础预制+客户端侧按需启用专属组件」的方案,无需维护两套预制体,逻辑更易维护:
- 统一使用一套玩家预制,预制上默认禁用相机、FPS移动脚本、PlayerInput组件
- 修正
ApprovalCheck逻辑 - 在玩家预制上挂载初始化脚本,客户端侧根据
IsLocalPlayer状态处理组件启用逻辑
修正后的 ApprovalCheck 代码
private void ApprovalCheck(byte[] connectionData, ulong clientId, MLAPI.NetworkManager.ConnectionApprovedDelegate callback) { // 修正字节数组比较逻辑 bool approve = System.Text.Encoding.ASCII.GetBytes("xd").SequenceEqual(connectionData); // 关闭MLAPI自动生成玩家逻辑,手动控制生成 bool createPlayerObject = false; // 回调返回连接审批结果 callback(createPlayerObject, null, approve, positionToSpawnAt, Quaternion.identity); if (approve) { // 连接通过后服务端生成统一的基础玩家预制 serverPlayerPrefab.GetComponent<NetworkObject>().SpawnAsPlayerObject(clientId); } }
客户端侧玩家初始化脚本
将该脚本挂载到玩家预制上即可:
public class PlayerInit : NetworkBehaviour { // 提前在Inspector中赋值预制上对应组件,默认设置为禁用状态 [SerializeField] private Camera playerCamera; [SerializeField] private MonoBehaviour fpsMoveController; [SerializeField] private PlayerInput playerInput; public override void OnNetworkSpawn() { base.OnNetworkSpawn(); // 仅客户端侧执行初始化逻辑 if (!IsClient) return; if (IsLocalPlayer) { // 本地玩家启用专属组件 playerCamera.enabled = true; fpsMoveController.enabled = true; playerInput.enabled = true; } else { // 远程玩家销毁不需要的本地专属组件 Destroy(playerCamera.gameObject); Destroy(fpsMoveController); Destroy(playerInput); } } }
内容的提问来源于stack exchange,提问作者circles.png
相关产品推荐
相关产品推荐

