0
\$\begingroup\$

What I'm trying to do is to get a random index not a number but index from the randomPatrol List and use it in the patrolPoints.

private void Update()
{
 if (mode == PatrolMode.Random)
        {
            var rn = randomPatrol[Random.Range(0, randomPatrol.Count)];
            randomPatrol.RemoveAt(rn);
            patrol = patrolPoints[rn];

            if (randomPatrol.Count == 0)
            {
                randomPatrol = new List<int>();
                for (int i = 0; i < patrolPoints.Length; i++)
                {
                    randomPatrol.Add(i);
                }
            }
        }
        else
        {
            patrol = patrolPoints[index];
        }
}

randomPatrol is List randomPatrol contain for example 100 int numbers. Also patrolPoints is a List contain 100 items.

I used a break point at the first few times it was getting some indexs. rn value was 13 then 27 then 41 and 44 and then after few more times I'm getting out of range exception on the line:

randomPatrol.RemoveAt(rn);

And I see that randomPatrol count is 93 but the index number in rn is 96. Not sure how the random chosen number can be 96 if the List count is 93.

The complete script:

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

[System.Serializable]
public class PatrolData
{
    public Transform target = null;
    public float minDistance = 5f;
    public float lingerDuration = 5f;
    public float desiredHeight = 10f;
    public float flightSmoothTime = 10f;
    public float maxFlightspeed = 10f;
    public float flightAcceleration = 1f;
    public float levelingSmoothTime = 0.5f;
    public float maxLevelingSpeed = 10000f;
    public float levelingAcceleration = 2f;
}

public class PatrolOverTerrain : MonoBehaviour
{
    public FlyToOverTerrain flyOverTerrain;
    public LookAtCamera lookAtCamera;
    public UserInformation userinformation;
    public enum PatrolMode { Clamp, Wrap, PingPong, Random };
    public PatrolData[] patrolPoints;
    public PatrolMode mode = PatrolMode.Wrap;

    private int iterator = 0;
    private int index = 0;
    private float lingerDuration = 0f;
    private int overallLength = 0;
    private List<int> randomPatrol = new List<int>();
    private PatrolData patrol;

    public bool autoFreedomPatrol = false;
    public List<GameObject> Targets = new List<GameObject>();
    public string tagName;
    public Vector3 distanceFromTarget;

    public void Start()
    {
        if (tagName != "")
        {
            GameObject[] tempObj = GameObject.FindGameObjectsWithTag(tagName);

            for (int i = 0; i < tempObj.Length; i++)
            {
                //Add to list only if it does not exist
                if (!Targets.Contains(tempObj[i]))
                {
                    Targets.Add(tempObj[i]);
                }
            }

            //Get the current Size
            if (tempObj != null)
            {
                overallLength = Targets.Count;
            }

            GeneratePatrolPoints();

            for (int i = 0; i < patrolPoints.Length; i++)
            {
                randomPatrol.Add(i);
            }
        }
    }

    private void OnEnable()
    {
        if (patrolPoints.Length > 0)
        {
            lingerDuration = patrolPoints[index].lingerDuration;
        }
    }

