[Code review] wandering NPC's on a NavMesh

Hey, I’m looking for some insight on this script I made for wandering NPC’s.

If anyone has any critiques, suggestions, refactoring tips, or any comments I would love to hear them.

The specific script I am asking for a review on if called NCP_Patroll.cs

it can be found in my github project under nav-Experiments/Assets/This-Project/Scripts/NPC_Patrol.cs

The main ideas behind the script are for an NPC to cast rays out in a view range, collect a series of hit navigation points into an array, pick the farthest point and navigate to it.
once the NPC has a nav point it will stop casting rays for overhead reasons.

the project can be found here GitHub - JacobAButler/nav-Experiments

Here is the code for the script if that is better

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class NPC_Patrol : MonoBehaviour
{

  // The number of rays
  [SerializeField]
  public int _rayNumber = 5;

  // The view range in degrees.
  [SerializeField]
  public int _viewRange = 210;

  // The distance between the rays.
  [SerializeField]
  public int _separation;

  // The direction of the ray.
  [SerializeField]
  public Vector3 _rayVector;

  // The length of the ray.
  [SerializeField]
  public float _rayLength = 10f;

  // The distance between NPC and navPoint.
  [SerializeField]
  public float _dist;

  // The height of the ray from the ground.
  [SerializeField]
  Vector3 _rayHeight = new Vector3(0.12f,.05f,0);

  // May have to move this back into update
  [SerializeField]
  public RaycastHit _hit;

  // Array of navPoints hit by the NPC
  [SerializeField]
  public Vector3[] _hitNavPoints;

  // The destination chosen from _hitNavPoints
  [SerializeField]
  public Vector3 _destination;

  // The
  [SerializeField]
  public float _maxDistance;

  // Check to see in the NPC is moving
  [SerializeField]
  public bool _onRoute = false;

  // NavMeshAgent component
  NavMeshAgent _agent;


    // Start is called before the first frame update
    void Start()
    {
      _agent = this.GetComponent<NavMeshAgent>();
      _destination = transform.position;
      if (_agent == null)
      {
        Debug.LogError("The nav mesh agent component is not attached to " + gameObject.name);
      }
      _hitNavPoints = new Vector3[_rayNumber];
      // When _hitNavPoints is initialized all the indicies are given a Vector3 and (0,0,0),
      // if all the rays do not hit a navPoint on the first call,
      for (int i = 0; i < _rayNumber; i++)
      {
        _hitNavPoints[i] = transform.position;
      }
    }

    // Update is called once per frame
    void Update()
    {
      if(_onRoute==false)
      {
        _hitNavPoints = drawRays();
        _destination = findDestination(_hitNavPoints);
        setDestination(_destination);

        turnAround(_hitNavPoints);

      }
      //drawRays();

      if(_onRoute && _agent.remainingDistance <= 1.0f)
        {
            _destination = transform.position;
            _onRoute = false;
        }
    }
    Vector3[] drawRays()
    {
      _rayVector = transform.TransformDirection(Vector3.right);
      // the view range divided by the number of rays.
      _separation = _viewRange/_rayNumber;
      for(int i = 0; i < _rayNumber; i++)
      {
        //Need to figure out why there is not a ray for when i == 0
        _rayVector = Quaternion.Euler(0, (_separation)%_viewRange, 0) * _rayVector;
        Debug.DrawRay(transform.position + _rayHeight, -_rayVector*_rayLength, Color.green);
        //**************************************
        //******This is what works for now******
        //**************************************
        if (Physics.Raycast(transform.position+ _rayHeight, -_rayVector , out _hit, _rayLength))
        {
          _hit.collider.gameObject.tag = "NPC_Hit";
          _hitNavPoints[i] = _hit.point;
        }
        else
        {
          _hitNavPoints[i] = transform.position;
        }
      }
      return _hitNavPoints;
    }


    Vector3 findDestination(Vector3[] hitNavPoints)
    {
      Vector3 nextDestination = transform.position;
      _maxDistance = 0;

      for(int i = 0; i<hitNavPoints.Length;i++)
      {
        _dist = Vector3.Distance(hitNavPoints[i], transform.position);
        if (_dist>_maxDistance)
        {
          _maxDistance = _dist;
          nextDestination = hitNavPoints[i];
        }
      }
      return  nextDestination;
    }

    void setDestination(Vector3 destination)
    {

      if (destination!=transform.position)
      {
        _onRoute = true;
        _agent.SetDestination(_destination);
      }
    }

    void turnAround(Vector3[] _hitNavPoints)
    {

    }
}

SerializeField is for private fields. Using it on those public variables is redundant, assuming it doesn’t cause some unexpected behavior (I’ve never tried it).

Access modifies aren’t my strong suit, but I had them like that so I could see everything in the inspector, thanks for the info.