[SOLVED] Problem with movement

Hello, I have a problem with movement, only the host can move Units, but not clients

Hi there,
Are these both running in builds? Are you able to run the client in the editor and see if there are any errors?

Hello, the problem is also in the editor, but I also noticed an error on lines 27 and 34, but I can’t figure out where it is

using System;
using System.Collections;
using System.Collections.Generic;
using Mirror;
using Networking;
using Units;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Serialization;

public class UnitSelectionHandler : MonoBehaviour
{
    [SerializeField] private RectTransform unitSelectionArea = null;

    [SerializeField] private LayerMask layerMask = new LayerMask();
    
    private Vector3 startPosition;

    private RTSPlayer player;
    private Camera mainCamera;

    public List<Unit> SelectedUnits { get; } = new List<Unit>();

    private void Start()
    {
        mainCamera = Camera.main;
        player = NetworkClient.connection.identity.GetComponent<RTSPlayer>(); // line 27
    }

    private void Update()
    {
        if (player == null)
        {
            player = NetworkClient.connection.identity.GetComponent<RTSPlayer>(); // line 34
        }
        if (Mouse.current.leftButton.wasPressedThisFrame)
        {
            StartSelectionArea();
        }
        else if (Mouse.current.leftButton.wasReleasedThisFrame)
        {
            ClearSelectionArea();
        }
        else if (Mouse.current.leftButton.isPressed)
        {
            UpdateSelectionArea();
        }
    }
        
    private void StartSelectionArea()
    {
        if (!Keyboard.current.leftShiftKey.isPressed)
        {
            foreach (Unit selectedUnit in SelectedUnits)
            {
                selectedUnit.Deselect();
            }

            SelectedUnits.Clear();
        }

        unitSelectionArea.gameObject.SetActive(true);

        startPosition = Mouse.current.position.ReadValue();
        UpdateSelectionArea();
    }
    private void UpdateSelectionArea()
    {
        if (!unitSelectionArea.gameObject.activeSelf)
        {
            unitSelectionArea.gameObject.SetActive(true);
        }

        Vector3 mousePosition = Mouse.current.position.ReadValue();

        float areaWidth = mousePosition.x - startPosition.x;
        float areaHeight = mousePosition.y - startPosition.y;

        unitSelectionArea.sizeDelta = new Vector2(Mathf.Abs(areaWidth), Mathf.Abs(areaHeight));
        unitSelectionArea.anchoredPosition = startPosition + new Vector3(areaWidth / 2, areaHeight / 2);
    }

    private void ClearSelectionArea()
    {
        unitSelectionArea.gameObject.SetActive(false);
        
        if (unitSelectionArea.sizeDelta.magnitude == 0)
        {
            Ray ray = mainCamera.ScreenPointToRay(Mouse.current.position.ReadValue());

            if (!Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity, layerMask)) { return; }

            if (!hit.collider.TryGetComponent<Unit>(out Unit unit)) { return; }

            if (!unit.hasAuthority) { return; }

            SelectedUnits.Add(unit);

            foreach(Unit selectedUnit in SelectedUnits)
            {
                selectedUnit.Select();
            }
            
            return;
        }

        Vector2 min = unitSelectionArea.anchoredPosition - (unitSelectionArea.sizeDelta / 2);
        Vector2 max = unitSelectionArea.anchoredPosition + (unitSelectionArea.sizeDelta / 2);

        foreach (Unit unit in player.GetMyUnits())
        {
            Vector3 screenPosition = mainCamera.WorldToScreenPoint(unit.transform.position);
            
            if (screenPosition.x > min.x && screenPosition.x < max.x && screenPosition.y > min.y && screenPosition.y < max.y)
            {
                SelectedUnits.Add(unit);
                unit.Select();
            }
        }

    }
}

Unity: 2022.1.15f1
IDE: JetBrains Rider
Mirror: 70.0.0

It could be the player reference. Sometimes it tries to get hold of it before the Network.connection is ready and it breaks the script.

The solution most students use is to move the player reference line into a coroutine and add a 0.5 second delay.

