在Unity中基于回合的网络

时间:2015-01-19 10:56:22

标签: c# unity3d network-programming

我想创建一个基于回合制的网络游戏,所以在某个地方我必须告诉玩家等待转弯。这看起来像一个简单的问题,但我现在正在与它斗争很多天。首先,我告诉你我现在的情况,请告诉我,如果我在任何阶段做错了什么。

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

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

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

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

另一位玩家现在可以刷新列表,并通过点击按钮将此服务器与HostData提供的MasterServer一起加入:

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 个答案:

答案 0 :(得分:2)

虽然我自己从未使用过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" }));

    }
}

接下来,将此脚本附加到您的播放器GameObjects,并在检查器中分配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();