    private void Update()
    {
        int length = patrolPoints.Length;
        if (!flyOverTerrain) return;
        if (patrolPoints.Length < 1) return;
        if (index < 0) return;

        if (mode == PatrolMode.Random)
        {
            var rn = randomPatrol[Random.Range(0, randomPatrol.Count)];
            randomPatrol.RemoveAt(rn);
            patrol = patrolPoints[rn];

            if (randomPatrol.Count == 0)
            {
                randomPatrol = new List<int>();
                for (int i = 0; i < patrolPoints.Length; i++)
                {
                    randomPatrol.Add(i);
                }
            }
        }
        else
        {
            patrol = patrolPoints[index];
        }
        if (lingerDuration <= 0)
        {
            iterator++;
            switch (mode)
            {
                case PatrolMode.Clamp:
                    index = (iterator >= length) ? -1 : iterator;
                    break;
                case PatrolMode.Wrap:
                    iterator = Modulus(iterator, length);
                    index = iterator;
                    break;
                case PatrolMode.PingPong:
                    index = PingPong(iterator, length);
                    break;
                case PatrolMode.Random:

                    break;
            }
            if (index < 0) return;

            patrol = patrolPoints[index];

            flyOverTerrain.target = patrol.target;
            flyOverTerrain.desiredHeight = patrol.desiredHeight;
            flyOverTerrain.flightSmoothTime = patrol.flightSmoothTime;
            flyOverTerrain.maxFlightspeed = patrol.maxFlightspeed;
            flyOverTerrain.flightAcceleration = patrol.flightAcceleration;
            flyOverTerrain.levelingSmoothTime = patrol.levelingSmoothTime;
            flyOverTerrain.maxLevelingSpeed = patrol.maxLevelingSpeed;
            flyOverTerrain.levelingAcceleration = patrol.levelingAcceleration;

            if (lookAtCamera != null)
            {
                lookAtCamera.target = patrol.target;
                lookAtCamera.RotationSpeed = 3;
            }
            //userinformation.target = patrol.target;

            lingerDuration = patrolPoints[index].lingerDuration;
        }

        Vector3 targetOffset = Vector3.zero;
        if ((bool)patrol.target)
        {
            targetOffset = transform.position - patrol.target.position;
        }

        float sqrDistance = patrol.minDistance * patrol.minDistance;
        if (targetOffset.sqrMagnitude <= sqrDistance)
        {
            flyOverTerrain.target = null;
            if (lookAtCamera != null)
                lookAtCamera.target = null;
            lingerDuration -= Time.deltaTime;
        }
        else
        {
            flyOverTerrain.target = patrol.target;
            if (lookAtCamera != null)
                lookAtCamera.target = patrol.target;
        }
        distanceFromTarget = transform.position - patrol.target.position;
    }

    private int PingPong(int baseNumber, int limit)
    {
        if (limit < 2) return 0;
        return limit - Mathf.Abs(limit - Modulus(baseNumber, limit + (limit - 2)) - 1) - 1;
    }

    private int Modulus(int baseNumber, int modulus)
    {
        return (modulus == 0) ? baseNumber : baseNumber - modulus * (int)Mathf.Floor(baseNumber / (float)modulus);
    }

    public void GeneratePatrolPoints()
    {
        patrolPoints = new PatrolData[Targets.Count];
        for (int i = 0; i < patrolPoints.Length; i++)
        {
            patrolPoints[i] = new PatrolData();
            patrolPoints[i].target = Targets[i].transform;
            patrolPoints[i].minDistance = 30f;
            patrolPoints[i].lingerDuration = 3f;
            patrolPoints[i].desiredHeight = 20f;
            patrolPoints[i].flightSmoothTime = 10f;
            patrolPoints[i].maxFlightspeed = 10f;
            patrolPoints[i].flightAcceleration = 3f;
            patrolPoints[i].levelingSmoothTime = 0.5f;
            patrolPoints[i].maxLevelingSpeed = 10000f;
            patrolPoints[i].levelingAcceleration = 2f;
        }
    }
}
\$\endgroup\$
  • \$\begingroup\$ Where is the value for "index" being set? \$\endgroup\$ – ErnieDingo Mar 19 '18 at 0:33
  • \$\begingroup\$ @ErnieDingo I updated the question with the full script. The index variable is updating in some places in the switch/case part. But when it's in Random mode index is not in use at least not in the if (mode == PatrolMode.Random) part. \$\endgroup\$ – Daniel Lip Mar 19 '18 at 0:47
2
\$\begingroup\$

It's because you get the index from inside the list, instead of just getting a random int.

To illustrate this, let's say you create randomPatrol with only 6 elements, so the values go from 0 to 5.

The first time Random.Range gives you back 3, so since randomPatrol[3] is 3, then rn is 3.

Afterwards you make randomPatrol.RemoveAt(rn), removing the value at index 3.

Now randomPatrol contains 0, 1, 2, 4, 5 at indexes 0, 1, 2, 3, 4.

Now, if the next time Random.Range returns you 4, rn = randomPatrol[4] = 5. And when you try to randomPatrol.RemoveAt(5) you get the exception, since there's no more randomPatrol[5].

To fix, you should change your code to this:

var index = Random.Range(0, randomPatrol.Count);
var rn = randomPatrol[index];
randomPatrol.RemoveAt(index);
patrol = patrolPoints[rn];
\$\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.