Unity Mirror专用服务器:如何调用非Player对象的CreateGame方法
解决方案:非Player对象的服务器方法调用实现
针对你在房间制卡牌游戏开发中遇到的客户端调用服务器端ServerManager.CreateGame()的问题,以下是两种基于Unity Netcode for GameObjects的可行方案,结合你的单场景架构设计:
方法一:直接使用ServerRpc(推荐,更简洁)
ServerRpc是客户端主动调用服务器端方法的核心机制,默认要求调用者拥有目标NetworkObject的所有权,但可以通过关闭权限检查来调用服务器托管的全局对象(如你的ServerManager)。
步骤1:改造ServerManager
给ServerManager挂载NetworkBehaviour,并将其所在GameObject标记为NetworkObject(Inspector中勾选NetworkObject组件)。因为是单场景专用服务器,场景加载时该对象会自动在服务器端存在,客户端连接后会同步其引用。
public class ServerManager : NetworkBehaviour { public static ServerManager Instance; private void Awake() { Instance = this; } // 标记为ServerRpc,关闭所有权检查 [ServerRpc(RequireOwnership = false)] public void CreateGameServerRpc(string gameName, int maxPlayers) { // 服务器端执行创建游戏的核心逻辑 GameObject gameInstance = new GameObject($"Game_{gameName}"); RoomManager roomManager = gameInstance.AddComponent<RoomManager>(); InGameManager inGameManager = gameInstance.AddComponent<InGameManager>(); // 初始化房间参数 roomManager.InitRoom(gameName, maxPlayers); // 后续添加房间管理逻辑(如加入玩家列表、同步房间信息到客户端等) } }
步骤2:客户端调用
客户端在网络连接成功后,获取ServerManager的引用并调用ServerRpc方法:
// 示例:UI按钮点击事件触发创建游戏 public void OnCreateGameBtnClick() { if (!NetworkManager.Singleton.IsClient) return; // 获取ServerManager实例(需确保客户端已完成网络同步) ServerManager serverManager = FindObjectOfType<ServerManager>(); if (serverManager != null) { // 调用服务器端的创建游戏方法 serverManager.CreateGameServerRpc("我的卡牌房间", 8); } }
方法二:通过Player对象的Command中转
如果需要验证调用者的身份(如仅允许已登录玩家创建房间),可以通过客户端的Player对象作为中间件,用Command触发服务器端逻辑。
步骤1:在Player的NetworkBehaviour中添加中转Command
public class PlayerNetwork : NetworkBehaviour { // 客户端调用,服务器端执行的Command [Command] public void CmdCreateGame(string gameName, int maxPlayers) { // 服务器端可在此验证玩家权限(如是否已在房间、是否有创建权限等) if (IsOwner && ServerManager.Instance != null) { ServerManager.Instance.CreateGame(gameName, maxPlayers); } } }
步骤2:客户端调用
客户端通过本地Player对象触发Command:
public void OnCreateGameBtnClick() { if (!NetworkManager.Singleton.IsClient) return; // 获取本地Player对象 NetworkObject localPlayer = NetworkManager.Singleton.LocalClient.PlayerObject; PlayerNetwork playerNetwork = localPlayer.GetComponent<PlayerNetwork>(); if (playerNetwork != null) { playerNetwork.CmdCreateGame("我的卡牌房间", 8); } }
关键注意事项
- 服务器权威原则:所有修改游戏状态的逻辑(如创建房间、移动Player对象)必须在服务器端执行,客户端仅负责发起请求和同步显示。
- Player对象迁移:
startGame()时将Player从RoomManager移至InGameManager的操作,需在服务器端执行(如在RoomManager的ServerRpc或Command中修改Player的父Transform),客户端会自动同步该变更。 - 引用获取时机:客户端需在
NetworkManager.Singleton.IsClient为true且网络连接完成后,再获取ServerManager或Player对象的引用,可通过NetworkManager.Singleton.OnClientConnectedCallback回调确保时机正确。
内容的提问来源于stack exchange,提问作者ImAntizero
相关产品推荐
相关产品推荐

