简体   繁体   中英

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. 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:

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. RPC or Remote Procedure Calls are calls sent over the network, and are executed on all peers, provided a matching public method is found.

I won't go into too many details about RPC here, it's well detailed on Unity's NetworkView.RPC docs here

To your problem, here's some code you can try

Create a new C# script, and name it 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" }));

    }
}

Next, attach this script to your player GameObjects, and assign the NetworkView variable in the inspector.

Now, change your StartServer method to look like

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

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

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();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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