NRLDash
As part of my Internship with Pixeloco I worked with the Lead Developer on this AR Running game. I coded the Audience Spawning Code using the plugin GPU Instancer in Unity which allow me the add 3000 audience objects to spawn in the stadium seats running the game at 70fps and alone at 122fps. I also created the High Score Front End Website Code using CSS and HTML5.
Audience Spawner Script C#
using System.Collections; using System.Collections.Generic; using System; using System.Diagnostics; using System.Threading; using System.IO; using UnityEditor; using UnityEngine; //Created by: Emily Cochrane 2/08/19 namespace GPUInstancer { public class AudienceSpawner : MonoBehaviour { //480 seats in Test Stadium //childcount public int childcount = 0; public string audienceTag; public GameObject audience; public Vector3 audienceSize = new Vector3(0.03f, 0.03f, 0.03f); public GameObject[] audienceMembers; public GameObject[] seatParent; public GameObject[] tagged; public Texture2D[] audienceTextures; public Material audienceMaterial; public Material[] audienceMaterials; public GPUInstancerPrefabManager prefabManager; public AudienceDataSO scriptableObject; private GameObject fileParent; //for each audience model so they only get called 1 time per list private List<GameObject> instanceList; private List<GameObject> instanceList2; private List<GameObject> instanceList3; private List<GameObject> instanceList4; private GPUInstancerPrefabPrototype prototype, p2, p3, p4; private GameObject prototypeGameObject; void Start() { SpawnInstancedFromFile(); } //spawn audience members //find and return gameobjects name by parent GameObject findParent(GameObject parent) { return GameObject.Find(parent.name); } //spawn an audience member on the children of this script (only one layer deep) void SearchByChild() { childcount = this.gameObject.transform.childCount; for (int i = 0; i < childcount; i++) { GameObject Seat = this.gameObject.transform.GetChild(i).gameObject; GameObject Audience = Instantiate(audience, Seat.transform.position, Seat.transform.rotation); Audience.transform.parent = Seat.transform;// makes the audienceMember a child of seat Audience.transform.localScale = audienceSize;// scale the caspule to fit the stadium } } //spawn audience members in the children of the parents array supplied void SearchByChild(GameObject[] seatParents) { foreach (GameObject parent in seatParents) { childcount = parent.gameObject.transform.childCount; for (int i = 0; i < childcount; i++) { GameObject Seat = parent.gameObject.transform.GetChild(i).gameObject; GameObject Audience = Instantiate(audience, Seat.transform.position, Seat.transform.rotation); Audience.transform.parent = Seat.transform;// makes the audienceMember a child of seat } } } //spawn audience members in the gameobjects with the tag void SearchByTag(string tag) { tagged = GameObject.FindGameObjectsWithTag(tag); foreach (GameObject seat in tagged) { Vector3 seatSize = seat.GetComponent<Renderer>().bounds.size; GameObject audienceMember = Instantiate(audience, seat.transform.position, seat.transform.rotation); audienceMember.transform.parent = seat.transform;// makes the audienceMember a child of seat } } //create 3000 objects in one parent void Create3000(GameObject parent) { GameObject Row1 = new GameObject(); for (int i = 0; i < 3000; i++) { GameObject audienceMember = Instantiate(Row1, parent.transform.position, parent.transform.rotation); audienceMember.transform.parent = parent.transform; audienceMember.tag = audienceTag; audienceMember.AddComponent<UnityEngine.MeshRenderer>(); } } // testing which function is faster to spawn the Audience void TestTimeBetweenTagAndChild() { //Create3000(seatParent[0]); Stopwatch st = new Stopwatch(); st.Start(); SearchByChild(seatParent); st.Stop(); TimeSpan timespan = st.Elapsed; string elapsedtime = string.Format("{0:00}:{1:00}:{2:00}.{3:00}", timespan.Hours, timespan.Minutes, timespan.Seconds, timespan.Milliseconds / 10); Stopwatch st2 = new Stopwatch(); st2.Start(); SearchByTag(audienceTag); st2.Stop(); TimeSpan timespan2 = st2.Elapsed; string elapsedtime2 = string.Format("{0:00}:{1:00}:{2:00}.{3:00}", timespan2.Hours, timespan2.Minutes, timespan2.Seconds, timespan2.Milliseconds / 10); } //save the seat positions using the parents to save to the scriptable object needs to be run at least once to be used by SpawnInstancedFromFile() void SaveSeatsInScriptableObject() { int totalChildCount = 0; foreach (GameObject parent in seatParent) { childcount = parent.gameObject.transform.childCount; for (int i = 0; i < childcount; i++) { scriptableObject.seatPosition[totalChildCount] = parent.gameObject.transform.GetChild(i).gameObject.transform.position;//get the child of the parent scriptableObject.seatRotation[totalChildCount] = parent.gameObject.transform.GetChild(i).gameObject.transform.rotation; totalChildCount++; } } } //this code is taken from the GPUInstancer plugin and expands on the SpawnFromFile() function -- Needs to have a scriptable object, add the direction to the front of the stands void SpawnInstancedFromFile() { //create the parent game object to hold the Clones in the hierachy fileParent = new GameObject(); fileParent.name = "AudienceClonesParent"; fileParent.transform.position = new Vector3(0, 0, 0); int childCount = 0; int totalChildCount = 0; // Create a list to keep track of instances instanceList = new List<GameObject>(); instanceList2 = new List<GameObject>(); instanceList3 = new List<GameObject>(); instanceList4 = new List<GameObject>(); for (int i = 0; i < scriptableObject.seatPosition.Length; i++) { Vector3 newSeatPos = scriptableObject.seatPosition[i];//convert string to Vector3 Quaternion newSeatRot = scriptableObject.seatRotation[i]; int spawnRand = UnityEngine.Random.Range(0, 4);// randomly skip a spawn(range is actually 0 -3)? if (spawnRand != 3) { int randAM = UnityEngine.Random.Range(0, 4); prototypeGameObject = audienceMembers[randAM]; // this created muliple instance drawns for each type of gameobject GameObject Audience = Instantiate(prototypeGameObject, newSeatPos, newSeatRot); Audience.transform.parent = fileParent.transform;// makes the audience a child of fileParent switch (randAM) { case 0: instanceList.Add(Audience); // Define the prototype prototype = GPUInstancerAPI.DefineGameObjectAsPrefabPrototypeAtRuntime(prefabManager, prototypeGameObject); //// Make changes in the prototype settings prototype.enableRuntimeModifications = true; prototype.autoUpdateTransformData = true; break; case 1: instanceList2.Add(Audience); // Define the prototype p2 = GPUInstancerAPI.DefineGameObjectAsPrefabPrototypeAtRuntime(prefabManager, prototypeGameObject); //// Make changes in the prototype settings p2.enableRuntimeModifications = true; p2.autoUpdateTransformData = true; break; case 2: instanceList3.Add(Audience); // Define the prototype p3 = GPUInstancerAPI.DefineGameObjectAsPrefabPrototypeAtRuntime(prefabManager, prototypeGameObject); //// Make changes in the prototype settings p3.enableRuntimeModifications = true; p3.autoUpdateTransformData = true; break; case 3: instanceList4.Add(Audience); // Define the prototype p4 = GPUInstancerAPI.DefineGameObjectAsPrefabPrototypeAtRuntime(prefabManager, prototypeGameObject); //// Make changes in the prototype settings p4.enableRuntimeModifications = true; p4.autoUpdateTransformData = true; break; } childCount++; } totalChildCount++; } //// Add the prototype instances GPUInstancerAPI.AddInstancesToPrefabPrototypeAtRuntime(prefabManager, prototype, instanceList); GPUInstancerAPI.AddInstancesToPrefabPrototypeAtRuntime(prefabManager, p2, instanceList2); GPUInstancerAPI.AddInstancesToPrefabPrototypeAtRuntime(prefabManager, p3, instanceList3); GPUInstancerAPI.AddInstancesToPrefabPrototypeAtRuntime(prefabManager, p4, instanceList4); } public static Vector3 StringToVector3(string sVector) { // Remove the parentheses if (sVector.StartsWith("(") && sVector.EndsWith(")")) { sVector = sVector.Substring(1, sVector.Length - 2); } // split the items string[] sArray = sVector.Split(','); // store as a Vector3 Vector3 result = new Vector3( float.Parse(sArray[0]), float.Parse(sArray[1]), float.Parse(sArray[2])); return result; } } }