Quick question. Is there a way to identify the prefab from which a clone was created? I need to have certaing objects (clones) at times trying to find other, identical objects (clones from the same prefab). I'd prefer not to store the reference to the prefab manually on the cloned object.
I would make a MonoBehavior that registers itself at Start() with a central list of "things just like me." Stick that on the base prefab and every time you instantiate one, it will register itself centrally. By using a combination of static "singleton-ish" constructs within a MonoBehavior for the manager, plus the instance-level Start() call that says "Hey register me with the manager," you can do the entire thing in a single script.
I often need a way to access all of some type. So I create a static HashSet for that type that you Add objects to OnEnable, and remove OnDisable. Simple example: Code (csharp): public class MyBehaviour : MonoBehaviour { public static HashSet<MyBehaviour> Pool = new HashSet<MyBehaviour>(); void OnEnable() { _table.Add(this); } void OnDisable() { _table.Remove(this); } } Of course in real practice I wrap the HashSet in a class I call MultitonPool that extends the functionality a bit more with Find methods, and safe registering: https://github.com/lordofduct/space...er/SpacepuppyBase/Collections/MultitonPool.cs Code (csharp): public class MultitonPool<T> : IMultitonPool<T> where T : class { #region Fields private HashSet<T> _pool; private bool _querying; private System.Action _queryCompleteAction; #endregion #region CONSTRUCTOR public MultitonPool() { _pool = new HashSet<T>(); } public MultitonPool(IEqualityComparer<T> comparer) { _pool = new HashSet<T>(comparer); } #endregion #region IMultitonPool Interface public void AddReference(T obj) { if (object.ReferenceEquals(obj, null)) throw new System.ArgumentNullException(); if (_querying) { if (!_pool.Contains(obj)) _queryCompleteAction += () => _pool.Add(obj); } else { _pool.Add(obj); } } public bool RemoveReference(T obj) { if (object.ReferenceEquals(obj, null)) throw new System.ArgumentNullException(); if (_querying) { if (_pool.Contains(obj)) { _queryCompleteAction += () => _pool.Remove(obj); return true; } else { return false; } } else { return _pool.Remove(obj); } } public T Find(System.Func<T, bool> predicate) { if (_querying) throw new System.InvalidOperationException("MultitonPool is already in the process of a query."); _querying = true; try { var e = _pool.GetEnumerator(); if (predicate == null) { if (e.MoveNext()) return e.Current; else return null; } while (e.MoveNext()) { if (predicate(e.Current)) return e.Current; } return null; } finally { if (_queryCompleteAction != null) { _queryCompleteAction(); _queryCompleteAction = null; } _querying = false; } } public T[] FindAll(System.Func<T, bool> predicate) { if (_querying) throw new System.InvalidOperationException("MultitonPool is already in the process of a query."); try { if (predicate == null) { _querying = true; T[] arr = new T[_pool.Count]; var e = _pool.GetEnumerator(); int i = 0; while (e.MoveNext()) { arr[i] = e.Current; i++; } return arr; } else { using (var lst = TempCollection.GetList<T>()) { FindAll(lst, predicate); return lst.ToArray(); } } } finally { if (_queryCompleteAction != null) { _queryCompleteAction(); _queryCompleteAction = null; } _querying = false; } } public int FindAll(ICollection<T> coll, System.Func<T, bool> predicate) { if (coll == null) throw new System.ArgumentNullException("coll"); if (_querying) throw new System.InvalidOperationException("MultitonPool is already in the process of a query."); _querying = true; try { int cnt = 0; var e = _pool.GetEnumerator(); if (predicate == null) { while (e.MoveNext()) { coll.Add(e.Current); cnt++; } } else { while (e.MoveNext()) { if (predicate(e.Current)) { coll.Add(e.Current); cnt++; } } } return cnt; } finally { if (_queryCompleteAction != null) { _queryCompleteAction(); _queryCompleteAction = null; } _querying = false; } } public int FindAll<TSub>(ICollection<TSub> coll, System.Func<TSub, bool> predicate) where TSub : class, T { if (coll == null) throw new System.ArgumentNullException("coll"); if (_querying) throw new System.InvalidOperationException("MultitonPool is already in the process of a query."); _querying = true; try { int cnt = 0; var e = _pool.GetEnumerator(); if (predicate == null) { while (e.MoveNext()) { if (e.Current is TSub) { coll.Add((TSub)e.Current); cnt++; } } } else { while (e.MoveNext()) { if (e.Current is TSub && predicate((TSub)e.Current)) { coll.Add((TSub)e.Current); cnt++; } } } return cnt; } finally { if (_queryCompleteAction != null) { _queryCompleteAction(); _queryCompleteAction = null; } _querying = false; } } #endregion #region IEnumerable Interface public Enumerator GetEnumerator() { return new Enumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return this.GetEnumerator(); } #endregion #region Special Types public struct Enumerator : IEnumerator<T> { #region Fields private HashSet<T>.Enumerator _e; #endregion #region CONSTRUCTOR public Enumerator(MultitonPool<T> multi) { if (multi == null) throw new System.ArgumentNullException(); _e = multi._pool.GetEnumerator(); } #endregion public T Current { get { return _e.Current; } } object IEnumerator.Current { get { return _e.Current; } } public void Dispose() { _e.Dispose(); } public bool MoveNext() { return _e.MoveNext(); } void IEnumerator.Reset() { (_e as IEnumerator).Reset(); } } #endregion } And implemented: Code (csharp): public class MyBehaviour : MonoBehaviour { public static readonly MultitonPool<MyBehaviour> Pool = new MultitonPool<MyBehaviour>(); void OnEnable() { _table.AddReference(this); } void OnDisable() { _table.RemoveReference(this); } } Now of course this wouldn't find by prefab it was sourced from, but rather all of some type. But if you also register the prefab with the object at spawn, you can then use the 'Find' method to compare prefab source: Code (csharp): public class MyBehaviour : MonoBehaviour { public static readonly MultitonPool<MyBehaviour> Pool = new MultitonPool<MyBehaviour>(); private MyBehaviour _prefabSource; void OnEnable() { _table.AddReference(this); } void OnDisable() { _table.RemoveReference(this); } public void Init(MyBehaviour prefabSource) { _prefabSource = prefabSource; } public MyBehaviour PrefabSource { get { return _prefabSource; } } } When instantiating from prefab: Code (csharp): MyBehaviour prefab = *the prefab*; var instance = Instantiate(prefab, Vector3.zero, Quaternion.identity) as MyBehaviour; instance.Init(prefab); And you can search like so: Code (csharp): MyBehaviour target = *some MyBehaviour you want to find the siblings of*; var relatives = MyBehaviour.Pool.FindAll((c) => c.PrefabSource == target.PrefabSource); If you wanted to generalize spawned object's so that any of any type can be generically associated with it's prefab source... well I do that with a special 'SpawnedObjectController' which gets attached to all objects I spawn through my 'SpawnPool'. SpawnedObjectController: https://github.com/lordofduct/space...cepuppySpawn/Spawn/SpawnedObjectController.cs SpawnPool: https://github.com/lordofduct/space...lob/master/SpacepuppySpawn/Spawn/SpawnPool.cs I no longer use Instantiate, and rather call 'SpawnPool.DefaultPool.Spawn(...)'. This automatically will add the controller and associate the pool and prefab with it. So you don't have to manually do it.