123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- /*
- * InstantiatePrefab.cs must be run before any other custom scripts because
- * humanGameObject, wanderTimer and waypointsArray may be needed in other scripts.
- * This can be set in Uniy3d under "Edit -> Project Settings ... -> Script Execution Order".
- */
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.AI;
- [DefaultExecutionOrder(0)]
- public class InstantiatePrefab : MonoBehaviour
- {
- [Header("Game Objects")]
- public GameObject prefabHuman;
- [SerializeField]
- private GameObject waypoints;
- public int[] waypointsFrequency;
- public Vector2[] individualWaitingTimer;
-
- [Header("Number of Humans and Groups")]
- public int amount = 100;
- public int maxNumPerGroup = 1;
-
- [Header("Set Spawn point")]
- public Vector3[] spawnPointArray;
-
- [Header("Steering")]
- public Vector2 speedMinMax = new Vector2(4.0f, 7.0f);
- public Vector2 wanderTimerMinMax = new Vector2(10.0f, 15.0f);
- public float stoppingDistance = 1;
-
- //Can be passed on
- [HideInInspector]
- public GameObject[][] humanGameObject;
- [HideInInspector]
- public Animator[][] humanAnimator;
- [HideInInspector]
- public NavMeshAgent[][] humanNavMeshAgent;
- [HideInInspector]
- public int[][] humanPriorities;
- [HideInInspector]
- public float[] wanderTimer;
- [HideInInspector]
- public List<List<int>> waitingTimer; // waitingTime (1-5 s) X WPs
- [HideInInspector]
- public Transform[] waypointsArray;
- // Start is called before the first frame update
- void Start()
- {
- // Adding frequency for increasing probability to visit some waypoints
- int freqLength = 0;
- for (int freq = 0; freq < waypointsFrequency.Length; ++freq)
- {
- freqLength += waypointsFrequency[freq];
- }
- //Save all waypoints from GameObject into Transform array
- Transform[] wpArray = waypoints.GetComponentsInChildren<Transform>();
- waypointsArray = new Transform[freqLength];
- freqLength = 0;
- for(int k = 1; k < wpArray.Length; ++k)
- {
- for(int freq = 0; freq < waypointsFrequency[k-1]; ++freq)
- {
- waypointsArray[freqLength] = wpArray[k];
- freqLength++;
- }
- }
- //gameObject.GetComponent<WanderingAITest>().waypoints = waypointsArray;
- //Create priority list for different NavMeshAgent priorities
- List<int> priorityList = new List<int>();
- // NavMeshAgents max avoidancePriority is 99 (0 high Priority is already used)
- for (int i = 0; i < 99; ++i)
- priorityList.Add(i + 1); //1 .. 99
- //Calculate number of groups
- int numGroups = 1;
- if(amount > 0)
- numGroups = (int) Mathf.Ceil((float)amount / (float)maxNumPerGroup);
- //Set size of attributes that can be passed on
- humanGameObject = new GameObject[numGroups][];
- humanAnimator = new Animator[numGroups][];
- humanNavMeshAgent = new NavMeshAgent[numGroups][];
- humanPriorities = new int[numGroups][];
- //Set wanderTimer
- wanderTimer = new float[humanGameObject.Length];
- // Set waitingTimer
- waitingTimer = new List<List<int>>();
- for (int i = 0; i < waypointsArray.Length; ++i)
- // create Matrix waitingTime X WPs with waitingTime from 1-5 seconds, bc we want all WP vistited the same duration
- waitingTimer.Add(new List<int> { 1, 2, 3, 4, 5 });
- int humansLeft = amount;
- //for positioning the instances
- //float inRow = Mathf.Ceil(Mathf.Sqrt(amount));
- int count = 1;
- int offsetx = 0;
- int offsetz = 0;
- int spawnPointIndex = 0;
- int maxPerSP = (int)Mathf.Ceil(amount / 4f);
- // not enought space for more humans (incl. 0 - 4)
- float inRow = 4;
- // instantiate humans, save in array and modifie
- for (int i = 0; i < humanGameObject.Length; ++i)
- {
- //Calculate Group Size
- int groupSize = (humansLeft > maxNumPerGroup) ? maxNumPerGroup : humansLeft;
- humanGameObject[i] = new GameObject[groupSize];
- humansLeft -= groupSize;
- //Set Animator and NavMeshAgent
- humanAnimator[i] = new Animator[groupSize];
- humanNavMeshAgent[i] = new NavMeshAgent[groupSize];
- humanPriorities[i] = new int[groupSize];
- //Nav Mesh Agent - speed
- float speed = Random.Range(speedMinMax.x, speedMinMax.y);
- //Wandering AI Waypoints (Script)
- wanderTimer[i] = Random.Range(wanderTimerMinMax.x, wanderTimerMinMax.y);
- // instantiate humans per group and save them in matrix
- for (int j = 0; j < humanGameObject[i].Length; ++j)
- {
- // Instantiate human [i][j]
- humanGameObject[i][j] = Instantiate(prefabHuman,
- new Vector3(spawnPointArray[spawnPointIndex].x - offsetx, 0, spawnPointArray[spawnPointIndex].z - offsetz),
- Quaternion.identity,
- this.transform);
- // Calculate offset
- if (offsetx < inRow * 2)
- offsetx += 2;
- else
- {
- offsetx = 0;
- offsetz += 2;
- }
- if(count != 0 && count % maxPerSP == 0)
- {
- spawnPointIndex++;
- offsetx = 0;
- offsetz = 0;
- }
- count++;
- // Set Humans initial values
- humanGameObject[i][j].tag = this.transform.tag;
- humanGameObject[i][j].GetComponent<NavMeshAgent>().stoppingDistance = stoppingDistance;
- humanGameObject[i][j].GetComponent<NavMeshAgent>().speed = speed;
- humanGameObject[i][j].GetComponent<Animator>().speed = 0.5f + (speed / speedMinMax.y);
- //Set Humans Priority
- int priority = GetRandomPriority(i, j, maxNumPerGroup, priorityList);
- humanGameObject[i][j].GetComponent<NavMeshAgent>().avoidancePriority = priority;
- humanPriorities[i][j] = priority;
- // Set Components
- humanAnimator[i][j] = humanGameObject[i][j].GetComponent<Animator>();
- humanNavMeshAgent[i][j] = humanGameObject[i][j].GetComponent<NavMeshAgent>();
- }
- }
- }
- public int GetRandomPriority(int i, int j, int maxNumPerGroup, List<int> priorityList)
- {
- int index = i * maxNumPerGroup + j ;
-
- if(index % 99 == 0)
- {
- priorityList = Shuffle(priorityList);
- }
- return priorityList[index % 99];
- }
- // Fisher-Yates shuffle
- public List<int> Shuffle(List<int> list)
- {
- int n = list.Count;
- while(n > 1)
- {
- n--;
- int k = Random.Range(0, n + 1);
- int tmp = list[k];
- list[k] = list[n];
- list[n] = tmp;
- }
- return list;
- }
- }
|