You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
    }
}

关键注意事项

  1. 服务器权威原则:所有修改游戏状态的逻辑(如创建房间、移动Player对象)必须在服务器端执行,客户端仅负责发起请求和同步显示。
  2. Player对象迁移:startGame()时将Player从RoomManager移至InGameManager的操作,需在服务器端执行(如在RoomManager的ServerRpc或Command中修改Player的父Transform),客户端会自动同步该变更。
  3. 引用获取时机:客户端需在NetworkManager.Singleton.IsClient为true且网络连接完成后,再获取ServerManager或Player对象的引用,可通过NetworkManager.Singleton.OnClientConnectedCallback回调确保时机正确。

内容的提问来源于stack exchange,提问作者ImAntizero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 07:05:30