Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question how to create a system to measure the amount of Prefabs in game and limit that at a certain number

Discussion in 'Scripting' started by Elbowbread, Jun 26, 2023.

  1. Elbowbread

    Elbowbread

    Joined:
    Aug 4, 2020
    Posts:
    9
    I have a game where there are rockets falling from the sky. They are created by an Instantiate. Is there a way where I could track the amount that have been spawned in without using an int or a float. Those options would be difficult as I would have to reference those variables in many scripts.
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,769
    Instantiate returns the copy. You can register these copies into a collection in some overarching manager (such as a singleton or static class), and then the
    .Count
    /
    .Length
    property tells you how many there are in the scene.

    Naturally you need to remember to unregister them on their destruction. Probably the kind of thing where the manager could provide a factory pattern for supplying these prefabs.
     
    AngryProgrammer likes this.
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    I would just make a class like this one and put an instance on ever prefab!

    Code (csharp):
    1. using UnityEngine;
    2.  
    3. // @kurtdekker - put this on every prefab you want to count
    4. //
    5. // at any time you can read the Thingamadoodle.Count property,
    6. // which tells you how many there are enabled in scene.
    7.  
    8. public class Thingamadoodle : MonoBehaviour
    9. {
    10.     static int count;
    11.  
    12.     public static int Count {
    13.         get
    14.         {
    15.             return count;
    16.         }
    17.     }
    18.  
    19.     void OnEnable()
    20.     {
    21.         count++;
    22.     }
    23.  
    24.     void OnDisable()
    25.     {
    26.         count--;
    27.     }
    28.   }
     
  4. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,495
    Right, the simple solutions are often times the best ones. However I would probably go a little step further and use a ScriptableObject that has a single "count" variable as pluggable "bucket". That way you can create several separate buckets for various reasons. You can slap this script onto a prefab several times (or make it use a list of buckets), That way you could count all objects as well as type specific ones. Another great thing is whenever you need the current count, any other script could just hold a reference to that scriptable object and look up the current value.

    Code (CSharp):
    1. // ObjectBucketMember.cs
    2. public class ObjectBucketMember : MonoBehaviour
    3. {
    4.     public List<ObjectBucket> buckets;
    5.     void OnEnable()
    6.     {
    7.         foreach(var b in buckets)
    8.             b.Add(this);
    9.     }
    10.     void OnDisable()
    11.     {
    12.         foreach(var b in buckets)
    13.             b.Remove(this);
    14.     }
    15. }
    16.  
    17. // ObjectBucket.cs
    18. [CreateAssetMenu]
    19. public class ObjectBucket : ScriptableObject
    20. {
    21.     int m_Count = 0;
    22.     public int Count => m_Count;
    23.     public virtual void Add(ObjectBucketMember aMember) => m_Count++;
    24.     public virtual void Remove(ObjectBucketMember aMember) => m_Count--;
    25. }
    26.  
    As you can see I made the Add and Remove methods virtual. So you could create a subclass that also acts as a tracker or may provide add / remove events for other systems to listen to. This could be used in all sorts of ways.

    For example

    Code (CSharp):
    1. // ObjectBucketE.cs
    2. [CreateAssetMenu]
    3. public class ObjectBucketE : ObjectBucket
    4. {
    5.     public UnityEvent<ObjectBucketMember> OnObjectAdded;
    6.     public UnityEvent<ObjectBucketMember> OnObjectRemoved;
    7.     public override void Add(ObjectBucketMember aMember)
    8.     {
    9.         base.Add(aMember);
    10.         OnObjectAdded.Invoke(aMember);
    11.     }
    12.     public virtual void Remove(ObjectBucketMember aMember)
    13.     {
    14.         base.Remove(aMember);
    15.         OnObjectRemoved.Invoke(aMember);
    16.     }
    17. }
    18.  
    ps: You may want to add method to "reset" a bucket any maybe include some safeguards. However usually there should be no possible scenarios where the bucket goes out of sync with the actual objects enabled.
     
    Kurt-Dekker likes this.
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    That is a far superior approach Bunny... I went de-minimus on my solution!