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

求助:如何用Photon Fusion制作Unity回合制多人桌游

使用Photon Fusion实现回合制多人桌游核心功能

一、核心思路:用状态同步替代预测移动

桌游不需要FPS类游戏的预测/插值同步逻辑,直接用Fusion的状态同步即可——所有核心游戏状态(回合归属、物品持有、物体位置)通过[Networked]标记自动同步,玩家操作通过RPC触发服务器验证后执行,避免状态不一致。

二、步骤实现

1. 创建回合管理核心(NetworkBehaviour)

新建TurnManager.cs,挂载到一个NetworkObject上作为全局游戏状态管理器,核心是同步当前回合的玩家标识:

using Fusion;

public class TurnManager : NetworkBehaviour
{
    // 同步当前回合玩家的PlayerRef(Fusion内置的玩家唯一标识)
    [Networked] public PlayerRef CurrentTurnPlayer { get; set; }

    // 初始化:设置第一个回合玩家(取房间内第一个加入的玩家)
    public override void Spawned()
    {
        if (Runner.IsServer) // 仅服务器能初始化全局状态
        {
            CurrentTurnPlayer = Runner.SessionInfo.PlayerIds[0];
        }
    }

    // RPC:切换到下一个回合玩家(仅当前回合玩家可调用)
    [Rpc(RpcSources.InputAuthority, RpcTargets.StateAuthority)]
    public void RpcNextTurn()
    {
        var playerIds = Runner.SessionInfo.PlayerIds;
        int currentIndex = System.Array.IndexOf(playerIds, CurrentTurnPlayer);
        // 循环切换到下一位玩家
        CurrentTurnPlayer = playerIds[(currentIndex + 1) % playerIds.Length];
    }
}

2. 按钮权限控制(商店/下一回合按钮)

给按钮绑定脚本,仅允许当前回合玩家操作:

using Fusion;
using UnityEngine.UI;

public class TurnButtonHandler : MonoBehaviour
{
    public Button shopButton;
    public Button nextTurnButton;
    private TurnManager _turnManager;
    private NetworkRunner _runner;

    void Start()
    {
        _runner = FindObjectOfType<NetworkRunner>();
        _turnManager = FindObjectOfType<TurnManager>();
    }

    void Update()
    {
        bool isCurrentTurn = _runner.LocalPlayer == _turnManager.CurrentTurnPlayer;
        // 动态控制按钮可交互状态
        shopButton.interactable = isCurrentTurn;
        nextTurnButton.interactable = isCurrentTurn;
    }

    // 商店按钮点击事件
    public void OnShopButtonClicked()
    {
        _turnManager.RpcPurchaseItem("治疗药水"); // 传入具体物品名
    }

    // 下一回合按钮点击事件
    public void OnNextTurnClicked()
    {
        _turnManager.RpcNextTurn();
    }
}

3. 购买物品同步逻辑

在TurnManager中添加物品购买的RPC,确保所有客户端同步物品状态:

// 用网络字典存储每个玩家的物品(自动同步)
[Networked, Capacity(8)] private NetworkDictionary<PlayerRef, NetworkString<_16>> _playerItems =>
    GetNetworkDictionary<PlayerRef, NetworkString<_16>>();

// RPC:购买物品(仅当前回合玩家可调用,服务器执行)
[Rpc(RpcSources.InputAuthority, RpcTargets.StateAuthority)]
public void RpcPurchaseItem(string itemName)
{
    // 验证调用者是否为当前回合玩家,防止作弊
    if (Runner.LocalPlayer != CurrentTurnPlayer) return;

    // 将物品添加到调用者的物品列表
    if (_playerItems.ContainsKey(Runner.LocalPlayer))
    {
        _playerItems[Runner.LocalPlayer] = itemName;
    }
    else
    {
        _playerItems.Add(Runner.LocalPlayer, itemName);
    }
}

4. GameObject移动同步

要移动的物体必须是NetworkObject,添加NetworkTransform组件(Fusion自带的位置同步组件),通过RPC触发服务器端移动:

using Fusion;

public class MovableObject : NetworkBehaviour
{
    private TurnManager _turnManager;
    private NetworkRunner _runner;

    void Start()
    {
        _runner = FindObjectOfType<NetworkRunner>();
        _turnManager = FindObjectOfType<TurnManager>();
    }

    // RPC:移动物体(仅当前回合玩家可调用)
    [Rpc(RpcSources.InputAuthority, RpcTargets.StateAuthority)]
    public void RpcMoveToPosition(Vector3 targetPos)
    {
        // 权限验证
        if (_turnManager.CurrentTurnPlayer != Runner.LocalPlayer) return;

        // 服务器端执行移动,Fusion自动同步到所有客户端
        GetComponent<NetworkTransform>().TeleportToPosition(targetPos);
    }
}

若需要平滑移动,可在FixedUpdateNetwork中根据同步的目标位置做插值,不要直接在客户端修改位置。

5. 回合专属文本框显示

给文本框绑定脚本,仅当前回合玩家可见:

using Fusion;
using UnityEngine.UI;

public class TurnExclusiveText : MonoBehaviour
{
    public Text turnPromptText;
    private TurnManager _turnManager;
    private NetworkRunner _runner;

    void Start()
    {
        _runner = FindObjectOfType<NetworkRunner>();
        _turnManager = FindObjectOfType<TurnManager>();
    }

    void Update()
    {
        // 根据回合状态切换文本框显示
        turnPromptText.gameObject.SetActive(_runner.LocalPlayer == _turnManager.CurrentTurnPlayer);
    }
}

三、关键注意事项

  • 所有需要跨客户端同步的状态必须用[Networked]标记,避免客户端直接修改同步变量导致状态不一致。
  • 所有玩家操作必须通过RPC触发,并在RPC内做权限验证(如检查调用者是否为当前回合玩家),防止恶意作弊。
  • 确保NetworkRunner正确初始化,所有NetworkObject均通过Runner生成(不要直接用Instantiate)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 21:37:32