News › Forums › Squad Command: Adv Warfighter AI › General Discussion and Troubleshooting › Spawn Pool
Tagged: Spawn Pool
This topic contains 22 replies, has 2 voices, and was last updated by Sigil 1 year, 2 months ago.
-
AuthorPosts
-
June 28, 2022 at 2:33 am #38385
Hi, I wish for a spawn pool in my game instead of instantiating objects, when I add the following script to my enemy character nothing happens, any ideas as to what I am doing? Please do excuse me for simple mistakes I am a beginner to unity, the pool script is as follows:
using UnityEngine; using System.Collections; using System.Collections.Generic; public class ObjectPool : MonoBehaviour { public static ObjectPool instance; /// <summary> /// The object prefabs which the pool can handle. /// </summary> public GameObject[] objectPrefabs; /// <summary> /// The pooled objects currently available. /// </summary> public List<GameObject>[] pooledObjects; /// <summary> /// The amount of objects of each type to buffer. /// </summary> public int[] amountToBuffer; public int defaultBufferAmount = 3; /// <summary> /// The container object that we will keep unused pooled objects so we dont clog up the editor with objects. /// </summary> protected GameObject containerObject; void Awake () { instance = this; } // Use this for initialization void Start () { containerObject = new GameObject("ObjectPool"); //Loop through the object prefabs and make a new list for each one. //We do this because the pool can only support prefabs set to it in the editor, //so we can assume the lists of pooled objects are in the same order as object prefabs in the array pooledObjects = new List<GameObject>[objectPrefabs.Length]; int i = 0; foreach ( GameObject objectPrefab in objectPrefabs ) { pooledObjects[i] = new List<GameObject>(); int bufferAmount; if(i < amountToBuffer.Length) bufferAmount = amountToBuffer[i]; else bufferAmount = defaultBufferAmount; for ( int n=0; n<bufferAmount; n++) { GameObject newObj = Instantiate(objectPrefab) as GameObject; newObj.name = objectPrefab.name; PoolObject(newObj); } i++; } } /// <summary> /// Gets a new object for the name type provided. If no object type exists or if onlypooled is true and there is no objects of that type in the pool /// then null will be returned. /// </summary> /// <returns> /// The object for type. /// </returns> /// <param name='objectType'> /// Object type. /// </param> /// <param name='onlyPooled'> /// If true, it will only return an object if there is one currently pooled. /// </param> public GameObject GetObjectForType ( string objectType , bool onlyPooled ) { for(int i=0; i<objectPrefabs.Length; i++) { GameObject prefab = objectPrefabs[i]; if(prefab.name == objectType) { if(pooledObjects[i].Count > 0) { GameObject pooledObject = pooledObjects[i][0]; pooledObjects[i].RemoveAt(0); pooledObject.transform.parent = null; pooledObject.SetActiveRecursively(true); return pooledObject; } else if(!onlyPooled) { return Instantiate(objectPrefabs[i]) as GameObject; } break; } } //If we have gotten here either there was no object of the specified type or non were left in the pool with onlyPooled set to true return null; } /// <summary> /// Pools the object specified. Will not be pooled if there is no prefab of that type. /// </summary> /// <param name='obj'> /// Object to be pooled. /// </param> public void PoolObject ( GameObject obj ) { for ( int i=0; i<objectPrefabs.Length; i++) { if(objectPrefabs[i].name == obj.name) { obj.SetActiveRecursively(false); obj.transform.parent = containerObject.transform; pooledObjects[i].Add(obj); return; } } } }
- This topic was modified 1 year, 3 months ago by Sigil. Reason: Added code block
June 28, 2022 at 9:46 pm #38389Well that particular script will only provide a collection of objects for spawning, so it won’t actually spawn anything. This may be why you aren’t seeing anything happen.
If you take that script and add it to an empty GameObject in your scene, then add a commander and soldier prefab to objectPrefabs in the inspector, you can use it in our Spawner script. Here’s a modified Spawner to take advantage of that:
using UnityEngine; public class Spawner : MonoBehaviour { public float spawnDelay = 10f; public int squadSize = 5; private float timer = 0f; public GameObject Commander = null; public GameObject Soldier = null; public void Update() { if (timer <= 0f) { //1 commander if ((squadSize > 0) && (Commander != null)) { GameObject tCommander = ObjectPool.instance.GetObjectForType(Commander.name, true); if (tCommander != null) { tCommander.transform.position = gameObject.transform.position; tCommander.transform.rotation = gameObject.transform.rotation; } } //squadSize -1 soldiers, arrayed in line behind the spawn point if (Soldier != null) { for (int i = 1; i < squadSize; i++) { GameObject tSoldier = ObjectPool.instance.GetObjectForType(Soldier.name, true); if (tSoldier != null) { tSoldier.transform.position = gameObject.transform.position; tSoldier.transform.rotation = gameObject.transform.rotation; } } } timer = spawnDelay; } else timer -= Time.deltaTime; } }
June 29, 2022 at 1:47 am #38391thanks for your response, ok, just so that we are on the right lines, I have created an empty object added my spawn pool script to the empty object filled in the object prefabs, set the buffer size to 5, gone back into my spawner (seperate object) added the new spawner script as above and hurrraaay…nothing happened. Any ideas as to what is happening, and why it is not working…..
June 30, 2022 at 10:07 am #38398You know what, after looking at the script I posted, it is kind of confusing the way it works. Lets change it up a bit:
using UnityEngine; public class Spawner : MonoBehaviour { public float spawnDelay = 10f; public int squadSize = 5; private float timer = 0f; public string Commander = ""; public string Soldier = ""; public void Start() { if (Commander == "") Debug.LogWarning("Spawner: Commander field is empty"); if (Soldier == "") Debug.LogWarning("Spawner: Soldier field is empty"); } public void Update() { if (timer <= 0f) { //1 commander if ((squadSize > 0) && (Commander != "")) { GameObject tCommander = ObjectPool.instance.GetObjectForType(Commander, true); if (tCommander != null) { tCommander.transform.position = gameObject.transform.position; tCommander.transform.rotation = gameObject.transform.rotation; } } //squadSize -1 soldiers, arrayed in line behind the spawn point if (Soldier != "") { for (int i = 1; i < squadSize; i++) { GameObject tSoldier = ObjectPool.instance.GetObjectForType(Soldier, true); if (tSoldier != null) { tSoldier.transform.position = gameObject.transform.position; tSoldier.transform.rotation = gameObject.transform.rotation; } } } timer = spawnDelay; } else timer -= Time.deltaTime; } }
I changed the Commander and Soldier fields to be strings instead of GameObjects. After replacing the Spawner with this script, make sure you fill out the Commander and Soldier fields to be the name of the Prefabs you want to spawn. It should match the names of the Prefabs you added to the objectPrefabs on the ObjectPool.
After that, note any errors/warning in the log when you play. You can come back here and post if there are some.
You may also want to check out this page on debugging. It’ll save you a lot of time (and reduce some frustration) if you can look a little closer at what is happening with your scripts, aside from pressing play and not seeing any results.
July 1, 2022 at 1:35 am #38402Hi…I get the following error message:
NullReferenceException: Object reference not set to an instance of an object
ObjectPool.GetObjectForType (System.String objectType, Boolean onlyPooled) (at Assets/SquadCommand/Scripts/new/ObjectPool.cs:90)
Spawner.Update () (at Assets/SquadCommand/Scripts/new/Spawner.cs:29)July 1, 2022 at 10:24 am #38404You will have to dig a little deeper. Given the code in the GetObjectForType function, a null reference exception could be caused by this line:
... GameObject prefab = objectPrefabs[i]; // if objectPrefabs[i] is empty if (prefab.name == objectType) // this will throw the exception ...
Or perhaps:
... // if somehow the pooledObjects list didn't get initialized if (pooledObjects[i].Count > 0) // this would throw the exception ...
Perhaps there are more errors and you just linked the last one? Double clicking the error should open Mono Develop so you can see exactly what line the problem is caused on.
July 5, 2022 at 11:08 am #38432k, in the original spawner script please can you tell me what code actually makes the soldiers walk off, so for instance once they are spawned in stead of standing there, what code actually makes them move
July 9, 2022 at 12:12 pm #38472Ok, give me a moment here and I will post a spawning script that does pool allocation for you. I think I will be updating the Squad Command Spawner for the asset store with similar code, as it probably should have been done this way to begin with.
As for movement. The soldiers’ behavior trees handle the movement, and I believe they listen for commands from their commander. The original Spawner would spawn a commander first, and then several soldiers after that (which would automatically pick up the commander). The commander’s behavior tree was setup to start patrolling after the spawn, which is why all the other soldiers would follow.
I’ll have the updated Spawner code up soon, need to test it first.
July 10, 2022 at 12:20 am #38474Here is a new and improved spawner. This one preallocates all of the soldiers on Start, which should reduce any hitching caused by the Spawner. It also introduces a new variable, squadCount, which limits the number of squads spawned. Previously it would just spawn forever, possibly creating some funniness if you never engaged the soldiers (or always beat them).
using System.Collections.Generic; using UnityEngine; /// <summary> /// Spawner is a simple component that spawns a team of AI at a specified interval /// </summary> public class Spawner : MonoBehaviour { /// <summary> /// The delay between spawns in seconds /// </summary> public float spawnDelay = 10f; /// <summary> /// The number of AI to spawn. This will include 1 commander and the rest as soldiers. /// </summary> public int squadSize = 5; /// <summary> /// The number of squads to spawn /// </summary> public int squadCount = 5; /// <summary> /// A timer tracking next spawn /// </summary> private float timer = 0f; /// <summary> /// The Commander prefab/object to replicate /// </summary> public GameObject Commander = null; /// <summary> /// The Soldier prefab/object to replicate /// </summary> public GameObject Soldier = null; /// <summary> /// The list of instantiated soldiers /// </summary> private Stack<GameObject> squads = new Stack<GameObject>(); public void Start() { // We aren't going to work without a commander and soldier if (Commander == null || Soldier == null) return; Preload(); } /// <summary> /// Update the timer and check for respawn. Create a team of 1 commander and squadSize - 1 soldiers /// </summary> public void Update() { if (timer <= 0f) { Spawn(); timer = spawnDelay; } else timer -= Time.deltaTime; } private void Preload() { squads.Clear(); for (int i = 0; i < squadCount; i++) { // 1 commander if (squadSize > 0) { squads.Push((GameObject)GameObject.Instantiate(Commander, gameObject.transform.position, gameObject.transform.rotation)); squads.Peek().transform.parent = gameObject.transform; squads.Peek().SetActive(false); } // squadSize - 1 soldiers, arrayed in line behind the spawn point for (int j = 1; j < squadSize; j++) { squads.Push((GameObject)GameObject.Instantiate(Soldier, gameObject.transform.position - (gameObject.transform.forward * (float)j), gameObject.transform.rotation)); squads.Peek().transform.parent = gameObject.transform; squads.Peek().SetActive(false); } } } private void Spawn() { for (int i = 0; i < squadSize && i < squads.Count; i++) { squads.Peek().SetActive(true); squads.Pop(); } } }
July 10, 2022 at 4:48 pm #38522Thank you for the script, yes the script is definitely moving in the right direction, however there is still some of that character lag when enemies are spawned, further more soldiers are “on top” of each other literally, so yes it is a step in the right direction, but I still feel we can do a “little” more to brush this script in particularly in terms of game play “lag”…look forward to your next input…
July 13, 2022 at 10:29 am #38536Well if soldiers are on top of each other it is likely that they are colliding with each other. Squad Command has rigid bodies on the soldiers but it removes the Character layer from colliding with itself (in the Physics settings), allowing them to pass through each other.
As far as lag is concerned, using this in Unity 5.1 and using the profiler, I no longer detect any lag on spawn. There is an occasional GC collection but it no longer lines up with the actual spawn. I don’t think there is anything we can do with this particular script that will change any of that.
As far as GC collection is concerned. We do have one fix that will be in the next release to reduce these further, but it never completely goes away.
July 14, 2022 at 11:36 am #38574I am still having the issue of lag, there must be a way of getting around this, if not then another way has to be thought of as this script is no use as it stands, worst still it cost money…
Can we not use an Ienumerator?
July 14, 2022 at 1:12 pm #38577See if you can run the profiler and see where the lag is coming from. It should be fairly clear as it will suddenly spike. You can also click the spike and see what is running at the time.
Try turning down the spawn delay as well when looking at the profiler, so that you can see multiple spawns on the profiler window at the same time. This is what mine looks like right now, using the same Squad Command that is on the store, with the new Spawner (set spawn delay to 1 and number of soldiers to 8).
July 14, 2022 at 1:23 pm #38580In retrospect, this is what it looked like with the old spawner:
So this was definitely a much needed change to the spawner, and will be in the next version for sure. Now lets see if we can hunt down where your lag is coming from.
July 27, 2022 at 3:44 pm #38740Hi guys any suggestions?
-
AuthorPosts
You must be logged in to reply to this topic.