@Senture

Синхронизация выбранного оружия для каждого из игроков в мультиплеерном шутере на Unity?

Всем здравствуйте!
Есть код для синхронизации позиции, поворота игроков и в нем же есть код для синхронизации выбранного оружия для каждого из игроков:
spoiler
/*
 * 
 * Скрипт SyncPlayer отвечает за синхранизацию игроков
 * 
 */
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class SyncPlayer : NetworkBehaviour
{
    [SyncVar] Vector3 syncPosition; // Позиция всех клиентов кроме самого игрока
    [SyncVar] Quaternion syncRotation; // Поворот всех игроков кроме самого игрока
    [SyncVar] SyncListBool syncWeapon = new SyncListBool();

    public float lerpSpeed = 20; // Скорость сглаживания

    /// <summary>
    /// Фиксированый вызов метода TransmitPosition для синхронизации позиции
    /// </summary>
	void FixedUpdate ()
    {
        LerPosition();
        TransmitTransform();
    }

    /// <summary>
    /// Метод для сглаживания позиции всех клиентов но кроме самого игрока
    /// </summary>
    void LerPosition()
    {
        if (!isLocalPlayer)
        {
            transform.position = Vector3.Lerp(transform.position, syncPosition, Time.deltaTime * lerpSpeed);
            transform.rotation = Quaternion.Lerp(transform.rotation, syncRotation, Time.deltaTime * lerpSpeed);

            for(int i = 0; i < syncWeapon.Count; i++)
            {
                gameObject.GetComponent<PlayerScrolWeapon>().weapon[i].SetActive(syncWeapon[i]);
            }

        }
    }

    /// <summary>
    /// Отправка позиции локального игрока на сервер в переменную syncPosition
    /// </summary>
    [Client]
    void TransmitTransform()
    {
        if (isLocalPlayer)
        {
            List<GameObject> weapon = gameObject.GetComponent<PlayerScrolWeapon>().weapon;
            GameObject[] _weapon = new GameObject[4];

            int i = 0;

            foreach (GameObject goGun in weapon)
            {
                _weapon[i] = goGun;
                i++;
            }

            CmdSendTransform(transform.position, transform.rotation, _weapon);
        }
    }

    /// <summary>
    /// Запись позиции локального игрока в переменную syncPosition
    /// </summary>
    [Command]
    void CmdSendTransform(Vector3 position, Quaternion rotation, GameObject[] _weapon)
    {
        syncPosition = position;
        syncRotation = rotation;

        syncWeapon.Clear();
        foreach (GameObject weap in _weapon)
        {
            syncWeapon.Add(weap.activeSelf);
        }
    }
}



Сам скрипт PlayerScrolWeapon:
spoiler
using System.Collections.Generic;
using UnityEngine;

public class PlayerScrolWeapon : MonoBehaviour
{

    [SerializeField] private GameObject[] weapons; // Массив всех оружий
    private string[] nameSelectedWeapons = new string[4]; // Массив названий всех выбранных оружий
    public List<GameObject> weapon = new List<GameObject>(); // Список всех выбранных оружий для переключения между ними
    private int scrolInt = 0; // Индекс выбранного оружия(скрола)
    private int lastScrolInt = 0; // Индекс старого значения
    private Animator anim;
	void Start ()
    {
        anim = GetComponent<Animator>();
        nameSelectedWeapons[0] = "Cube Gun";
        nameSelectedWeapons[1] = "Sphere Gun";
        nameSelectedWeapons[2] = "Cylinder Gun";
        nameSelectedWeapons[3] = "Capsule Gun";
        // Переносим в список выбранных оружий из массива всех оружий по названиям оружий в массиве названий
        foreach (GameObject goWeapon in weapons)
        {
            foreach(string nameSelectedWeapon in nameSelectedWeapons)
            {
                if (nameSelectedWeapon == goWeapon.name)
                    weapon.Add(goWeapon);
            }
        }

        weapon[scrolInt].SetActive(true);
 	}
	
	void Update ()
    {
        lastScrolInt = scrolInt;
        // Изменение значения индекса выбранного оружия при прокрутке колесиком мыши
        if (Input.GetAxis("Mouse ScrollWheel") > 0f)
            scrolInt++;
        else if(Input.GetAxis("Mouse ScrollWheel") < 0f)
            scrolInt--;

        // Не даем выйти индексу за пределы допустимого
        if (scrolInt > weapon.Count - 1)
            scrolInt = 0;
        else if(scrolInt < 0)
            scrolInt = weapon.Count - 1;

        // Переключение между разными оружиями
        if (lastScrolInt != scrolInt)
        {
            //Debug.Log(scrolInt);
            for (int i = 0; i < weapon.Count; i++)
            {
                if (i == scrolInt)
                    weapon[i].SetActive(true);
                else
                    weapon[i].SetActive(false);
            }
        }
	}
}



При запуске хоста когда 1 игрок только находится на сцене(сам сервер и клиент) то все окей, после того как подключается клиент(2-ой игрок) сервер останавливается и выдает вот такую ошибку:
spoiler

