Move an object through a set of positions

Okay, I know this should be much more straightforward than I'm finding but my brain is mush today, sorry.

In the level i'm making I want characters to patrol back and forth over an area repeatedly - specifically travel through a set of waypoints. I've been reading up on Angry Ant's Path and Aron Granberg's A* Pathfinding for a future project, but for this I don't need actual pathfinding since the characters don't have to go anywhere other than along their set path. They will have a vision cone or torchlight that, when it touches the player, will reset the players position. Basically a really simple stealth game.

Last year I modified the SeekSteer script on the wiki to have a character move along a set of waypoints but it was a bit of a rushed job and it had some problems. I'm returning to it now and starting from scratch. I'm using the Lerp function as described in this post to move my object to the new position and i've combined that script with my waypoint one (it looks nothing like SeekSteer now by the way).

I rewrote my old script since I had the unwanted effect of easing in and out of positions - where that came from I don't know - but aside from that it worked. I'm using the same code here, the only real difference is the method to move the character and the old script had a radius for each waypoint. There are currently 3 transforms in the waypoints array to make an 'L' shape. But after the character reaches the first waypoint I get an Index Out of Range error.

As far as I can tell, the part where the targetwaypoint variable is being incremented is suspect but this wasn't a problem in the other script despite being in the Update function.

// array to hold waypoint locations
var waypoints : Transform[];

// variable to control time taken to travel between points
var duration : float = 1.0;

private var startPoint : Vector3;
private var endPoint : Vector3;
private var startTime : float;

// the array index number of the current target waypoint
private var targetwaypoint : int;

function Start() {
    startPoint = transform.position;
    startTime = Time.time;

    if(waypoints.Length <= 0){
    Debug.Log("No waypoints found");
    enabled = false;
    }

    targetwaypoint = 0;
    endPoint = waypoints[targetwaypoint].position;
    }

function Update () {

   transform.position = Vector3.Lerp(startPoint, endPoint, (Time.time - startTime) / duration);

if(transform.position == endPoint){

    targetwaypoint++;

    endPoint = waypoints[targetwaypoint].position;

        // if this new target is the last item in the array
        if(targetwaypoint>=waypoints.Length){

            targetwaypoint = 0;
        }
    }

}

I think your "super fast" problem is occuring because you're not resetting the startTime variable when you increment the targetwaypoint counter. This means that for every transition after the first one, the duration has already elapsed.

As for the 'index out of range' error, I would guess that's occuring because you're assigning the new endPoint before you check whether the targetwaypoint variable should be wrapped back to zero.

Move the line:

endPoint = waypoints[targetwaypoint].position;

...to after the check where you test if it's the last item in the array. (remember, array access is zero-indexed, so if targetwaypoint == waypoints.Length, then targetwaypoint isn't a valid index!

(If your array is 8 items long, the first item is at position zero, and the last item is at position 7!)

Also, you might be interested in a neat way of "wrapping" your integer index counter using the modulus operator.

Also, I've moved the Lerp interpolation value to a separate variable for shorter line length, and fixed the indentation :)

So, with these fixes, your could might look like this.

// array to hold waypoint locations
var waypoints : Transform[];

// variable to control time taken to travel between points
var duration : float = 1.0;

private var startPoint : Vector3;
private var endPoint : Vector3;
private var startTime : float;

// the array index number of the current target waypoint
private var targetwaypoint : int;

function Start() {

    startPoint = transform.position;
    startTime = Time.time;

    if(waypoints.Length <= 0){
        Debug.Log("No waypoints found");
        enabled = false;
    }

    targetwaypoint = 0;
    endPoint = waypoints[targetwaypoint].position;
}

function Update () {

    var i = (Time.time - startTime) / duration;
    transform.position = Vector3.Lerp(startPoint, endPoint, i);

    if(i >= 1){

        startTime = Time.time;

        // increment and wrap the target waypoint index
        targetwaypoint++;
        targetwaypoint = targetwaypoint % waypoints.Length;

        // assign the new lerp waypoints
        startPoint = endPoint;
        endPoint = waypoints[targetwaypoint].position;

    }
}

I've been looking into stepping back through the array when I reach the end. I didn't achieve that yet (seemed to have become a bit distracted in the process!) but I've modified my code quite a bit so thought I would post it here as an alternate solution.

Now i'm using a normal Javascript array rather than an in-built one (although i've read in-built ones are faster). This approach allows me to use the Shift and Add functions to achieve the same effect as Duck's modulus approach (as far as I can tell) and also means that the array is resizeable. Since Javascript arrays can't be modified from the editor i've added some script to automatically add the waypoints to the array at initialisation (much more efficient than dragging them into the editor).

Currently I have an empty object called waypoints with child cubes for the individual waypoints. The script is attached to the NPC and so has to find the waypoint object's children (took me a while to get that working!). I'd be happy to hear and comments/criticism, and thanks once again to you Duck for your help.

// array to hold waypoint locations
var waypoints = new Array();

// variable to control time taken to travel between points
var duration : float = 1.0;

private var startPoint : Vector3;
private var endPoint : Vector3;
private var startTime : float;

private var wp : Transform;

// the array index number of the current target waypoint
private var targetwaypoint : int;

function Start() {
    startPoint = transform.position;
    startTime = Time.time;

    // store a reference to the transform of the waypoints object
    wp = GameObject.Find("waypoints").transform;

    // for each of the child objects of the waypoints object
    for (var child : Transform in wp) {

        // add them to the waypoints array
        waypoints.Push(child);
    }   

    if(waypoints.length <= 0){
        Debug.Log("No waypoints found");
        enabled = false;
    }

    targetwaypoint = 0;

    // set the initial end point to the first item in the array
    endPoint = waypoints[targetwaypoint].position;
    }

function Update () {

    var i = (Time.time - startTime) / duration;
    transform.position = Vector3.Lerp(startPoint, endPoint, i);

    // if we have reached the target
    if(i >= 1){

        // store the current time as the new start time
        startTime = Time.time;

        // store the value of the current item in the array and remove it from the array
        currentwaypoint = waypoints.Shift();
        // add the previously removed item to the end of the array
        waypoints.Add(currentwaypoint);

        // set our start point to our current position
        startPoint = endPoint;

        //set our new endpoint to the position of the new target waypoint
        endPoint = waypoints[targetwaypoint].position;

    }

}

Use this code add as many waypoint you want.

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

[RequireComponent(typeof(Rigidbody2D))]
public class SquareMovement : MonoBehaviour {

[SerializeField]
private List<Transform> wayPoints;

public float speed = 10f;

private Transform target;
private int waypointIndex = 0;

// Use this for initialization
void Start ()
{
    target = wayPoints[0];
}

// Update is called once per frame
void Update ()
{
    Movement();
}

//methode which decide which axis to move
void Movement()
{
    Vector3 dir = target.position - transform.position;
    transform.Translate(dir.normalized * speed * Time.deltaTime , Space.World);

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

}

void GetNextWayPoint()
{
    if (waypointIndex >= wayPoints.Count - 1)
    {
        waypointIndex = 0;
    }
    else
    {
        waypointIndex++;
    }

    target = wayPoints[waypointIndex];
}

}