使用 Photon Fusion 对非 Unity 场景相关数据进行建模

问题描述 投票:0回答:1

我正在寻求一些帮助,让我的游戏成为多人游戏。

我刚刚开始使用 Photon,虽然我理解为什么文档首先关注玩家移动之类的事情,但我对网络额外数据有点着迷。

例如,我正在创建的游戏是纸牌游戏,当前单例保存代表每个玩家手牌的列表,该列表不直接与 GUI 绑定。它存在于世界游戏对象上,然后用于跟踪所有当前的卡牌。虽然我认为这可以仅作为附加到实际游戏对象(例如每张卡)的数据存在,但我认为拥有一组数据然后根据 GUI 进行映射会更清晰。

因此,如果我有 p1、p2 和 p3,有 3 张牌,称为 k、j、j,我如何告诉 photon 这些数据应该只在主机上保存一份副本,而不是每个设备上每个人的手牌的四份副本。假设我正确理解 p1 将有一个用于其场景的 Gamecore 实例,而 p2 将有一个用于其场景的游戏核心实例,因为即使它是单例,每个客户端都有自己的实例。

orrrr

每个客户端是否应该生成自己的 p1、p2 和 p3 列表,然后传达要在所有客户端之间传播的更改,以确保所有客户端都具有相同的数据。如果是这种情况,它更像是 p1 说丢弃一张卡,更新自身,然后发送一条消息供客户端接收。作为参考,这里是我当前的游戏核心和玩家类别的缩减。

public class GameCore : MonoBehaviour{

public List<Player> playerList = new List<Player>();
public static GameCore Instance { get; private set; }

private void Awake()
{
    if (Instance != null && Instance != this)
        Destroy(gameObject);
    else
        Instance = this;
}

}



public struct Player {

//should initialize with a name and 7 blank cards
public Player(string playerName)
{
    name = playerName;
    playerCards = new List<Card>();
    score = 0;
    sticks = new Stick();
}

private string name;
private int score;
public List<Card> playerCards;
public Stick sticks;

}
c# unity-game-engine multiplayer photon
1个回答
0
投票

Fusion 的要点是使用

[Networked]
属性,它会自动通过网络同步。网络属性必须位于
NetworkBehaviour
内部,具有
[Networked]
属性,并且是 兼容的可序列化类型。

因此,在您的情况下,您的

Player
结构可以是 NetworkBehaviour:

public class PlayerData : NetworkBehaviour {
    private const int MAX_NAME_SIZE = 16;
    private const int MAX_HAND_SIZE = 7;

    [Networked, Capacity(MAX_NAME_SIZE)] private string Name { get; set; }
    [Networked] private int Score { get; set; }
    [Networked, Capacity(MAX_HAND_SIZE)] public NetworkList<Card> PlayerCards => default;
    [Networked] public Stick Sticks { get; set; }
}

public struct Card : INetworkStruct {
    public CardSuit Suit;
    public int Value;
}

public enum CardSuit : byte {
    Spades, Clubs, Hearts, Diamonds
}

public struct Stick : INetworkStruct {
    // I'm not sure what a "stick" is...
}

然后对于加入的每个玩家,您可以使用类似

INetworkRunnerCallbacks.OnPlayerJoined
:
 之类的内容生成包含 
Player 行为(以及协调同步的 NetworkObject

)的预制件副本
public void OnPlayerJoined(NetworkRunner runner, PlayerRef player) {
    // Only spawn our own copy.
    if (runner.LocalPlayer == player) {
        Runner.Spawn(yourPlayerPrefab);
    }
}

此解决方案是“共享”模式的首选,因为每个玩家都对自己的对象拥有 StateAuthority(允许他们修改网络变量)。


如果您使用主机模式,那么主机(或专用服务器)将在 PlayerData 类上拥有 StateAuthority,并且玩家想要做的任何事情都必须通过 inputs 或 RPC(使用

[Rpc(RpcSources.InputAuthority, RpcTargets.StateAuthority)] 
)。

这意味着服务器将负责卡牌的生成和修改,这使得客户端不可能通过直接修改自己的卡牌变量来进行作弊:

public void OnPlayerJoined(NetworkRunner runner, PlayerRef player) {
    if (runner.IsServer) {
        Runner.Spawn(yourPlayerPrefab, inputAuthority: player);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.