目录
一、插件介绍
Unity插件-Mirror使用方法(一)Mirror介绍-优快云博客
二、主要组件
Unity插件-Mirror使用方法(二)组件介绍-优快云博客
Network Manager
Unity插件-Mirror使用方法(三)组件介绍(Network Manager)-优快云博客
Network Manager HUD
Unity插件-Mirror使用方法(四)组件介绍(Network Manager HUD)-优快云博客
Network Identity
Unity插件-Mirror使用方法(五)组件介绍(Network Identity)-优快云博客
Network Transform
Unity插件-Mirror使用方法(六)组件介绍(Network Transform)-优快云博客
Network Animator
Unity插件-Mirror使用方法(七)组件介绍(Network Animator)-优快云博客
Network Behaviour
Unity插件-Mirror使用方法(八)组件介绍(Network Behaviour)-优快云博客
Network Start Position
Unity插件-Mirror使用方法(九)组件介绍(Network Start Position)-优快云博客
Network Room Manager
Unity插件-Mirror使用方法(十)组件介绍(Network Room Manager)-优快云博客
三、Network Room Player
1、组件介绍
Network Room Player 是 Unity Mirror 中用于管理房间内玩家状态的核心组件,与 NetworkRoomManager
配合使用,负责同步玩家在房间中的信息(如准备状态、角色选择、队伍分配等)。每个加入房间的玩家都会生成一个 NetworkRoomPlayer
实例,作为其在大厅场景中的代表,直至游戏开始。
该组件用于在房间场景中为每个玩家存储状态信息。使用该组件时,需要编写允许玩家标记准备状态的脚本,通过设置ReadyToBegin属性来实现。
技术规范:
- 带有Network Room Player组件的游戏对象必须同时包含Network Identity组件
- 当创建Network Room Player组件时,若对象未包含Network Identity组件,Unity会自动创建
2、核心功能
-
玩家状态同步
-
通过
[SyncVar]
同步玩家名称、准备状态、队伍、角色皮肤等属性。 -
自动更新所有客户端的房间玩家列表,确保状态一致。
-
-
UI交互控制
-
处理本地玩家的准备/取消准备、角色选择等操作。
-
通过
[Command]
向服务器发送状态变更请求,并在服务器验证后同步。
-
-
生命周期管理
-
提供玩家加入、离开房间的回调方法(如
OnClientEnterRoom
、OnClientExitRoom
)。 -
在游戏开始时,将
RoomPlayer
替换为实际的游戏角色(GamePlayer
)。
-
-
权限管理
-
区分本地玩家与远程玩家,控制UI交互权限(如仅本地玩家可点击准备按钮)。
-
3、关键属性与配置
属性 | 说明 |
---|---|
显示房间GUI界面(Show Room GUI) | 启用开发者界面用于房间内玩家状态显示(默认开启,建议正式发布时禁用) |
准备状态(Ready To Begin) | 诊断性指示器,标识玩家是否已准备就绪 |
玩家索引(Index) | 诊断性标识,显示玩家序号(如玩家1、玩家2等) |
网络同步间隔(Network Sync Interval) | 控制玩家状态数据从客户端同步到服务器的频率(单位:秒) |
4、基础使用步骤
步骤1:创建房间玩家预制体
-
创建UI预制体(如
RoomPlayerPrefab
),包含玩家名称文本、准备状态图标、准备按钮等元素。 -
为预制体添加
NetworkRoomPlayer
组件(或继承自该组件的自定义脚本)。 -
将该预制体拖入
NetworkRoomManager
的 Room Player Prefab 属性。
步骤2:同步玩家状态
using UnityEngine;
using Mirror;
public class RoomPlayer : NetworkRoomPlayer {
[SyncVar(hook = nameof(UpdateNameDisplay))]
public string playerName = "Player";
[SyncVar(hook = nameof(UpdateReadyUI))]
public bool isReady;
public Text nameText;
public GameObject readyIcon;
// 本地玩家点击准备按钮
public void OnReadyButtonClick() {
CmdToggleReady();
}
[Command]
private void CmdToggleReady() {
isReady = !isReady;
}
// 客户端同步准备状态
private void UpdateReadyUI(bool oldValue, bool newValue) {
readyIcon.SetActive(newValue);
}
// 客户端同步名称
private void UpdateNameDisplay(string oldValue, string newValue) {
nameText.text = newValue;
}
// 服务器初始化时设置名称
public override void OnStartServer() {
playerName = "Player_" + Random.Range(100, 999);
}
}
步骤3:房间玩家生命周期回调
方法说明
客户端同步变量钩子方法
public virtual void IndexChanged(int oldIndex, int newIndex) { } // 当玩家索引变更时触发
public virtual void ReadyStateChanged(bool oldReadyState, bool newReadyState) { } // 当准备状态变更时触发
客户端虚拟方法
public virtual void OnClientEnterRoom() { } // 客户端进入房间时调用
public virtual void OnClientExitRoom() { } // 客户端退出房间时调用
[Obsolete("OnClientReady方法已弃用,请改用ReadyStateChanged同步变量钩子")]
public virtual void OnClientReady(bool readyState) {} // 准备状态变更回调(已废弃)
public class CustomRoomPlayer : NetworkRoomPlayer {
// 客户端进入房间时调用
public override void OnClientEnterRoom() {
Debug.Log($"{playerName} 进入房间");
}
// 客户端离开房间时调用
public override void OnClientExitRoom() {
Debug.Log($"{playerName} 离开房间");
}
// 本地玩家获得控制权时调用
public override void OnStartLocalPlayer() {
GetComponent<Button>().interactable = true; // 启用本地操作按钮
}
}
5、高级功能与场景
1. 角色选择系统
public class RoomPlayer : NetworkRoomPlayer {
[SyncVar(hook = nameof(UpdateCharacterIcon))]
public int selectedCharacterId;
public Image characterIcon;
public void OnCharacterButtonClick(int characterId) {
CmdSelectCharacter(characterId);
}
[Command]
private void CmdSelectCharacter(int characterId) {
selectedCharacterId = characterId;
}
private void UpdateCharacterIcon(int oldId, int newId) {
characterIcon.sprite = characterDatabase.GetIcon(newId);
}
}
2. 房主权限管理
public class RoomPlayer : NetworkRoomPlayer {
[SyncVar(hook = nameof(UpdateLeaderUI))]
public bool isLeader;
public GameObject kickButton;
private void UpdateLeaderUI(bool oldValue, bool newValue) {
kickButton.SetActive(newValue); // 仅房主显示踢人按钮
}
public void OnKickButtonClick(int targetPlayerId) {
if (isLeader) {
CmdKickPlayer(targetPlayerId);
}
}
[Command]
private void CmdKickPlayer(int targetPlayerId) {
// 根据ID找到对应连接并断开
foreach (var conn in NetworkServer.connections.Values) {
if (conn.identity.GetComponent<RoomPlayer>().Index == targetPlayerId) {
conn.Disconnect();
break;
}
}
}
}
3. 跨场景数据传递
public class RoomPlayer : NetworkRoomPlayer {
[SyncVar]
public int playerLevel;
[SyncVar]
public Color playerColor;
// 游戏开始时将数据传递给GamePlayer
public override void OnRoomServerSceneLoadedForPlayer(NetworkConnection conn, GameObject roomPlayer, GameObject gamePlayer) {
gamePlayer.GetComponent<GamePlayer>().playerLevel = roomPlayer.GetComponent<RoomPlayer>().playerLevel;
gamePlayer.GetComponent<GamePlayer>().playerColor = roomPlayer.GetComponent<RoomPlayer>().playerColor;
}
}
6、常见问题与解决
问题 | 解决方案 |
---|---|
准备状态不同步 | 确保使用 [Command] 修改 SyncVar ,且服务器逻辑正确。 |
玩家列表不更新 | 检查 NetworkRoomManager 的 roomSlots 是否包含所有玩家实例。 |
本地玩家UI未激活 | 在 OnStartLocalPlayer 中启用交互组件(如按钮)。 |
游戏开始时玩家未生成 | 在 NetworkRoomManager 的 OnRoomServerSceneChanged 中调用替换玩家方法。 |
7、最佳实践
UI与逻辑分离
- 使用
SyncVar
的hook
更新UI,避免直接在Command/RPC中操作UI元素。
输入验证
- 所有客户端发起的操作需在服务器验证(如检查玩家是否为房主)。
性能优化
- 减少高频同步数据(如实时位置),仅在状态变化时同步。
扩展性设计
- 将房间玩家数据与游戏玩家数据分离,通过场景切换传递必要信息。