I am working on a game that uses items and slots to put them in. There is a store menu with a grid of slots that fill in dynamically when the menu opens using a slot prefab that is also used at runtime for the player inventory.
Each slot has multiple UI components in it for different things like icon, text, status indicators etc.
What I am seeing is that the frame that the shop menu is opened it fills in a grid of 64 of these slot prefabs to then display items for sale. The CPU ms it takes to instantiate those slots is enormous like 250ms on my particular rig. At any rate, it causes a noticeable frame hitch compared to the regular framerate of the game.
I looked at the profiler and all this time seems to be tied up within the internal Instantiate code (Copy, Awake, Produce).
I was wondering if there were some secrets I could use to help increase the performance of this. Is there any way to batch instantiate? Would that even help? Should I think about just reducing the amount of stuff that is in each slot? Instantiating them over many game frames and then making the menu grid visible only after they are done? Just looking for tips from the community.
It’s not a huge issue for the game but its noticeable and I would like to polish it up.
Edit: grammar
Yeah creating a GameObjectCache concept completely wiped out this hitch. I have it in the DontDestroyOnLoad scene and keep a static reference to it in a global static GameState object.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif //#if UNITY_EDITOR
public class GameObjectCache : MonoBehaviour
{
public Dictionary< string, List<GameObject> > cache;
public Dictionary< string, GameObject > root;
public GameObjectCache()
{
cache = new Dictionary<string, List<GameObject>>();
root = new Dictionary<string, GameObject>();
}
public void Start()
{
if ( GameState.ObjectCache == null )
GameState.ObjectCache = this;
}
public void OnDestroy()
{
if ( GameState.ObjectCache == this )
GameState.ObjectCache = null;
}
public List<GameObject> GetList( string prefabPath )
{
prefabPath = prefabPath.ToLower();
GameObject prefab = Resources.Load<GameObject>( prefabPath );
if ( prefab == null )
{
Debug.LogError( "GameObjectCache - invalid prefab path '" + prefabPath + "'" );
return null;
}
if ( !cache.ContainsKey( prefabPath ) )
cache.Add( prefabPath, new List<GameObject>() );
if ( !root.ContainsKey( prefabPath ) )
{
GameObject newRoot = new GameObject();
newRoot.transform.SetParent( transform );
newRoot.SetActive( false );
newRoot.name = prefabPath;
root.Add( prefabPath, newRoot );
}
return cache[prefabPath];
}
public void Precache( string prefabPath, int count )
{
prefabPath = prefabPath.ToLower();
GameObject prefab = Resources.Load<GameObject>( prefabPath );
List<GameObject> list = GetList( prefabPath );
if ( list != null && prefab != null )
{
for ( int i = count - list.Count; i > 0; i-- )
{
GameObject obj = GameObject.Instantiate<GameObject>( prefab, root[prefabPath].transform );
if ( obj != null )
cache[prefabPath].Add( obj );
}
}
}
public GameObject Pop( string prefabPath )
{
prefabPath = prefabPath.ToLower();
List<GameObject> list = GetList( prefabPath );
if ( list.Count == 0 )
{
GameObject prefab = Resources.Load<GameObject>( prefabPath );
if ( prefab != null )
return GameObject.Instantiate<GameObject>( prefab );
}
GameObject result = list[0];
list.RemoveAt( 0 );
if ( result == null )
{
GameObject prefab = Resources.Load<GameObject>( prefabPath );
if ( prefab != null )
return GameObject.Instantiate<GameObject>( prefab );
}
return result;
}
public void Push( string prefabPath, GameObject gameObj )
{
if ( gameObj == null )
return;
prefabPath = prefabPath.ToLower();
List<GameObject> list = GetList( prefabPath );
if ( list != null )
{
list.Add( gameObj );
gameObj.transform.SetParent( root[prefabPath].transform );
}
}
}
#if UNITY_EDITOR
[CustomEditor( typeof( GameObjectCache ), true )]
public class EditorGameObjectCache : Editor
{
public override void OnInspectorGUI()
{
Handles.BeginGUI();
GUI.changed = false;
GameObjectCache editObject = (GameObjectCache)target;
int total = 0;
EditorGUILayout.Space();
EditorGUILayout.LabelField( "Cached Game Objects:" );
foreach ( string key in editObject.cache.Keys )
{
for ( int i = editObject.cache[key].Count - 1; i >= 0; i-- )
{
if ( editObject.cache[key] *== null )*
-
editObject.cache[key].RemoveAt( i );*
-
}*
-
EditorGUILayout.LabelField( " " + key + ": " + editObject.cache[key].Count );*
-
total += editObject.cache[key].Count;*
-
}*
-
EditorGUILayout.LabelField( "Total: " + total);*
-
EditorGUILayout.Space();*
-
if ( GUI.changed )*
-
editObject.SetDirty();*
-
Handles.EndGUI();*
-
}*
}
#endif //#if UNITY_EDITOR