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;
        }
    }
}