Daniel Lip
Daniel Lip

Reputation: 11321

How can I loop using foreach each time once in the Update and also using a bool flag each time once?

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;
    private bool currentSpeedState;

    [Header("Waypoints")]
    [SerializeField] private List<Transform> waypoints;

    [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()
    {
        currentSpeedState = changeSpeedOnce;

        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;

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

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

        SpeedUpdater();

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

    private void Update()
    {
        lineRendererPositions.Clear();
        lineRendererPositions.AddRange(GetLinePointsInWorldSpace());

        SpeedUpdater();
    }

    public int Count => waypoints.Count;
    public Vector3 GetWaypoint(int index)
    {
        return waypoints[index].position;
    }

    public int CountLR => lineRendererPositions.Count;
    public Vector3 GetLRWaypoint(int index)
    {
        return lineRendererPositions[index];
    }

    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()
    {
        foreach (WaypointsFollower follower in waypointsFollowers)
        {
            if (randomSpeed)
            {
                follower.speed = Random.Range(minRandomSpeed, maxRandomSpeed);
            }
            else
            {
                follower.speed = speed;
            }
        }
    }

    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;
    }
}

Inside the SpeedUpdtaer I'm using a flag and I want to be able to change the flag in run time too. The problem is calling the SpeedUpdater in the Update will make the foreach loop every frame and it might be expensive because in the List waypointsFollowers there might be a lot of items.

and about the delay part, I want to do that if I change the useDelay flag in run time then from that moment each moving object will get to the next waypoint and then from there the delay will start working. same if changing the useDelay flag to false at run time then don't wait at the next waypoint/s.

The delay is working fine but only in the Start for now and also the SpeedUpdater is working fine but I'm not sure if making foreach each frame is a good way. and not sure how to make and wherein the code that I will be able to change the speed and the speed random flag at run time without making the loop each frame.

Upvotes: 1

Views: 215

Answers (1)

rustyBucketBay
rustyBucketBay

Reputation: 4561

I would use properties. With properties you can keep track in the variable value set, to conditionally or on value change execute some logic, like this (I did not compile check);

private bool useDelay = false;
public bool UseDelay { get => useDelay; set {
useDelay = value;
if (useDelay)
    StartCoroutine(SendObjectstomoveWithDelay()); 
}};
private bool randomDelay = false;
public bool RandomDelay { get => randomDelay; set {
SpeedUpdater(value);
randomDelay = value;
}};

For that I would make also that SpeedUpdater() accepts the bool argument:

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

I was not very careful in adjusting to the logic of your question. The sample code is just to show you how you can run logic on value get/set. Other way are events, a bit more complicated option, and not much needed for this case I believe. You can give a read to the docs

Upvotes: 1

Related Questions