繁体   English   中英

Unity 中的回合制网络

[英]Turn based networking in Unity

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

在游戏开始之前,玩家进入大厅并可以加入游戏(或可能创建游戏)。 目前我的大厅只有 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;
        }
    }
}

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

所以我在寻求有关如何在服务器玩家和连接的客户端之间实现一个非常基本的回合制系统的提示。

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

我不会在这里介绍太多关于 RPC 的细节, Unity 的 NetworkView.RPC 文档在这里有很详细的介绍

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

创建一个新的 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();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM