# How can I loop over waypoints to move all the objects between them?

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

public class Waypoints : MonoBehaviour
{
public enum RotationMode
{
Normal, Curved
}

public GameObject objectToDuplicate;
public Transform[] waypoints;
public float movingSpeed;
public bool randomSpeed = false;

private GameObject[] prefabsToMove;

private void Start()
{
prefabsToMove = GameObject.FindGameObjectsWithTag("FrameLine");
DuplicatePrefabEffects(prefabsToMove.Length);
}

private void DuplicatePrefabEffects(int duplicationNumber)
{
for (int i = 0; i < duplicationNumber; i++)
{
var go = Instantiate(objectToDuplicate);
go.tag = "Duplicated Prefab";
go.name = "Duplicated Prefab";
}
}

private void WaypointsAI()
{
for (int i = 0; i < waypoints.Length; i++)
{
if (randomSpeed)
{
movingSpeed = Random.Range(1, 20);
}
prefabsToMove[i].transform.position = Vector3.MoveTowards(
prefabsToMove[i].transform.position,
waypoints[i].position,
movingSpeed * Time.deltaTime
);
}
}

void Update()
{
WaypointsAI();
}
}


The problem is inside the loop there might be less or more prefabsToMove then waypoints so it will throw exception.

Then doing prefabsToMove[i] is wrong.

• You don't need to use the same index i for the prefab and the waypoint. Which waypoint do you want each prefab to move towards? – DMGregory Feb 10 '18 at 15:39
• @DMGregory I want each prefab to move between all the waypoints with random speed each prefab with another speed. – Daniel Lip Feb 10 '18 at 15:51

Like I mentioned in the last answer, you can solve this by keeping a parallel array of data about how each instance should move. There, it was the object's speed. Here, we add the index of the waypoint it's supposed to drive toward. That way we can simulate object 1 on its way to waypoint 4 while object 5 is still working to reach waypoint 3, and they don't interfere with each other.

// Adding selectable behaviour at the end of the path,
// as requested from the comments.
public enum PathCompleteBehaviour {
Stop,
Loop,
Reverse
}
public PathCompleteBehaviour completeBehaviour;

// Store parallel arrays for our movement parameters.
private float[] movementSpeeds;    // Randomized speed per object.
private int[] nextWaypointIndices; // Destination per object.

private void Start()
{
// Changing terminology to be more standard.
// - a "prefab" is a source asset you want to copy
// - an "instance" is a copy of it that's been spawned in the scene
instancesToMove = GameObject.FindGameObjectsWithTag("FrameLine");

movementSpeeds = new float[instancesToMove.Length];
nextWaypointIndices = new int[instancesToMove.Length];

for(int i = 0; i < instancesToMove.Length; i++)
movementSpeeds[i] = Random.Range(minSpeed, maxSpeed);
}

private void WaypointsAI()
{
// We want to iterate over the instances, not over the waypoints.
for (int i = 0; i < instancesToMove.Length; i++)
{
// Check to see if we reached the last waypoint.
// If so, stop / loop / turn around as needed.
int waypointIndex = nextWaypointIndices[i];
if(waypointIndex < 0 || waypointIndex >= waypoints.Length) {
switch(completeBehaviour) {
case PathCompleteBehaviour.Stop:
// Leave it where it is and skip to the next instance.
continue;
case PathCompleteBehaviour.Loop:
// Wrap front to back / back to front.
waypointIndex = (waypointIndex + waypoints.Length) % waypoints.Length;
break;
case PathCompleteBehaviour.Reverse:
// Bounce back to the point before last.
waypointIndex += (movementSpeeds[i] > 0f) ? -2 : 2;
// Reverse direction.
movementSpeeds[i] *= -1f;
break;
}
nextWaypointIndices[i] = waypointIndex;
}

// Look up the waypoint we want to move toward next.
Vector3 waypoint = waypoints[waypointIndex].position;

// to compute how far it should move in this frame.
float travel = Mathf.Abs(movementSpeeds[i]) * Time.deltaTime;

// Apply the motion.
Vector3 position = instancesToMove[i].transform.position;
position = Vector3.MoveTowards(position, waypoint, travel);
instancesToMove[i].transform.position = position;

// If we're within a configurable tolerance of the
// destination waypoint, set our destination
// to the next waypoint after it.
if((position - waypoint).sqrMagnitude < 0.1f) {
nextWaypointIndices[i] += (movementSpeeds[i] > 0f) ? 1 : -1;
}
}
}

• I've added the three options, using the sign of the movement speed to track whether we're moving forward through the waypoints or backwards. – DMGregory Feb 10 '18 at 19:07
• The code is working but there are two small problems. The first when it's on loop mode the loop is a ping pong between the last waypoint and the one before the last. But loop should be from the last waypoint to the first one then to the second and the last and so on. Second problem is with reverse the objects are coming to the first waypoint second and last then return back to the second and first then moving forward. But reverse as I see it should be in start objects should go to the last waypoint then to the first second last reverse direction. – Daniel Lip Feb 10 '18 at 20:26
• I'm unable to reproduce the ping-pong effect that you describe on loop mode. When I run this code with 3 waypoints, my objects move from waypoint 0 to waypoint 1, 2, back to 0, 1, 2, 0, 1, 2... As for the reverse behaviour, remember this was requested in the context of "how to change what the objects do at the end of the path - not how they should begin. That's why it's described as a path complete behaviour in the code above. You're welcome to change the starting direction yourself if you like (hint: all you need to do is change the initial values of movementSpeeds & nextWaypointIndices) – DMGregory Feb 10 '18 at 20:58