0
\$\begingroup\$

This might be a really easy solution that I probably just do not know due to lack of experience so thanks for any and all the help. TLDR at bottom of post.

I'm still learning Unity / C# and I am following Brackey's Tower Defense tutorial series while adding my own twist. The tutorials use levels with only 1 available path for units to walk along. However, the game I am currently developing has 3 separate paths that units can walk along.

Essentially, the game is similar to the mobile game Clash Royale with 3 lanes except it is also a tower defense.

Here is the current layout: Map layout

The different lanes are empty gameObject labeled as Path1 (red), Path2 (blue), and Path3 (green). The nodes laid out in each path are all children objects of their respective path.

Each of the parent path objects contain the following script:

public class Waypoints : MonoBehaviour
{
    public static Transform[] points;

    private void Awake()
    {
        points = new Transform[transform.childCount];
        for (int i = 0; i < points.Length; i++)
        {
            points[i] = transform.GetChild(i);
        }
    }
}

Now, following the tutorial, I have also successfully added an enemy that contains this EnemyMovement script:

public class EnemyMovement : MonoBehaviour
{
    public float speed = 10f;

    private Transform target;
    private int waypointIndex = 7;

    void Start()
    {
        target = Waypoints.points[7];
    }

    void Update()
    {
        Vector3 dir = target.position - transform.position;
        transform.Translate(dir.normalized * speed * Time.deltaTime);

        if(Vector3.Distance(transform.position, target.position) <= 0.2f)
        {
            GetNextWaypoint();
        }
    }

    void GetNextWaypoint()
    {
        if(waypointIndex <= 0)
        {
            Destroy(gameObject);
            return;
        }

        waypointIndex--;
        target = Waypoints.points[waypointIndex];
    }
}

Now, as it currently stands, whenever I have an enemy present on the field, it will successfully run down path2 (blue nodes). However, it will ONLY run down path2. I would like to be able to decide which path the enemy will take. Eventually, the enemy's actions will be decided by an Enemy AI.

The player will also be able to spawn units and will be able to decide which path the unit will travel.

So to reiterate:

TL;DR: Following Brackey's Tower Defense tutorial. Currently, enemy will always default to path2. I need to figure out how to have control over which path, out of 3 options, an enemy or friendly unit will take.

\$\endgroup\$
3
\$\begingroup\$

There are many possible solutions to your problem. Some will be more reusable and flexible but for now, let's keep it simple and go with only few changes:

The problem with your current waypoint solution is that the Transform[] points array is static, which means all enemies see the same waypoints and the other two paths' waypoints are overwritten by the points your enemy script is seeing (each Waypoints gameobject creates a new array, thus overwriting the array created previously by a different waypoints gameobject).

For now I assume it is ok for the enemy to just pick one of the three paths randomly.

First, store all paths' waypoints in an unique Transform[] array within a list:

public class Waypoints : MonoBehaviour
{

    public static List<Transform[]> pathPoints = new List<Transform[]>();

    private void Awake()
    {
        Transform[] points = new Transform[transform.childCount];
        for (int i = 0; i < points.Length; i++)
        {
            points[i] = transform.GetChild(i);
        }
        pathPoints.Add(points);
    }
}

Each Waypoint will now add it's points array to the list instead of overwriting the existing pat

Next, modify your enemy script to randomly pick one of the available paths and then use the points of the picked path:

public class EnemyMovement : MonoBehaviour
{
    public float speed = 10f;

    private Transform target;
    private int waypointIndex = 7;
    private int selectedPath = 0;  // New

    void Start()
    {
        // Select between 0 and max path, currently 3 paths so this selects a random number between 0 and 2 (zero-based index)
        selectedPath = Random.Range(0, Waypoints.pathPoints.Count);
        waypointIndex = Waypoints.pathPoints[selectedPath].Length - 1;
        // Select the points array depending on selected path, and from there the waypoint
        target = Waypoints.pathPoints[selectedPath][waypointIndex];
    }

    void Update()
    {
        Vector3 dir = target.position - transform.position;
        transform.Translate(dir.normalized * speed * Time.deltaTime);

        if(Vector3.Distance(transform.position, target.position) <= 0.2f)
        {
            GetNextWaypoint();
        }
    }

    void GetNextWaypoint()
    {
        if(waypointIndex <= 0)
        {
            Destroy(gameObject);
            return;
        }

        waypointIndex--;
        target = Waypoints.pathPoints[selectedPath][waypointIndex];
    }
}

Here the Waypoints.pathPoints[selectedPath] gets the points array of the selected path form which we then can select the next waypoint. A good improvement would be to store the Waypoints.pathPoints[selectedPath] array inside the enemy for easier access.

Note that the number 7 should not be hardcoded in your script since the number of waypoints can change. Therefore I use the waypoint arrays Length-1 to get the last waypoint in the path array. This is also dependant on the order of your waypoints in the Gameobject hierarchy.

Regarding the Random.Range(): As stated in the documentation for integers this returns a random integer number between min [inclusive] and max [exclusive] (not so for floats). So we can use it to select an existing path from our pathPoints list.


In a different approach (much more changes) you could make the Transform[] points non-static. Then in your game manager / enemy spawner assign references to each of the waypoints in your scene. The manager can then tell the newly spawned enemy which path to take.

\$\endgroup\$
1
  • \$\begingroup\$ Worked wonderfully, thank you! :) \$\endgroup\$ – Kalfin Feb 26 '20 at 16:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.