NullReferenceException: Object reference not set to an instance of an object
SyncPlayer.CmdSendTransform (Vector3 position, Quaternion rotation, UnityEngine.GameObject[] _weapon) (at Assets/Scripts/Player/SyncPlayer.cs:80)
SyncPlayer.InvokeCmdCmdSendTransform (UnityEngine.Networking.NetworkBehaviour obj, UnityEngine.Networking.NetworkReader reader)
UnityEngine.Networking.NetworkIdentity.HandleCommand (Int32 cmdHash, UnityEngine.Networking.NetworkReader reader) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkIdentity.cs:618)
UnityEngine.Networking.NetworkServer.OnCommandMessage (UnityEngine.Networking.NetworkMessage netMsg) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkServer.cs:1281)
UnityEngine.Networking.NetworkConnection.HandleReader (UnityEngine.Networking.NetworkReader reader, Int32 receivedSize, Int32 channelId) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkConnection.cs:469)
UnityEngine.Networking.NetworkConnection.HandleBytes (System.Byte[] buffer, Int32 receivedSize, Int32 channelId) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkConnection.cs:425)
UnityEngine.Networking.NetworkConnection.TransportReceive (System.Byte[] bytes, Int32 numBytes, Int32 channelId) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkConnection.cs:576)
UnityEngine.Networking.NetworkServer.OnData (UnityEngine.Networking.NetworkConnection conn, Int32 receivedSize, Int32 channelId) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkServer.cs:738)
UnityEngine.Networking.NetworkServer+ServerSimpleWrapper.OnData (UnityEngine.Networking.NetworkConnection conn, Int32 receivedSize, Int32 channelId) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkServer.cs:1869)
UnityEngine.Networking.NetworkServerSimple.HandleData (Int32 connectionId, Int32 channelId, Int32 receivedSize, Byte error) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkServerSimple.cs:384)
UnityEngine.Networking.NetworkServerSimple.Update () (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkServerSimple.cs:247)
UnityEngine.Networking.NetworkServer.InternalUpdate () (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkServer.cs:691)
UnityEngine.Networking.NetworkServer.Update () (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkServer.cs:642)
UnityEngine.Networking.NetworkIdentity.UNetStaticUpdate () (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkIdentity.cs:1091)

Но у клиента видно какое оружие было выбрано у сервера до того пока он не остановился. При попытки снять сервер с паузы возникает та же самая ошибка. Я уже множество вариантов перепробовал и все безуспешны, решил остановиться именно на этом варианте т.к. он мне кажется самым правильным.
Помогите пожалуйста исправить данную ошибку.

P.S. Спасибо большое!!!!
  • Вопрос задан
  • 425 просмотров
Решения вопроса 1
@Senture Автор вопроса
Проблема решена, это было из за того что 2 приложения клиент и сервер были запущены на 1пк, после того как сервер и клиент были запущены на разных пк, почти все заработало, но почему то клиент видит как сервер меняет оружие, а сервер не видит как клиент меняет оружие. Есть у кого варианты решения данной задачки?

Что никто не знает как это сделать? Я уже весь инет перерыл по поводу смены оружия в мультиплеере и его синхронизацию но пусто!!! Помогите -_- пожалуйста)

Решение:
spoiler
using UnityEngine;
using UnityEngine.Networking;

public class PlayerScrolWeapon : NetworkBehaviour
{
    public GameObject[] weapon;
    [SyncVar] int syncWeaponIndex;
    private int weaponIndex = 0;
	
    [Client]
	void FixedUpdate()
    {
        ScrolWeapon();
        if(isLocalPlayer)
            CmdSendToServerSyncWeapon(weaponIndex);
        SendToClientSyncWeapon();
	}

    void ScrolWeapon()
    {
        if(isLocalPlayer)
        {
            if(Input.GetAxisRaw("Mouse ScrollWheel") > 0f)
            {
                if (weaponIndex > 3)
                    weaponIndex = 0;
                else
                    weaponIndex++;
            }
            else if(Input.GetAxisRaw("Mouse ScrollWheel") < 0f)
            {
                if (weaponIndex < 0)
                    weaponIndex = 3;
                else
                    weaponIndex--;
            }

            for (int i = 0; i < 4; i++)
                if (i == weaponIndex)
                    weapon[i].SetActive(true);
                else
                    weapon[i].SetActive(false);
        }
    }

    void SendToClientSyncWeapon()
    {
        if(!isLocalPlayer)
        {
            for (int i = 0; i < 4; i++)
                if (i == syncWeaponIndex)
                    weapon[i].SetActive(true);
                else
                    weapon[i].SetActive(false);
        }
    }

    [Command]
    void CmdSendToServerSyncWeapon(int _weaponIndex)
    {
        syncWeaponIndex = _weaponIndex;
    }
}



Это 1 скрипт который отвечает и за смену оружия и за его синхронизацию, может кому то пригодится.

P.S. Тема закрыта!
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы