I messed it all with too many bool variables and code.
The first script Instantiate Objects.
The script is attached to 3 different GameObjects and creating different cloned objects.
On the left the Hierarchy the script is attached now to only two GameObjects and create children cloned gameobjects. On the right the script inspector.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//[ExecuteInEditMode]
public class InstantiateObjects : MonoBehaviour
{
public GameObject objectToInstantiate;
public Terrain terrain;
public float yOffset = 0.5f;
public int objectsToInstantiate;
public bool parent = true;
public bool randomScale = false;
public bool patrolPoints = false;
public Vector3 RandScaleMin;
public Vector3 RandScaleMax;
private float terrainWidth;
private float terrainLength;
private float xTerrainPos;
private float zTerrainPos;
private int numberOfObjectsToCreate;
private GameObject objInstance;
private GameObject[] createdObjects;
private string objname;
private bool destroyObjects = false;
private bool listUpdated = false;
public void Start()
{
//Get terrain size
terrainWidth = terrain.terrainData.size.x;
terrainLength = terrain.terrainData.size.z;
//Get terrain position
xTerrainPos = terrain.transform.position.x;
zTerrainPos = terrain.transform.position.z;
numberOfObjectsToCreate = objectsToInstantiate;
objname = objectToInstantiate.name;
MyCustomEditor.TagsAndLayers.AddTag(objname);
generateObjectOnTerrain();
}
public void Update()
{
if (patrolPoints == true && destroyObjects == true
&& listUpdated == false)
{
UpdateList(true, objname);
}
if (patrolPoints == true && destroyObjects == false
&& listUpdated == false)
{
UpdateList(false, objname);
}
if (patrolPoints == false)
{
listUpdated = false;
RemovePatrols(objname, true);
}
}
public void DestroyObjects()
{
UpdateList(true, objname);
if (createdObjects != null && createdObjects.Length > 0)
{
for (int i = 0; i < createdObjects.Length; i++)
{
DestroyImmediate(createdObjects[i]);
}
createdObjects = new GameObject[0];
}
}
public void generateObjectOnTerrain()
{
for (int i = 0; i < objectsToInstantiate; i++)
{
//Generate random x,z,y position on the terrain
float randX = UnityEngine.Random.Range(xTerrainPos, xTerrainPos + terrainWidth);
float randZ = UnityEngine.Random.Range(zTerrainPos, zTerrainPos + terrainLength);
float yVal = Terrain.activeTerrain.SampleHeight(new Vector3(randX, 0, randZ));
var randScaleX = Random.Range(RandScaleMin.x, RandScaleMax.x);
var randScaleY = Random.Range(RandScaleMin.y, RandScaleMax.y);
var randScaleZ = Random.Range(RandScaleMin.z, RandScaleMax.z);
var randVector3 = new Vector3(randScaleX, randScaleY, randScaleZ);
//Apply Offset if needed
yVal = yVal + yOffset;
//Generate the Prefab on the generated position
objInstance = Instantiate(objectToInstantiate, new Vector3(randX, yVal, randZ), Quaternion.identity);
if (randomScale == true)
objInstance.transform.localScale = randVector3;//new Vector3(randScaleX, randScaleY, randScaleZ);
if (parent)
objInstance.transform.parent = this.transform;
objInstance.tag = objname;
}
createdObjects = GameObject.FindGameObjectsWithTag(objname);
if (patrolPoints == true)
UpdateList(false, objname);
}
private void UpdateList(bool destroy, string tagname)
{
listUpdated = false;
destroyObjects = destroy;
GameObject go = GameObject.Find("Main Camera");
var list = go.GetComponent<PatrolOverTerrain>().Targets;
if (destroy == false)
{
list.AddRange(createdObjects);
go.GetComponent<PatrolOverTerrain>().Targets = list;
go.GetComponent<PatrolOverTerrain>().tagName = tagname;
go.GetComponent<PatrolOverTerrain>().removedTargets = false;
listUpdated = true;
}
if (destroy == true)
{
list.Clear();
go.GetComponent<PatrolOverTerrain>().Targets.Clear();
go.GetComponent<PatrolOverTerrain>().tagName = tagname;
go.GetComponent<PatrolOverTerrain>().removedTargets = false;
listUpdated = true;
}
}
private void RemovePatrols(string tagname, bool removed)
{
GameObject go = GameObject.Find("Main Camera");
var list = go.GetComponent<PatrolOverTerrain>().Targets;
list.Clear();
go.GetComponent<PatrolOverTerrain>().Targets.Clear();
go.GetComponent<PatrolOverTerrain>().tagName = tagname;
go.GetComponent<PatrolOverTerrain>().removedTargets = removed;
}
}
Then i have a script of a ui button and ui toggle i’m using it to decide if to destroy and create new cloned gameobjects or without destroying and only to create new cloned gameobjects.
So if i the toggle is checked it will destroy first and will create new objects. If not checked it will just add new gameobjects to the already exists.
For example if in the inspector i set to 20 and then uncheck the toggle and click the ui button it will add more new 20 gameobjects. If checked and clicked the button it will destroy first and then will add new 20 clones.
This is the game window when the game is not running showing the button and the ui:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GenerateObjectsButton : MonoBehaviour
{
[SerializeField]
private InstantiateObjects[] instantiateobjects;
private bool toggleOnOf;
public Toggle toggle;
public bool destroyed = false;
private void Start()
{
toggle.onValueChanged.AddListener((value) =>
{
MyListener(value);
});
}
public void MyListener(bool value)
{
if (value)
{
//do the stuff when the toggle is on
toggleOnOf = true;
}
else
{
//do the stuff when the toggle is off
toggleOnOf = false;
}
}
public void OnButton()
{
for (int i = 0; i < instantiateobjects.Length; i++)
{
if (toggleOnOf == false)
{
if (instantiateobjects[i] != null)
instantiateobjects[i].generateObjectOnTerrain();
}
else
{
if (instantiateobjects[i] != null)
{
instantiateobjects[i].DestroyObjects();
instantiateobjects[i].generateObjectOnTerrain();
destroyed = true;
}
}
}
}
}
And the last script create the patrolPoints array (like waypoints).
I’m using a public List name Targets and updating the list also in the InstantiateObjects script to decide if to destroy or not to destroy first when creating new cloned gameobjects.
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 enum PatrolMode { Clamp, Wrap, PingPong };
public PatrolData[] patrolPoints;
public PatrolMode mode = PatrolMode.Wrap;
private int iterator = 0;
private int index = 0;
private float lingerDuration = 0f;
private int oldLength = 0;
public bool autoFreedomPatrol = false;
public List<GameObject> Targets = new List<GameObject>();
public string tagName;
public bool removedTargets;
public Vector3 distanceFromTarget;
private 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)
{
oldLength = tempObj.Length;
}
GeneratePatrolPoints();
}
}
private void OnEnable()
{
if (patrolPoints.Length > 0)
{
lingerDuration = patrolPoints[index].lingerDuration;
}
}
private void Update()
{
if (tagName != "")
{
if (removedTargets == false)
{
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]);
}
}
}
//Check if oldLength has changed
if (oldLength != Targets.Count)
{
//Update oldLength
oldLength = Targets.Count;
//Call your the function
GeneratePatrolPoints();
}
GameObject go = GameObject.Find("Button");
var destroyed = go.GetComponent<GenerateObjectsButton>().destroyed;
if (destroyed)
{
GeneratePatrolPoints();
}
int length = patrolPoints.Length;
if (!flyOverTerrain) return;
if (patrolPoints.Length < 1) return;
if (index < 0) return;
// Getting exception out of index on line 89.
// Need to make a list also for the Cubes(buildings).
var 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;
}
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;
lookAtCamera.target = patrol.target;
lookAtCamera.RotationSpeed = 3;
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;
lookAtCamera.target = null;
lingerDuration -= Time.deltaTime;
}
else
{
flyOverTerrain.target = patrol.target;
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;
}
}
}
My logic of how it should work with all 3 scripts is:
When running the game if in one GameObject in the inspector the property Patrol Points is checked/unchecked add or not the cloned objects only for this children clones to the Targets list and to the patrolPoints.
Same thing if the game is already running and i check/uncheck the Patrol Points cool variable update and remove/add the cloned gameobjects from the Targets list and the patrolPoints.
Back to the first screenshot if for example in the Teleportation Booths inspector i check the Patrol Points add all the cloned Teleportation Booth(clone) children to the Targets list and to the patrolPoints and if unchecked remove them.
The part with the ui button and ui toggle script was working fine and still working fine.
But then i tried to make the part with the Patrol Points bool and messed it all up in the InstantiateObjects script with the Update function and the UpdateList and the RemovePatrols and then in the PatrolOverTerrain i messed it all also in the Update function with that:
if (tagName != "")
{
if (removedTargets == false)
{
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]);
}
}
}
In general the goal is to make it possible to add/remove the cloned objects to/from the Targets list and update the patrolPoints array.