How can I move an object from point to point in an array of points?

It seems like this should be simple enough, but I am struggle. Not to mention, I really struggle with for().

My goal is to set up an array of transforms/ points to move to. Then when the player enters the collider, the player is centered on the object and the object moves from position to position in the array of transforms.

Here’s what I’ve got so far, but it is doing jack sh**:

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

public class CloudSurfActivator : MonoBehaviour
{
    public GameObject barrier;
    private bool cloudSurfing;
    public Rigidbody2D theRB;
    private Vector2 moveDirection;
    public float speed;
    public Transform[] pointToMoveTo;

    // Start is called before the first frame update
    void Start()
    {
        barrier.SetActive(false);
        cloudSurfing = false;
    }

    // Update is called once per frame
    void Update()
    {
        if (cloudSurfing)
        {
           

            for (int i = 0; i < pointToMoveTo.Length; i++)
            {
                moveDirection = pointToMoveTo[i].position - transform.position;

                if (Vector3.Distance(transform.position, pointToMoveTo[i].position) > .5f)
                {
                    i++;
                }

            }
           
            moveDirection.Normalize();
        }

        theRB.velocity = moveDirection * speed;
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.tag == "Player")
        {
            PlayerController.instance.canWalk = false;
            PlayerController.instance.transform.position = this.transform.position;

            barrier.SetActive(true);
            cloudSurfing = true;
        }
    }
}

You don’t want to be looping through all of your points inside a single update call. Remember Update runs once every frame. You won’t be moving through all of your points in a single frame, just a little bit towards the next point. Instead, keep an int index around that means “The current point I’m moving to”. When you get close enough to the next point, you set the next point after that as the next point by incrementing your index. Something like:

int currentCloudIndex;

void Update() {
  if (cloudSurfing) {
    Vector3 currentPoint = pointToMoveTo[currentCloudIndex];
    // CODE HERE TO MOVE A LITTLE BIT TOWARDS currentPoint 
 
    if (/* code here to check if you are close to currentPoint */) {
       currentCloudIndex++;
    }

    if (currentCloudIndex >= pointToMoveTo.Length) {
      // We've moved to all the points.
      isCloudSurfing = false;
    }
  }
}

I haven’t written everything for you. But this is the gist of it.

OK this makes a lot of sense. I’m going to take a crack at this and check back in.

OK so I think I’m getting closer but I’m still having some issues.

Right now the object/ vehicle is now just heading in a random direction that seems to be a median of all positions in the array pointToMoveTo, and it just keeps going, never stopping or reaching any point.

Getting this error:
IndexOutOfRangeException: Index was outside the bounds of the array.

    void Update()
    {
        if (cloudSurfing)
        {
            Debug.Log("CloudSurfing bool " + cloudSurfing);

            moveDirection = pointToMoveTo[currentPoint].position - transform.position;

            if (Vector3.Distance(transform.position, pointToMoveTo[currentPoint].position) > .5f)
            {
                Debug.Log("Reached point.");
                currentPoint++;
            }

            if(currentPoint >= pointToMoveTo.Length)
            {
                cloudSurfing = false;
            }

           
        }

        moveDirection.Normalize();
        theRB.velocity = moveDirection * speed;
    }

First, your Logic at line 9. is wrong, you say as long as the distance is further then 0.5f , you reached the point and you want to go to the next point, so if you have your points around your ball, it will loop endless without reaching the goal, change it to:

            if (Vector3.Distance(transform.position, pointToMoveTo[currentPoint].position) < .5f)
            {
                Debug.Log("Reached point.");
                currentPoint++;
            }

Also, index out of range means that your point index is out of range

The logic I gave you also kind of assumes you’d just use something like Vector3.MoveTowards(transform.position, pointToMoveTo[currentPoint].position, Time.deltaTime * speed) instead of rigidbody movement. Is there a good reason you need to use physics/rigidbody movement for this particular logic?

If you do need to use physics-compatible movement you’re probably better moving this code into FixedUpdate and using rigidbody.MovePosition

