frarees
1
I’m developing a serialization tool on top of Unity. Every time I create an object and want to deserialize data to it, I have to retrieve all components to provide them with sensible data. The soonest I can do this is on Awake and via GetComponents(). However, this isn’t as fast as I would like it to, when components per GO are high or there are too much GOs to deserialize.
Is there a faster way to get every component a GO have? I imagine you cannot cache them at editor (I presume the instances are generated once instantiated… makes sense…), and I don’t see any property on GameObject exposing the Component I need.
Note that I want to retrieve every component on my GameObject just after its instantiation (and wisely, in the same tick) – the objects won’t be residing on the scene at build time, but will be instantiated at some point of the execution
Thanks
Try this:
using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
public class CacheComponents : MonoBehaviour
{
public List<Component> components;
public bool cacheNow;
void Awake()
{
if(!Application.isPlaying)
Cache();
}
void Update()
{
if(cacheNow)
{
cacheNow = false;
Cache();
}
}
void Cache()
{
components = new List<Component>();
foreach(var component in GetComponents<Component>())
{
if(component != this) components.Add(component);
}
}
}
Sisso
2
A partial and non so generic solution.
Before build you iterate between all Prefabs and objects in scene, then, attach a script that cache all information that you will need. For version 2, if you don’t want to dirt your objects you should catalog in a unique prefab, but you have a problem to identify wich object it is or for wich prefab (you can add a script with the id… ops, failed again :P).
If you need to interate between prefabas and scenes you can use this. It is a incrible usefull stuff to make dirt scripts and prepare your build.
Edited: Try to explain with code
Lets try, I will explain in code (not compiled :P)
This is your utility class that cache the components names
class ComponentsCache extends MonoBehaviour {
static function GenareteCache(obj: GameObject) {
var gc = obj.GetComponent(ComponentsCache);
if (!gc) gc = obj.AddComponent(ComponentsCache);
var names: String[] = [c.name for (c in obj.GetComponents())];
gc.componentNames = names;
}
static function GetComponentNames(obj: GameObject) {
// if we have build time cached
var gc = obj.GetComponent(ComponentsCache);
if (gc) return gc.componentsNames;
// if we don't have a cache, like in the editor or in objects created in runtime not derived from prefabs, we use the old fashion
return [c.name for (c in obj.GetComponents())];
}
var componentsNames: String[];
}
This is the code that you run on build time to cache all objects. Generally, for release only.
var ForAll = function() {
// for all objects generate cache
for (var obj in GameObject.FindObjectOfType(GameObject)) {
ComponentsCache.GenerateCache(obj);
}
}
EditorUtils.ForEachScene(function (sceneName: String) {
// we are in a scene, execute for all
ForAll();
return true;
});
EditorUtils.ForEachPrefab(function (obj: GameObject) {
// we are in a scene with prefab obj instantiated, execute for all
ForAll();
return true;
});
Now when you need at runtime the components names of any object you simple do
components = ComponentsCache.GetComponentNames(anyRuntimeObject)