Search Unity

Identify prefab of clone?

Discussion in 'Scripting' started by mattec75, Jun 16, 2017.

  1. mattec75

    mattec75

    Joined:
    Apr 11, 2017
    Posts:
    3
    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.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    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.
     
    lordofduct likes this.
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    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):
    1.  
    2. public class MyBehaviour : MonoBehaviour
    3. {
    4.  
    5.     public static HashSet<MyBehaviour> Pool = new HashSet<MyBehaviour>();
    6.  
    7.     void OnEnable()
    8.     {
    9.         _table.Add(this);
    10.     }
    11.  
    12.     void OnDisable()
    13.     {
    14.         _table.Remove(this);
    15.     }
    16.  
    17. }
    18.  
    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):
    1.  
    2.     public class MultitonPool<T> : IMultitonPool<T> where T : class
    3.     {
    4.  
    5.         #region Fields
    6.  
    7.         private HashSet<T> _pool;
    8.         private bool _querying;
    9.         private System.Action _queryCompleteAction;
    10.  
    11.         #endregion
    12.  
    13.         #region CONSTRUCTOR
    14.  
    15.         public MultitonPool()
    16.         {
    17.             _pool = new HashSet<T>();
    18.         }
    19.  
    20.         public MultitonPool(IEqualityComparer<T> comparer)
    21.         {
    22.             _pool = new HashSet<T>(comparer);
    23.         }
    24.  
    25.         #endregion
    26.  
    27.         #region IMultitonPool Interface
    28.  
    29.         public void AddReference(T obj)
    30.         {
    31.             if (object.ReferenceEquals(obj, null)) throw new System.ArgumentNullException();
    32.  
    33.             if (_querying)
    34.             {
    35.                 if (!_pool.Contains(obj)) _queryCompleteAction += () => _pool.Add(obj);
    36.             }
    37.             else
    38.             {
    39.                 _pool.Add(obj);
    40.             }
    41.         }
    42.  
    43.         public bool RemoveReference(T obj)
    44.         {
    45.             if (object.ReferenceEquals(obj, null)) throw new System.ArgumentNullException();
    46.  
    47.             if (_querying)
    48.             {
    49.                 if (_pool.Contains(obj))
    50.                 {
    51.                     _queryCompleteAction += () => _pool.Remove(obj);
    52.                     return true;
    53.                 }
    54.                 else
    55.                 {
    56.                     return false;
    57.                 }
    58.             }
    59.             else
    60.             {
    61.                 return _pool.Remove(obj);
    62.             }
    63.         }
    64.  
    65.         public T Find(System.Func<T, bool> predicate)
    66.         {
    67.             if (_querying) throw new System.InvalidOperationException("MultitonPool is already in the process of a query.");
    68.             _querying = true;
    69.  
    70.             try
    71.             {
    72.                 var e = _pool.GetEnumerator();
    73.                 if (predicate == null)
    74.                 {
    75.                     if (e.MoveNext())
    76.                         return e.Current;
    77.                     else
    78.                         return null;
    79.                 }
    80.  
    81.                 while (e.MoveNext())
    82.                 {
    83.                     if (predicate(e.Current)) return e.Current;
    84.                 }
    85.                 return null;
    86.             }
    87.             finally
    88.             {
    89.                 if (_queryCompleteAction != null)
    90.                 {
    91.                     _queryCompleteAction();
    92.                     _queryCompleteAction = null;
    93.                 }
    94.                 _querying = false;
    95.             }
    96.         }
    97.  
    98.         public T[] FindAll(System.Func<T, bool> predicate)
    99.         {
    100.             if (_querying) throw new System.InvalidOperationException("MultitonPool is already in the process of a query.");
    101.  
    102.             try
    103.             {
    104.                 if (predicate == null)
    105.                 {
    106.                     _querying = true;
    107.  
    108.                     T[] arr = new T[_pool.Count];
    109.                     var e = _pool.GetEnumerator();
    110.                     int i = 0;
    111.                     while (e.MoveNext())
    112.                     {
    113.                         arr[i] = e.Current;
    114.                         i++;
    115.                     }
    116.                     return arr;
    117.                 }
    118.                 else
    119.                 {
    120.                     using (var lst = TempCollection.GetList<T>())
    121.                     {
    122.                         FindAll(lst, predicate);
    123.                         return lst.ToArray();
    124.                     }
    125.                 }
    126.             }
    127.             finally
    128.             {
    129.                 if (_queryCompleteAction != null)
    130.                 {
    131.                     _queryCompleteAction();
    132.                     _queryCompleteAction = null;
    133.                 }
    134.                 _querying = false;
    135.             }
    136.         }
    137.  
    138.         public int FindAll(ICollection<T> coll, System.Func<T, bool> predicate)
    139.         {
    140.             if (coll == null) throw new System.ArgumentNullException("coll");
    141.             if (_querying) throw new System.InvalidOperationException("MultitonPool is already in the process of a query.");
    142.             _querying = true;
    143.  
    144.             try
    145.             {
    146.                 int cnt = 0;
    147.                 var e = _pool.GetEnumerator();
    148.                 if (predicate == null)
    149.                 {
    150.                     while (e.MoveNext())
    151.                     {
    152.                         coll.Add(e.Current);
    153.                         cnt++;
    154.                     }
    155.                 }
    156.                 else
    157.                 {
    158.                     while (e.MoveNext())
    159.                     {
    160.                         if (predicate(e.Current))
    161.                         {
    162.                             coll.Add(e.Current);
    163.                             cnt++;
    164.                         }
    165.                     }
    166.                 }
    167.                 return cnt;
    168.             }
    169.             finally
    170.             {
    171.                 if (_queryCompleteAction != null)
    172.                 {
    173.                     _queryCompleteAction();
    174.                     _queryCompleteAction = null;
    175.                 }
    176.                 _querying = false;
    177.             }
    178.         }
    179.  
    180.         public int FindAll<TSub>(ICollection<TSub> coll, System.Func<TSub, bool> predicate) where TSub : class, T
    181.         {
    182.             if (coll == null) throw new System.ArgumentNullException("coll");
    183.             if (_querying) throw new System.InvalidOperationException("MultitonPool is already in the process of a query.");
    184.             _querying = true;
    185.  
    186.             try
    187.             {
    188.                 int cnt = 0;
    189.                 var e = _pool.GetEnumerator();
    190.                 if (predicate == null)
    191.                 {
    192.                     while (e.MoveNext())
    193.                     {
    194.                         if (e.Current is TSub)
    195.                         {
    196.                             coll.Add((TSub)e.Current);
    197.                             cnt++;
    198.                         }
    199.                     }
    200.                 }
    201.                 else
    202.                 {
    203.                     while (e.MoveNext())
    204.                     {
    205.                         if (e.Current is TSub && predicate((TSub)e.Current))
    206.                         {
    207.                             coll.Add((TSub)e.Current);
    208.                             cnt++;
    209.                         }
    210.                     }
    211.                 }
    212.  
    213.                 return cnt;
    214.             }
    215.             finally
    216.             {
    217.                 if (_queryCompleteAction != null)
    218.                 {
    219.                     _queryCompleteAction();
    220.                     _queryCompleteAction = null;
    221.                 }
    222.                 _querying = false;
    223.             }
    224.         }
    225.  
    226.         #endregion
    227.  
    228.         #region IEnumerable Interface
    229.  
    230.         public Enumerator GetEnumerator()
    231.         {
    232.             return new Enumerator(this);
    233.         }
    234.  
    235.         IEnumerator IEnumerable.GetEnumerator()
    236.         {
    237.             return this.GetEnumerator();
    238.         }
    239.  
    240.         IEnumerator<T> IEnumerable<T>.GetEnumerator()
    241.         {
    242.             return this.GetEnumerator();
    243.         }
    244.  
    245.         #endregion
    246.  
    247.         #region Special Types
    248.  
    249.         public struct Enumerator : IEnumerator<T>
    250.         {
    251.  
    252.             #region Fields
    253.  
    254.             private HashSet<T>.Enumerator _e;
    255.  
    256.             #endregion
    257.  
    258.             #region CONSTRUCTOR
    259.  
    260.             public Enumerator(MultitonPool<T> multi)
    261.             {
    262.                 if (multi == null) throw new System.ArgumentNullException();
    263.                 _e = multi._pool.GetEnumerator();
    264.             }
    265.  
    266.             #endregion
    267.  
    268.             public T Current
    269.             {
    270.                 get
    271.                 {
    272.                     return _e.Current;
    273.                 }
    274.             }
    275.  
    276.             object IEnumerator.Current
    277.             {
    278.                 get
    279.                 {
    280.                     return _e.Current;
    281.                 }
    282.             }
    283.  
    284.             public void Dispose()
    285.             {
    286.                 _e.Dispose();
    287.             }
    288.  
    289.             public bool MoveNext()
    290.             {
    291.                 return _e.MoveNext();
    292.             }
    293.  
    294.             void IEnumerator.Reset()
    295.             {
    296.                 (_e as IEnumerator).Reset();
    297.             }
    298.         }
    299.  
    300.         #endregion
    301.  
    302.     }
    303.  
    And implemented:
    Code (csharp):
    1.  
    2. public class MyBehaviour : MonoBehaviour
    3. {
    4.  
    5.     public static readonly MultitonPool<MyBehaviour> Pool = new MultitonPool<MyBehaviour>();
    6.  
    7.     void OnEnable()
    8.     {
    9.         _table.AddReference(this);
    10.     }
    11.  
    12.     void OnDisable()
    13.     {
    14.         _table.RemoveReference(this);
    15.     }
    16.  
    17. }
    18.  
    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):
    1.  
    2. public class MyBehaviour : MonoBehaviour
    3. {
    4.  
    5.     public static readonly MultitonPool<MyBehaviour> Pool = new MultitonPool<MyBehaviour>();
    6.  
    7.     private MyBehaviour _prefabSource;
    8.  
    9.     void OnEnable()
    10.     {
    11.         _table.AddReference(this);
    12.     }
    13.  
    14.     void OnDisable()
    15.     {
    16.         _table.RemoveReference(this);
    17.     }
    18.  
    19.     public void Init(MyBehaviour prefabSource)
    20.     {
    21.         _prefabSource = prefabSource;
    22.     }
    23.  
    24.     public MyBehaviour PrefabSource
    25.     {
    26.         get { return _prefabSource; }
    27.     }
    28.  
    29. }
    30.  
    When instantiating from prefab:
    Code (csharp):
    1.  
    2. MyBehaviour prefab = *the prefab*;
    3. var instance = Instantiate(prefab, Vector3.zero, Quaternion.identity) as MyBehaviour;
    4. instance.Init(prefab);
    5.  
    And you can search like so:
    Code (csharp):
    1.  
    2. MyBehaviour target = *some MyBehaviour you want to find the siblings of*;
    3. var relatives = MyBehaviour.Pool.FindAll((c) => c.PrefabSource == target.PrefabSource);
    4.  
    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.
     
    Last edited: Jun 16, 2017