简体   繁体   English

Unity 中的回合制网络

[英]Turn based networking in Unity

I want to create a turn based network game so somewhere I have to tell the player to wait for there turn.我想创建一个基于回合的网络游戏,所以我必须在某个地方告诉玩家等待回合。 This looks like a simple problem but I am struggling with it for many days now.这看起来是一个简单的问题,但我已经为此苦苦挣扎了很多天。 First I talk you trough what I currently have, please tell me if I am doing something wrong at any stage.首先我用我目前的情况告诉你,如果我在任何阶段做错了什么,请告诉我。

Before the game starts a player enters a lobby and can join games (or possibly create them).在游戏开始之前,玩家进入大厅并可以加入游戏(或可能创建游戏)。 Currently my lobby has just 2 buttons where a server can be created and a server list retrieved.目前我的大厅只有 2 个按钮,可以在其中创建服务器和检索服务器列表。 Servers show up in buttons once retrieved.一旦检索到,服务器就会显示在按钮中。

When a player starts a server this script runs:当玩家启动服务器时,此脚本会运行:

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

As far as I know this player is now currently the server.据我所知,这个播放器目前是服务器。

Another player can refresh the list now and join this server with the HostData presented by the MasterServer by clicking the button:另一个玩家现在可以刷新列表并通过单击按钮加入此服务器,并使用MasterServer提供的HostData

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

As you can see, a new scene has been loaded after connecting.如您所见,连接后已经加载了一个新场景。 When the connection is made I do the same for the server:建立连接后,我对服务器执行相同操作:

private void OnPlayerConnected(NetworkPlayer player)
{
    Debug.Log(player.externalIP + " Has connected!");       
    Application.LoadLevel("GameScene");
}

Now both players (client and server) are in the game scene and they are still connected.现在两个玩家(客户端和服务器)都在游戏场景中并且他们仍然连接。 How would I give the turn to the server and let the client wait?我将如何轮到服务器并让客户端等待? Just feedback from pressing a button would be enough for me to understand.只需按下按钮的反馈就足以让我理解。 Like only allow Input Feedback for a single player.就像只允许单个玩家输入反馈一样。 This is what I tried in the new scene:这是我在新场景中尝试的:

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?
}

So obviously the following code to check which player can act does not work.所以很明显,下面的代码来检查哪个玩家可以行动是行不通的。

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

I am completely stuck for days, all tutorials about networking show two floating cubes but do not show how to distinct players at all.我完全被困了好几天,所有关于网络的教程都展示了两个浮动的立方体,但根本没有展示如何区分玩家。 How can I restrict a single player whether he created the server or joined as a client from moving until the current player has acted ?如何限制单个玩家(无论他是创建服务器还是作为客户端加入)在当前玩家采取行动之前移动

So I am asking for hints on how to implement a very basic turn based system between the server player and the connected client(s).所以我在寻求有关如何在服务器玩家和连接的客户端之间实现一个非常基本的回合制系统的提示。

While I've never used MasterServer myself, I believe that NetworkView.RPC calls should work.虽然我自己从未使用过 MasterServer,但我相信 NetworkView.RPC 调用应该可以工作。 RPC or Remote Procedure Calls are calls sent over the network, and are executed on all peers, provided a matching public method is found. RPC 或远程过程调用是通过网络发送的调用,并在所有对等方上执行,前提是找到了匹配的公共方法。

I won't go into too many details about RPC here, it's well detailed on Unity's NetworkView.RPC docs here我不会在这里介绍太多关于 RPC 的细节, Unity 的 NetworkView.RPC 文档在这里有很详细的介绍

To your problem, here's some code you can try对于您的问题,这里有一些您可以尝试的代码

Create a new C# script, and name it RPCExample创建一个新的 C# 脚本,并将其命名为RPCExample

RPCExample.cs 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" }));

    }
}

Next, attach this script to your player GameObjects, and assign the NetworkView variable in the inspector.接下来,将此脚本附加到您的玩家游戏对象,并在检查器中分配 NetworkView 变量。

Now, change your StartServer method to look like现在,将您的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);
}

Change your HostButton method as follows更改您的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);
}

Now, for this example, lets assume that the server ALWAYS goes first (you can easily change that).现在,对于这个例子,让我们假设服务器总是先行(你可以很容易地改变它)。 So when your game scene loads (the one you've loaded with Application.LoadLevel("GameScene")), call the following method ON THE CLIENT因此,当您的游戏场景加载时(您使用 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();
}

And that's it!.就是这样!。 When you're done with the current players' turn, just call当您完成当前玩家的回合后,只需调用

RPCExample.instance.FinishTurn();

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

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