Random failure of SamplePosition

Hiya,

Unity 2020.3.26f1

I’ve noticed a random failure of SamplePosition after this lecture. I’ve added some debugs to PlayerController and identified that I return false out of RayCastNavMesh because the SamplePosition returns false. Further debugs show that when successful, the hit.point and the NavMeshHit.position are the same (or very close), but when the cursor reports no available action, the debug shows that the hit.point is confirmed, but the NavMeshHit.position is infinity.

I’ve reworked my landscape and cleared/rebaked my navmesh - no joy (and client restarts, of course).

Changing the maxNavMeshProjectionDistance seems to work, but tends just to move the problem around the terrain (ie different points report this issue).

Any ideas?

CT

Paste in your RayCastNavMesh method, and we’ll take a look.

using RPG.Attributes;
using RPG.Movement;
using System;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.EventSystems;

namespace RPG.Control
{
    public class PlayerController : MonoBehaviour
    {
        Health health = null;

        [Serializable]
        public struct CursorMapping
        {
            public CursorType type;
            public Texture2D texture;
            public Vector2 hotspot;
        }

        [SerializeField] CursorMapping[] cursorMappings = null;
        [SerializeField] float maxNavMeshProjectionDistance = 1.0f;
        [SerializeField] float maxPathLength = 40.0f;

        void Awake()
        {
            health = GetComponent<Health>();
        }

        void Update()
        {
            if (InteractWithUI()) { return; }
            if (health.IsDead())
            {
                SetCursor(CursorType.None);
                return; 
            }

            if (InteractWithComponent()) { return; }
            if (InteractWithMovement()) { return; }

            SetCursor(CursorType.None);
        }

        private bool InteractWithUI()
        {
            if (EventSystem.current.IsPointerOverGameObject())
            {
                SetCursor(CursorType.UI);
                return true;
            }
            return false;
        }

        private bool InteractWithComponent()
        {
            RaycastHit[] hits = RaycastAllSorted();
            foreach (RaycastHit hit in hits)
            {
                IRaycastable[] raycastables = hit.transform.GetComponents<IRaycastable>();
                foreach (IRaycastable raycastable in raycastables)
                {
                    if (raycastable.HandleRaycast(this))
                    {
                        SetCursor(raycastable.GetCursorType());
                        return true;
                    }
                }
            }
            return false;
        }

        private bool InteractWithMovement()
        {
            Vector3 target;
            bool hasHit = RaycastNavMesh(out target);

            if (hasHit)
            {
                if (Input.GetMouseButton(0))
                {
                    GetComponent<Mover>().StartMoveAction(target, 1f);
                }
                SetCursor(CursorType.Movement);
                return true;
            }
            return false;
        }

        private bool RaycastNavMesh(out Vector3 target)
        {
            target = new Vector3();

            RaycastHit hit;
            bool hasHit = Physics.Raycast(GetMouseRay(), out hit);
            if (!hasHit)
            {
                return false;
            }

            NavMeshHit navMeshHit;
            bool hasCastToNavMesh = NavMesh.SamplePosition(hit.point, out navMeshHit, maxNavMeshProjectionDistance, NavMesh.AllAreas);
            if (!hasCastToNavMesh)
            {
                //NavMeshPath tempPath = new NavMeshPath();
                //target = navMeshHit.position;
                //NavMesh.CalculatePath(transform.position, hit.point, NavMesh.AllAreas, tempPath);
                Debug.Log($"Hit point {hit.point}.");
                //Debug.Log(target);
                //Debug.Log(GetPathLength(tempPath));
                Debug.Log($"NavMeshHit position = {navMeshHit.position}.");
                Debug.Log("Has not cast to navmesh");
                return false;
            }

            target = navMeshHit.position;

            NavMeshPath path = new NavMeshPath();
            bool hasPath = NavMesh.CalculatePath(transform.position, target, NavMesh.AllAreas, path);
            if (!hasPath)
            {
                return false; 
            }
            if (path.status != NavMeshPathStatus.PathComplete)
            {
                return false;
            }
            if (GetPathLength(path) > maxPathLength)
            {
                return false;
            }
            Debug.Log($"Hit point {hit.point} and NavMeshHitPosition {navMeshHit.position}.");
            return true;
        }

        private float GetPathLength(NavMeshPath path)
        {
            float total = 0.0f;
            if (path.corners.Length < 2) { return total; }

            for (int i = 1; i < path.corners.Length; i++)
            {
                total += Vector3.Distance(path.corners[i - 1], path.corners[i]);
            }
          
            return total;
        }

        private void SetCursor(CursorType type)
        {
            CursorMapping mapping = GetCursorMapping(type);
            Cursor.SetCursor(mapping.texture, mapping.hotspot, CursorMode.Auto);
        }

        private CursorMapping GetCursorMapping(CursorType type)
        {
            foreach (CursorMapping mapping in cursorMappings)
            {
                if (mapping.type == type)
                {
                    return mapping;
                }
            }
            return cursorMappings[0];
        }

        private RaycastHit[] RaycastAllSorted()
        {
            RaycastHit[] hits = Physics.RaycastAll(GetMouseRay());
            float[] distances = new float[hits.Length];
            for (int i = 0; i < hits.Length; i++)
            {
                distances[i] = hits[i].distance;
            }
            Array.Sort(distances, hits);
            return hits;
        }

        private Ray GetMouseRay()
        {
            return Camera.main.ScreenPointToRay(Input.mousePosition);
        }
    }
}

Hey Brian,

I’ve had a variety of plays.

  1. Replacing my PlayerController with the vanilla course
  2. Putting the camera back to the course camera (I had implemented the zoom/rotation version)
  3. Disabling my terrain and replacing it with a new flat one

The last one worked, so there must have been some terrain issue causing the problem. Will finish off this section and see if the Visual Polish section cleans it all up.

Thanks for looking, and sorry for the runaround.

CT

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

Privacy & Terms