2D-игра Unity Networking, ClientRpc работает неправильно

Я создаю сетевую 2D-игру для своего школьного проекта и столкнулся с проблемой при попытке заставить игрока «развиваться» в сетевом сценарии. Игрок будет правильно развиваться только на клиенте, а не на хосте. Код, вызывающий проблему, находится где-то в скрипте Evolve, но я не знаю, как показать проблему через код, так как проблема заключается в реализации кода. Следовательно, я прикрепил оба кода:

using System.Collections;
using System.Collections.Generic;
using UnityEngine.Networking;
using UnityEngine;

public class Evolve : NetworkBehaviour {

    public bool canEvolve;
    public bool isEvolving;
    public int evoTimer;
    public int timeToEvolve;
    public int currentEvo;
    public GameObject Evo0;
    public GameObject Evo1;
    public GameObject Evo2;
    public GameObject nextEvo;
    public GameObject nextA_Atk;
    public GameObject nextB_Atk;

    // Use this for initialization

    void Start() {
        canEvolve = true;
        isEvolving = false;
        evoTimer = 0;
        timeToEvolve = GameObject.FindGameObjectWithTag("Settings").GetComponent<GameSettings>().timeToEvolve;
        currentEvo = -1;
        RpcCallEvolve();
    }

    // Update is called once per frame
    void Update() {
        if (!isLocalPlayer)
        {
            return;
        }
        if ((Input.GetButton("Evolve")) && (canEvolve == true))
        {
            isEvolving = true;
            evoTimer += 1;
            if (evoTimer >= timeToEvolve)
            {
                RpcCallEvolve();
            }
        }
        else
        {
            isEvolving = false;
            evoTimer = 0;
        }
    }

    [ClientRpc(channel = 0)]
    void RpcCallEvolve()
    {
        currentEvo += 1;
        switch (currentEvo)
        {
            case 0:
                nextEvo = Instantiate(Evo0) as GameObject;
                break;
            case 1:
                nextEvo = Instantiate(Evo1) as GameObject;
                break;
            case 2:
                nextEvo = Instantiate(Evo2) as GameObject;
                break;
            case 3:
                Win(name);
                break;
        }
        GetComponent<SpriteRenderer>().sprite = nextEvo.GetComponent<SpriteRenderer>().sprite;
        GetComponent<PolygonCollider2D>().points = nextEvo.GetComponent<PolygonCollider2D>().points;
        canEvolve = true;
        evoTimer = 0;
        Destroy(nextEvo);
    }
    void Win(string player)
    {
        Debug.Log("Winner is " + player);
        gameObject.SetActive(false);
    }
}

И ссылку на скачивание полного проекта, если это поможет людям разобраться в проблеме. https://1drv.ms/u/s!ArLjF5CAV1VwgbxZdCQkb_9PZ_j5kw

Мне не нужно, чтобы остальная часть кода была исправлена ​​или приведена в порядок, просто информация о том, что может работать для вышеуказанной проблемы.

Большое спасибо всем, кто помогает.


person TheMemur    schedule 08.08.2018    source источник


Ответы (1)


После просмотра вашего сценария выяснилось, что есть несколько проблем. Во-первых, давайте рассмотрим некоторые правила использования ClientRPC:

  • ClientRPC вызывается на сервере/хосте, а соответствующий метод вызывается на всех клиентах (включая хост, поскольку хост является сервером и вместе взятым клиентом).
  • ClientRPC следует ТОЛЬКО вызывать на сервере, иначе они не будут работать должным образом. ClientRPC может вызываться клиентом, но они не будут отправлять данные на сервер и будут работать как обычный метод.

Теперь давайте посмотрим на ваш сценарий. Ваш метод RpcCallEvolve вызывается в методе Update, но первое вы проверяете, находится ли скрипт в локальном проигрывателе. Это создает некоторые проблемы, в основном из-за того, что метод RpcCallEvolve будет вызываться только на клиенте, которому принадлежит этот проигрыватель. Если это происходит на плеере хоста, сценарий должен работать правильно, так как ClientRPC в любом случае будет вызываться на сервере. Однако, если он вызывается на вашем клиенте, он будет работать как обычный локальный метод (как мы упоминали ранее). Я бы предложил использовать команду, чтобы гарантировать, что ClientRPC вызывается на сервере. Команды работают только с объектами игрока, поэтому имейте в виду, что этот Evolve скрипт должен быть на объекте игрока.

[Command]
public void CmdServerEvolve () 
{
    RpcCallEvolve();
}

Поэтому вместо вызова RpcCallEvolve в функции обновления вызовите CmdServerEvolve. Не стесняйтесь задавать вопросы, если что-то из этого было непонятно. Надеюсь это поможет!

person Scornz    schedule 08.08.2018
comment
Большое спасибо, теперь это имеет гораздо больше смысла. Я не думаю, что до конца понимал, как работает ClientRpc, и это помогло многое прояснить. - person TheMemur; 09.08.2018
comment
@TheMemur UNET может быть очень запутанным для начала, если у вас есть еще вопросы, пожалуйста, не стесняйтесь спрашивать меня! - person Scornz; 09.08.2018