Unity 中的回合制网络

Posted

技术标签:

【中文标题】Unity 中的回合制网络【英文标题】:Turn based networking in Unity 【发布时间】:2015-03-17 08:42:29 【问题描述】:

我想创建一个基于回合的网络游戏,所以我必须在某个地方告诉玩家等待那里的回合。这看起来像一个简单的问题,但我现在已经为此苦苦挣扎了很多天。首先我谈谈我目前所拥有的,如果我在任何阶段做错了什么,请告诉我。

在游戏开始之前,玩家进入大厅并可以加入游戏(或可能创建游戏)。目前我的大厅只有 2 个按钮,可以在其中创建服务器并检索服务器列表。服务器在检索后显示在按钮中。

当玩家启动服务器时,此脚本运行:

private void StartServer()

    Network.InitializeServer(2, 25000, false);
    MasterServer.RegisterHost(gameName, "Test game 2", "Welcome!");
    GameObject canvas = GameObject.Find("Canvas");
    canvas.SetActive(false);

据我所知,这个播放器现在是服务器。

其他玩家现在可以刷新列表,并通过单击按钮以MasterServer 提供的HostData 加入此服务器:

private void HostButton(HostData hostData)

    Debug.Log(hostData.gameName);
    Network.Connect(hostData);
    Application.LoadLevel("GameScene");

如您所见,连接后已加载了一个新场景。建立连接后,我对服务器执行相同操作:

private void OnPlayerConnected(NetworkPlayer player)

    Debug.Log(player.externalIP + " Has connected!");       
    Application.LoadLevel("GameScene");

现在两个玩家(客户端和服务器)都在游戏场景中并且他们仍然保持连接。我将如何轮到服务器并让客户端等待?只需按下按钮的反馈就足以让我理解。像只允许单个玩家的输入反馈。这是我在新场景中尝试的:

void Start () 

    players = Network.connections;
    foreach (NetworkPlayer player in players)
    
        Debug.Log(player.externalIP + ":" + player.externalPort + " entered the game!");
    
    Debug.Log(players.GetLength(0)); //returns 1. Obviously because server to client is one conncetion. But what is the NetworkPlayer of the server?

显然,以下检查哪个玩家可以行动的代码不起作用。

void Update () 

    if (players[currentPlayer] == Network.player)
    
        if (Input.GetMouseButtonDown(0))
        
            Debug.Log("Player " + (currentPlayer + 1) + " fired mouse!");
            currentPlayer++;
            if (currentPlayer > 1) currentPlayer = 0;
        
    

我完全被困了好几天,所有关于网络的教程都显示了两个浮动立方体,但根本没有说明如何区分玩家。 如何限制单个玩家(无论是创建服务器还是作为客户端加入)在当前玩家行动之前移动

所以我想请教如何在服务器玩家和连接的客户端之间实现一个非常基本的回合制系统。

【问题讨论】:

【参考方案1】:

虽然我自己从未使用过 MasterServer,但我相信 NetworkView.RPC 调用应该可以工作。 RPC 或 远程过程调用 是通过网络发送的调用,并在所有对等方上执行,前提是找到匹配的公共方法。

关于RPC这里就不过多赘述了,Unity's NetworkView.RPC docs here有详细的介绍

对于你的问题,这里有一些你可以尝试的代码

创建一个新的 C# 脚本,并将其命名为 RPCExample

RPCExample.cs

using UnityEngine;
using System.Collections;

public class RPCExample : MonoBehaviour 

    public static RPCExample instance;

    //Assign this NetworkView in the inspector
    public NetworkView networkView;

    //A boolean that states whether this player is the server
    //or the client
    public bool thisIsTheServer = false;

    //This is a boolean that will control whether it is THIS
    //player's turn or not
    public bool isMyTurn = false;


    void Awake () 
        instance = this;
    

    //This method will set whether this connected player is the server or not
    [RPC]
    public void SetAsServer (bool isServer) 
        thisIsTheServer = isServer;
    

//
    [RPC]
    public void SetTurn (bool turn) 
        isMyTurn = turn;
    

    [RPC]
    public void FinishTurn () 
        networkView.RPC("SetTurn", RPCMode.Others, new object[]  true );
        SetTurn(false);
    


    public void Update () 

        //It is not this player's turn, so early exit
        if(!isMyTurn)
            return;

        //If execution reaches here, it is this player's turn
        Debug.Log (string.Format("It is 0's turn!", 
                             new object[]  (thisIsTheServer) ? "Server" : "Client" ));

    

接下来,将此脚本附加到您的玩家游戏对象,并在检查器中分配 NetworkView 变量。

现在,将您的 StartServer 方法更改为如下所示

private void StartServer() 
    Network.InitializeServer(2, 25000, false);
    MasterServer.RegisterHost(gameName, "Test game 2", "Welcome!");
    GameObject canvas = GameObject.Find("Canvas");
    canvas.SetActive(false);

    //Set this player as server
    RPCExample.instance.SetAsServer(true);

如下更改您的 HostButton 方法

private void HostButton(HostData hostData) 
    Debug.Log(hostData.gameName);
    Network.Connect(hostData);
    Application.LoadLevel("GameScene");

    //This should only be executed on the client obviously.
    //Ensure you handle that scenario.
    RPCExample.instance.SetAsServer(false);

现在,对于这个例子,让我们假设服务器总是先走(你可以很容易地改变它)。因此,当您的游戏场景加载时(您使用 Application.LoadLevel("GameScene") 加载的场景),请在客户端上调用以下方法

void Start () 
    //By calling FinishTurn on the client, we pass the turn onto the server
    //You can always rewrite this to use a random value, like a coin flip
    RPCExample.instance.FinishTurn();

就是这样!当你完成当前玩家的回合时,只需调用

RPCExample.instance.FinishTurn();

【讨论】:

谢谢,这很有帮助。在过去的 5 个小时里,我有一些工作要做,如果你能快速浏览一下,我会很高兴的。 gamedev.net/topic/664940-turn-based-multiplayer-game/… 同时我会研究你发布的内容。

以上是关于Unity 中的回合制网络的主要内容,如果未能解决你的问题,请参考以下文章

从 Google Play 服务、Unity 插件获取所有回合制比赛信息

Unity 中 Google Games Services 回合制多人游戏的自定义 UI

回合对战制游戏第一篇

Android Google Play 游戏服务回合制多人游戏不自动匹配

实现回合制网页游戏[关闭]

Unity 掷骰子后让玩家的棋子轮流移动