Sadly I’ve wasted quite a few hours trying to crack this using an Array, but I keep failing.

With an Array I’ve been able to select a random GameObject and populate an object field using…

WayPointArray = (GameObject.FindGameObjectsWithTag("WayPoint"));

with

other.GetComponent<NPC_AI>().WayPoint = NPCWayPoint;

To find a way to get my NPCs to walk to random waypoints.

Naturally rather than having my NPCs active across a large map, I’m trying to keep them local to the player. Having a map of Spawn and WayPoint objects which direct the NPCs where to walk to next within an area.

On ‘Start’ the WayPoint script finds GameObjects tagged with ‘WayPoint’, and when it’s collider is triggered by an NPC, the script delivers a position for the NPC to go to. …using the code exampled above.

Only the problem is, my coding isn’t great and I can’t get the individual Arrays to only find tagged WayPoints within a small distance from each other, building a mesh of points that help the NPCs go A>B rather than A>Z across the map. My limitations in code means each WayPoint finds every WayPoint Tag across the map. Not ideal.

So I’ve now turned to Lists instead (for the first time), finding that On Start I can now get each WayPoint to find each other within a distance using a collider. (Couldn’t with an Array)

public List<GameObject> WayPoints;
void OnTriggerStay(Collider other)
{
    if (other.tag == "WayPoint")
    {
        if (!WayPoints.Contains(other.gameObject))
        {
            WayPoints.Add(other.gameObject);
        }
    }
}

With that working as hoped, I now have the opposite problem where I can’t get my other NPC_AI script to select a random WayPoint GameObject from the above.

Is there anyone that can help? The only way I could easily get my WayPoints to find each other close by, was to switch to lists instead.

As I mentioned, I’m not brilliant at coding generally and have managed with Arrays till now, but Lists so far have been alien to me and not as similar as I was hoping.
Any help I’d be really grateful. Thank you!!

the lazy way to do it would be linq

convert to array and reuse your old code

using System.Linq;

//  ... 
WayPoint [] waypointsArray  = WayPoints.ToArray();
yourOriginalMethodOfRandomSelection ( waypointsArray );
//  ...

or keep the lists and work directly on them

using System.Linq;
// .... 
var R  = new Random();
var randomWP = WayPoints.Skip(R.Next(WayPoints.Count())).First();
  • both have a performance impact
  • which one is faster depends on how long your list is

( the collider idea is kinda clever :slight_smile: )

Hey there,

as this information is only needed to be created once and using colliders is smart but bad on performance let me introduce you to the wonderful world of editor scripts:

#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;

//assuming your waypoint class has these variables:
public class Waypoint : MonoBehaviour
{
    public Waypoint[] nextWaypoints;
    // distance value of this specifc waypoint. if distance between 2 points is less then their dist sum you can move between them.
    public float maxWaypointDistance = 100f; // point of this is to give individual waypoints a way to generate a smaller grid..
}

public class EditorCustomCommands
{
    [MenuItem("CustomCommand/Initialize Waypoints")]
    public static void initializeWaypoints()
    {
        //find all "waypoints" in the current open scene:
        var allWaypoints = UnityEngine.Object.FindObjectsOfType<Waypoint>();
        //create an array of buffer lists for neighbour waypoints of each waypoint:
        var waypointBuffer = new System.Collections.Generic.List<Waypoint>[allWaypoints.Length];
        for (int i = 0; i < allWaypoints.Length; i++)
        {
            for (int j = 0; j < allWaypoints.Length; j++)
            {
                //check if the relation between these 2 points has already been discovered:
                if (waypointBuffer*.Contains(allWaypoints[j]))*

continue;
//check if the distance between these 2 waypoints is less than their added max waypoint distances:
if (allWaypoints_.maxWaypointDistance + allWaypoints[j].maxWaypointDistance > Vector3.Magnitude(allWaypoints*.transform.position - allWaypoints[j].transform.position))
{
//in this case we can move between the 2 waypoints and thus buffer this information:_
_waypointBuffer.Add(allWaypoints[j]);_
_waypointBuffer[j].Add(allWaypoints);
}
}
}
// now we have processed all waypoints so it is time to save the information on the object:
for (int i = 0; i < allWaypoints.Length; i++)
{
//this is needed to be able to save the changes in the scene later on:_

_Undo.RecordObject(allWaypoints, “set new next waypoint array”);
allWaypoints.nextWaypoints = waypointBuffer.ToArray();
//this is needed to be able to save the changes in the scene later on as well:_

_PrefabUtility.RecordPrefabInstancePropertyModifications(allWaypoints);
}
}
}
#endif*

What this does (in theory at least) is create a button in your top menu in the editor which you can click to automatically set all waypoint relations in your current scene.
These are then saved in the nextWaypoints array of each waypoint.
Let me know if anything in there is unclear. I hope the comments in the code explain everythin as needed._

Wow @Captain_Pineapple thank for such detailed help and effort on my behalf. I never knew something like that was possible. Great that you can get the editor to do the leg work, rather than manually or in game.

However I’m having issues making it work. I’ve tried changing some of my labelling to accommodate your script, but so far it doesn’t seem to be making any changes. It’ll tell you what I’ve got setup…

I have a test scene with a grid of waypoints 10x&y apart. Generally labelled NPC_Destination(XX) and have made sure the tags on these are ‘Waypoint’ as described in your code, and reinstated the Arrays again with your naming convention ‘nextWaypoints’.

Hitting ‘Initialise Waypoints’ does nothing so far. :frowning:

After my first failed attempt, I wasn’t sure of FindObjectsOfType<Waypoint> so I tried changing all tags to that and even also the name on some of the waypoints to ‘Waypoint’, in case. But no joy, and not sure how to get your script to recognise my waypoints, or change my objects to match that label.

How should I be setting up my waypoints?

Thank you so much, this help is incredible and far beyond what I expected.

[Edit] For some reason the Waypoint script didn’t show properly in the inspector when attached to an object/waypoint, despite the console being clear. …went to lunch, came back, suddenly they’re now loading properly. FindObjectOfType I’m guessing must relate to the script - find all objects with ‘Waypoint’ attached.

Now when I hit ‘Initialise Waypoints’, I get an error …Object reference not set to instance of an object - line 30 if (waypointBuffer*.Contains(allWaypoints[j]))*
I’m now trying to work that one out. Thanks again!