(Side note, you responded to both my Qs and I really appreciate it!!!)

Hm well this makes a lot of sense, but now that I’ve implemented it the vehicle is no longer moving at all.

Here’s the update:

    void Update()
    {
        if (cloudSurfing)
        {
            Debug.Log("CloudSurfing bool " + cloudSurfing);

            //moveDirection = pointToMoveTo[currentPoint].position - transform.position;



            if (Vector3.Distance(transform.position, pointToMoveTo[currentPoint].position) < .5f)
            {
                Debug.Log("Reached point.");
                currentPoint++;
            }

            if(currentPoint >= pointToMoveTo.Length)
            {
                cloudSurfing = false;
            }

           
        }

        moveDirection.Normalize();
        Vector2.MoveTowards(transform.position, pointToMoveTo[currentPoint].position, Time.deltaTime * speed);
        //theRB.velocity = moveDirection * speed;
    }

Ok so first, let’s make sure we’re initializing things correctly:

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.tag == "Player")
        {
            PlayerController.instance.canWalk = false;
            PlayerController.instance.transform.position = this.transform.position;
            barrier.SetActive(true);
            currentPoint = 0;
            cloudSurfing = true;
        }
    }

Then, move the MoveTowards into the cloudsurfing if statement, and you also have to make sure you’re actually doing something with the result of the MoveTowards call, and that you’re actually moving the player position not the CloudsurfActivator position ;D

    void Update()
    {
        if (cloudSurfing)
        {
            Debug.Log("CloudSurfing bool " + cloudSurfing);
         
            transform.position = Vector3.MoveTowards(transform.position, pointToMoveTo[currentPoint].position, Time.deltaTime * speed);
            if (Vector3.Distance(transform.position, pointToMoveTo[currentPoint].position) < .5f)
            {
                Debug.Log("Reached point.");
                currentPoint++;
            }
            if(currentPoint >= pointToMoveTo.Length)
            {
                cloudSurfing = false;
            }
        
        }
    }

OK, MUCH closer… but not quite there! For some reason the vehicle is STILL just moving to the first point, and continuing on. The debug “Reached point.” is never logged.

Here’s the update overall:

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

public class CloudSurfActivator : MonoBehaviour
{
    public GameObject barrier;
    private bool cloudSurfing;
    //public Rigidbody2D theRB;
    private Vector2 moveDirection;
    public float speed;
    public Transform[] pointToMoveTo;
    private int currentPoint;

    // Start is called before the first frame update
    void Start()
    {
        barrier.SetActive(false);
        cloudSurfing = false;
    }

    // Update is called once per frame
    void Update()
    {
        if (cloudSurfing)
        {
            Debug.Log("CloudSurfing bool " + cloudSurfing);

            //moveDirection = pointToMoveTo[currentPoint].position - transform.position;

            if (Vector2.Distance(transform.position, pointToMoveTo[currentPoint].position) < .5f)
            {
                Debug.Log("Reached point.");
                currentPoint++;
            }

            if(currentPoint >= pointToMoveTo.Length)
            {
                cloudSurfing = false;
                PlayerController.instance.transform.parent = null;
            }

            transform.position = Vector2.MoveTowards(transform.position, pointToMoveTo[currentPoint].position, Time.deltaTime * speed);
        }

        //moveDirection.Normalize();
        //theRB.velocity = moveDirection * speed;
    }


    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.tag == "Player")
        {
            PlayerController.instance.canWalk = false;
            PlayerController.instance.transform.position = new Vector2(transform.position.x, transform.position.y + 0.5f);
            PlayerController.instance.transform.parent = this.transform;
            currentPoint = 0;
            //barrier.SetActive(true);
            cloudSurfing = true;
        }
    }
}

Can you put a Debug.Log in the OnTriggerEnter? Is it possible we’re re-entering that trigger and resetting the cloudsurfing process?

Also, how many points are in the array? What are they set to>

Omg omg omg… prepare to face palm with me.

Had the points set as children of the vehicle… so they were constantly moving. I am SORRY to have wasted your time on that Q. Jeez.

1 Like