1
\$\begingroup\$

The is a bit long but I separated the relevant parts at the bottom of the question.

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

public class Waypoints : MonoBehaviour
{
    [Header("Objects To Move")]
    public Transform objectToMovePrefab;
    public int numberOfObjectsToMove = 1;

    [Header("Speed")]
    public float speed;
    public bool randomSpeed = false;
    public float minRandomSpeed = 1;
    public float maxRandomSpeed = 100;
    private bool changeSpeedOnce = false;

    [Header("Rotation")]
    public Quaternion rotationTothinkWhatToDoHere;

    [Header("Waypoints")]
    [SerializeField] private List<Transform> waypoints;
    public bool moveOnWaypoints = false;

    [Header("Delay")]
    public bool useDelay = false;
    public float delay = 3;
    public bool randomDelay = false;
    public float minRandomDelay = 0.3f;
    public float maxRandomDelay = 5;

    [Header("LineRenderer")]
    public LineRenderer lineRenderer;
    public bool moveOnLineRenderer = false;
    public List<Vector3> lineRendererPositions = new List<Vector3>();

    [Header("Cinemachine Cameras")]
    public CinemachineVirtualCamera virtualCamera;

    private List<WaypointsFollower> waypointsFollowers = new List<WaypointsFollower>();

    private void Start()
    {
        for (int i = 0; i < numberOfObjectsToMove; i++)
        {
            var parent = GameObject.Find("Moving Object Parent");
            var objectToMove = Instantiate(objectToMovePrefab, parent.transform);
            objectToMove.name = "Platfrom";

            waypointsFollowers.Add(objectToMove.GetComponent<WaypointsFollower>());
        }

        virtualCamera.Follow = waypointsFollowers[0].gameObject.transform;
        virtualCamera.LookAt = waypointsFollowers[0].gameObject.transform;

        WaypointsMovementStates();

        SpeedUpdater();

        if (useDelay)
            StartCoroutine(SendObjectstomoveWithDelay());
    }

    private void Update()
    {
        if (moveOnLineRenderer)
        {
            lineRendererPositions.Clear();

            if (moveOnWaypoints)
            {
                foreach (Transform wp in waypoints)
                {
                    lineRendererPositions.Add(wp.position);
                }
            }

            lineRendererPositions.AddRange(GetLinePointsInWorldSpace());
        }

        SpeedUpdater();
    }

    IEnumerator SendObjectstomoveWithDelay()
    {
        {
            foreach (WaypointsFollower follower in waypointsFollowers)
            {
                if (randomDelay)
                {
                    delay = Random.Range(minRandomDelay, maxRandomDelay);
                }

                yield return new WaitForSeconds(delay);

                follower.go = true;
            }
        }
    }

    private void SpeedUpdater()
    {
        if (changeSpeedOnce == false)
        {
            foreach (WaypointsFollower follower in waypointsFollowers)
            {
                if (randomSpeed)
                {
                    follower.speed = Random.Range(minRandomSpeed, maxRandomSpeed);
                }
                else
                {
                    follower.speed = speed;
                }
            }

            changeSpeedOnce = true;
        }
    }

    Vector3[] GetLinePointsInWorldSpace()
    {
        var positions = new Vector3[lineRenderer.positionCount];
        //Get the positions which are shown in the inspector 
        lineRenderer.GetPositions(positions);


        //the points returned are in world space
        return positions;
    }

    private void WaypointsMovementStates()
    {
        // If moving on both linerenderer positions and waypoints objects
        if (moveOnLineRenderer && moveOnWaypoints && waypoints.Count > 0)
        {
            if (useDelay == false)
            {
                foreach (WaypointsFollower wpf in waypointsFollowers)
                {
                    wpf.go = true;
                }
            }
        }


        // If moving on linerenderer positions only without moving on waypoints objects
        if (moveOnLineRenderer && moveOnWaypoints == false)
        {
            if (waypoints.Count > 0)
                waypoints.Clear();

            if (useDelay == false)
            {
                foreach (WaypointsFollower wpf in waypointsFollowers)
                {
                    wpf.go = true;
                }
            }
        }


        // If only to move on waypoints objects without moving on linerenderer positions
        if (moveOnWaypoints && waypoints.Count > 0 && moveOnLineRenderer == false)
        {
            lineRendererPositions.Clear();

            foreach (Transform wp in waypoints)
            {
                lineRendererPositions.Add(wp.position);
            }

            if (useDelay == false)
            {
                foreach (WaypointsFollower wpf in waypointsFollowers)
                {
                    wpf.go = true;
                }
            }
        }
    }
}

The method SpeedUpdater I call it in the Update :

private void SpeedUpdater()
    {
        if (changeSpeedOnce == false)
        {
            foreach (WaypointsFollower follower in waypointsFollowers)
            {
                if (randomSpeed)
                {
                    follower.speed = Random.Range(minRandomSpeed, maxRandomSpeed);
                }
                else
                {
                    follower.speed = speed;
                }
            }

            changeSpeedOnce = true;
        }
    }

and I'm using helper flag bool name changeSpeedOnce. If the randomSpeed is true I want it to give each moving object a random speed once the problem is if I want to change the flag randomSpeed at run time for example if at run time I change the randomSpeed to false then make all the objects move in the same speed and if I set it to true again in the run time give each one again a random speed value but only once.

If I don't use the helper flag changeSpeedOnce and set the randomSpeed to true it will stutter because it will give each moving object a new random speed value every frame.

\$\endgroup\$
1
\$\begingroup\$

In your case only use Update() for 2 things:

  1. To check if way point already is reached;
  2. If not yet, move gameobject small incremental distance;

Other parameters of gameobject, - ,such as speed, should be stored in easy accessible manner and its value set only when you require, NOT every frame in Update(). This is how I move units in my RTS game.

This would be simplified example of code:

public bool isMoving;
public Vector3 nextPoint;
public float speed;

private Vector3 dir = new Vector3();
void FixedUpdate()
{
    if (isMoving)
    {
        if (Vector3.Distance(transform.position, nextPoint) < 0.5f)   //are we there yet?
        {
            isMoving = false;

        }
        else
        {
            dir = (nextPoint - transform.position).normalized;  // direction of movement (also could be moved outside Update() function in most cases)
            transform.Translate(dir * speed);  // move a little bit!
        }

    }

}

Note: dir here is directional vector pointing from current position of gameobject to position of nextPoint.

speed here defines how far object is moved every frame. Basically speed of object. Can be set from everywhere.

\$\endgroup\$

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.