private IEnumerator GetPlayer()
{
     if(player == null)
    {
         yield return new waitForSeconds(0.5f);
         player = NetworkClient.connection.identitiy.GetComponent<RTSPlayer>();
}

error fixed, but theres is another error on this line

using System;
using System.Collections;
using System.Collections.Generic;
using Mirror;
using Networking;
using Units;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Serialization;

public class UnitSelectionHandler : MonoBehaviour
{
    [SerializeField] private RectTransform unitSelectionArea = null;

    [SerializeField] private LayerMask layerMask = new LayerMask();
    
    private Vector3 startPosition;

    private RTSPlayer player;
    private Camera mainCamera;

    public List<Unit> SelectedUnits { get; } = new List<Unit>();

    private void Start()
    {
        mainCamera = Camera.main;
        StartCoroutine(GetPlayer());
    }

    private void Update()
    {
        if (player == null)
        {
            StartCoroutine(GetPlayer());
        }
        if (Mouse.current.leftButton.wasPressedThisFrame)
        {
            StartSelectionArea();
        }
        else if (Mouse.current.leftButton.wasReleasedThisFrame)
        {
            ClearSelectionArea();
        }
        else if (Mouse.current.leftButton.isPressed)
        {
            UpdateSelectionArea();
        }
    }

    private IEnumerator GetPlayer()
    {
        if (player == null)
        {
            yield return new WaitForSeconds(1f);
            player = NetworkClient.connection.identity.gameObject.GetComponent<RTSPlayer>();
        }
    }
    private void StartSelectionArea()
    {
        if (!Keyboard.current.leftShiftKey.isPressed)
        {
            foreach (Unit selectedUnit in SelectedUnits)
            {
                selectedUnit.Deselect();
            }

            SelectedUnits.Clear();
        }

        unitSelectionArea.gameObject.SetActive(true);

        startPosition = Mouse.current.position.ReadValue();
        UpdateSelectionArea();
    }
    private void UpdateSelectionArea()
    {
        if (!unitSelectionArea.gameObject.activeSelf)
        {
            unitSelectionArea.gameObject.SetActive(true);
        }

        Vector3 mousePosition = Mouse.current.position.ReadValue();

        float areaWidth = mousePosition.x - startPosition.x;
        float areaHeight = mousePosition.y - startPosition.y;

        unitSelectionArea.sizeDelta = new Vector2(Mathf.Abs(areaWidth), Mathf.Abs(areaHeight));
        unitSelectionArea.anchoredPosition = startPosition + new Vector3(areaWidth / 2, areaHeight / 2);
    }

    private void ClearSelectionArea()
    {
        unitSelectionArea.gameObject.SetActive(false);
        
        if (unitSelectionArea.sizeDelta.magnitude == 0)
        {
            Ray ray = mainCamera.ScreenPointToRay(Mouse.current.position.ReadValue());

            if (!Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity, layerMask)) { return; }

            if (!hit.collider.TryGetComponent<Unit>(out Unit unit)) { return; }

            if (!unit.hasAuthority) { return; }

            SelectedUnits.Add(unit);

            foreach(Unit selectedUnit in SelectedUnits)
            {
                selectedUnit.Select();
            }
            
            return;
        }

        Vector2 min = unitSelectionArea.anchoredPosition - (unitSelectionArea.sizeDelta / 2);
        Vector2 max = unitSelectionArea.anchoredPosition + (unitSelectionArea.sizeDelta / 2);

        foreach (Unit unit in player.GetMyUnits()) // Here NullReferenceException
        {
            Vector3 screenPosition = mainCamera.WorldToScreenPoint(unit.transform.position);
            
            if (screenPosition.x > min.x && screenPosition.x < max.x && screenPosition.y > min.y && screenPosition.y < max.y)
            {
                SelectedUnits.Add(unit);
                unit.Select();
            }
        }

    }
}

Sorry, which line still has the error? You pasted the whole script so it’s not clear to me.

in foreach (Unit unit in player.GetMyUnits())



I also noticed that all UnitSpawners have the same asset id, could this be the problem?

UPD: I also noticed that until the host spawns its units, the clients cannot spawn their units.

For the line with the null reference, can you add a Debug.Log(player) on the line before and check if the player is still null for some reason. Maybe it’s not getting hold of the player correctly. Remind me, is the UnistSelectionHandler script attached to the player prefab?

“The asset ID refers to which source asset the object was instantiated from.”

Seems fine to me that they have the same Id.

Yes, the SelectionHandler script is attached and the player is displayed correctly too, but I also noticed that if I go to the server, the Units of the other player are not synchronized, I think the problem is somewhere there


YEAAA I FIXED PROBLEM!!! I just delete the [Command] attribute from the CmdMove method, and it works!

using Mirror;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.InputSystem;

namespace Units
{
    public class UnitMovement : NetworkBehaviour
    {
        [SerializeField] private NavMeshAgent agent;

        #region Server
        
        // [Command]
        public void CmdMove(Vector3 position)
        {
            if (!NavMesh.SamplePosition(position, out var hit, 1f, NavMesh.AllAreas)) return;
            Debug.Log($"Moving to {hit.position}");
            agent.SetDestination(hit.position);
            Debug.Log($"Destination set to {agent.destination}");
        }
        
        #endregion
    }
}

Thanks for the help, it was all very helpful for me

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms