Need help with making an AI car follow a path

Hello!
I am making a game where you have to follow an AI controlled car, that moves through a path, that is infinitely generated as the game goes on. On a random chance, a 3 way exit can be spawned, of which , the AI car has to take one of them. I tried doing this by adding nodes onto the prefabs and then making the car follow those nodes, but i’m running into many problems. keep in mind that the car always is turning at the same angle, so i don’t need a complected path finding script. Also remember that the nodes are being generated in playtime.
This is what I’ve tried:

 void Update()
    {
        activeNodes = GameObject.FindGameObjectsWithTag("Node");

        if (activeNodes[0] != null)
            if (activeNodes[nodeIndex].transform.position.z > transform.position.z)
                target = activeNodes[nodeIndex].transform;
            else
                nodeIndex++;

       

        dir = target.transform.position - transform.position;
        dir = dir.normalized;
        Debug.Log(dir);

       

        speed = GetComponent<Rigidbody>().velocity.z;
        Time.timeScale = 1;

       
       
    }
    private void OnCollisionEnter(Collision collision)
    {
        nodeIndex = 0;
    }

    private void FixedUpdate()
    {
       

        if(speed < MaxSpeed)
        {
            GetComponent<Rigidbody>().AddForce(dir * Acceleration);
            //GetComponent<Rigidbody>().AddForce(new Vector3 (0,0,1) * Acceleration * 100);
        }
    }

Thanks for any help!

I would tackle this by using a stack and a node controller.

So the node controller is a separate object, that can create nodes on the fly. It should be static so that as your map builds, it simply calls the static node creator and adds the points needed.

Your car then can simply ask for the next item in the stack. So, say your car holds a Transform from the stack. It asks teh stack when it reaches that point, to give it the next transform based off of the current transform. If the transform does not exist, (or is null) then it will give back teh first transform on the list.

Now, you simply have to manage the list as you create track parts. If you hold 50 track parts, then all you have is 50 nodes to handle.

Remember… this is a Stack, not an Array.

This does 2 things…

  1. creates a simple follow system that your vehicle can follow, that can be relatively infininte.
  2. stops using the GameObject.Find method which hinders processor usage.
1 Like

The thing is, When i generate Path pieces, The nodes are actually part of the prefabs that are spawned randomly. i do this because the nodes are different on each different piece of ground. How would i get the nodes that are already being generated, and put them into a stack?

Ok, let me put it in a way I can understand it. and hopefully it will work over for you.

Imagine that we are creating a race game, and each track piece is supposed to fit together to make a race track. Now, imagine we have only 4 sections of track we want to lay down. Straight, right, left and Y. with the following rules:

The straight piece can have any of the parts
The right turn, can only accept a left turn or straight piece
The left turn, can only accept the right turn or straight piece.
The Y can only accept a straight piece.

Next we create prefabs to make the rules. 4 prefabs, each with a Script (RaceNode) that will let us assign which nodes can be placed. Remember, to create all your prefabs, then assign the prefab to the list, then save it back to the prefab.

using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class RaceNode : MonoBehaviour
{
    // spawnable positions are rotated for the next node to dock with it.
    public Transform[] spawnablePositions;
    // a list of nodes this node can spawn
    public GameObject[] spawnableNodes;
    // a list of spawned target nodes
    private GameObject[] spawnedTargets;

    // spawn each node for targeting
    // do not do this on instantiate, it will lock your game up
    public GameObject[] SpawnChildren()
    {
        if (spawnablePositions == null) spawnablePositions = new Transform[0];
        if (spawnableNodes == null) spawnableNodes = new GameObject[spawnablePositions.Length];
        if (spawnedTargets == null) spawnedTargets = new GameObject[spawnablePositions.Length];

        for (var i = 0; i < spawnedTargets.Length; i++)
        {
            var spawnedTarget = spawnedTargets[i];
            if (spawnedTarget == null)
            {
                var spawnablePosition = spawnablePositions[i];
                if (spawnableNodes.Length > 0 && spawnablePosition != null)
                {
                    var node = spawnableNodes[Random.Range(0, spawnableNodes.Length)];
                    if (node != null)
                    {
                        spawnedTarget = Instantiate(node, spawnablePosition.position, spawnablePosition.rotation);
                        spawnedTargets[i] = spawnedTarget;
                    }
                }
            }
        }

        return spawnedTargets;
    }

    // get the next random node
    public GameObject GetNextTarget()
    {
        var available = this.spawnedTargets.Where(p => p != null).ToArray();
        if (available.Length == 0) return null;
        return available[Random.Range(0, available.Length)];
    }

    public static void SpawnTrack(GameObject root, int n)
    {
        var work = new List<GameObject>() {root};
        var children = new List<GameObject>();

        for (var i = 0; i < n; i++)
        {
            foreach (var obj in work)
            {
                var node = obj.GetComponent<RaceNode>();
                if (node != null)
                {
                    children.AddRange(node.SpawnChildren());
                }
            }

            work = children.ToList();
            children.Clear();
        }
    }
}

We add our first piece to the board. We also need a script that will start everything (not included)

Now, with this, we call, SpawnChildren() and it will return the spawned targets. With this, we use SpawnTrack(gameObject, 5) to loop through 5 iterations of track down each respective path.

Now, you need to get the target you are heading towards. GetNextTarget() With this, when you get to that target, you do 2 things… 1 spawn 5 children of that target, (thus increasing your map) and you get the next target. Now, the beauty of it, is that when you spawn 5 more targets

Pass 100 targets, and your race is done. :wink:

Yes, there is quite a bit more to this… Track cleanup, maybe some parenting to help keep your mind straight.

1 Like

Thank you! this is exactly the help i needed. I will try to re-wire your code to get it to work in my current situation. Thanks again, i really appreciate it!