I have recently been trying out object pooling in unity to speed up the instantiation of several game objects at once.
However, since these are fairly complex objects I need to reset them when they go back in the pool.
I read that using ScriptableObject might be a good way to store the default values for an easy reset. But in order to do that I need to load a fresh ScriptableObject at runtime to store the actual values of the object.
So in pseudocode, i'd have a class with public MyScriptableData data
and public MyScriptableData defaults
1) create new pooled object with default ScriptableObject data = defaults;
;
2) do stuff that changes values of scriptable object during lifetime of object
3) deactivate, and then return pooled object to pool, resetting the scriptableObject to its default (data = defaults;
again).
I have 3 main questions:
A) I'm not sure how to actually implement this. It seems to me, in step 2, the default values would be changed. Therefore resetting to defaults would do nothing. I thought about creating a new instance of my scriptable object using
data = ScriptableObject.CreateInstance<MyScriptableData>();
but then how would I copy in the default values from defaults
, ensuring in never changing the defaults? I would like for the defaults to be editable in the unity editor as an asset.
B) If I use CreateInstance, will the performance be bad? The whole reason i'm doing this object pooling is to reduce the performance costs of object instantiation. I'd hate to reintroduce slow code by instantiating scriptable objects.
C) Is this approach alright? or is there a better way to reset objects before going back into the pool?
EDIT based on some answers: I already have a setup that has a long list of fields, and then stores the default values of theses fields in a dictionary. But I found every time I wanted to add/change/remove a field, I had to change code in several spots
ATTEMPTED SOLUTION (But wrong, see below): I created an extension method for ScriptableObject:
using UnityEngine;
using System.Reflection;
public static class ScriptableObjectExtension {
public static T ShallowCopy<T> (this T orig) where T : ScriptableObject {
T copiedObject = ScriptableObject.CreateInstance<T> ();
FieldInfo[] myObjectFields = orig.GetType ().GetFields (
BindingFlags.NonPublic | BindingFlags.Public |
BindingFlags.Instance);
foreach (FieldInfo fi in myObjectFields) {
fi.SetValue (copiedObject, fi.GetValue (orig));
}
return copiedObject;
}
}
FINAL SOLUTION:
The above script worked to clone scriptable objects, however, it appears I was going down the wrong path with that solution.
Several people below pointed out that pooling isn't that important in unity for most applications. I had originally tried to put pooling in because my framerate according to the profiler was around 30-15 fps, and I thought pooling would help improve that.
Based on the comments I dug a bit deeper and found that there was a process called LogStringToConsole. I said to myself, could this be as simple as my Debug.Log statements slowing things down!? I deleted them and the huge spikes went away. Apparently Debug.Log causes huge performance problems. Now I'm well above 60fps. Because of this I have decided not to pool those objects (But I still use pooling on simpler objects in another scenario that are being spawned several times per second). This means I don't need to worry about scriptable objects here at all. I now have and instantiate that loads a prefab and an Init method to set things up, and the objects are destroyed when they are used up.
When I went back to using instantiate/destroy, I didn't notice a significant change in performance. Thanks for all the responses!