Centralize your Updates using Scriptable objects!

If you have 100’s of Mono behaviour scripts and if you want all of these scripts to run at the same interval
One of the solutions you would do so is to add the following code to all the Mono behaviour scripts.

void Update
{
    time = time + Time.deltaTime;
    if(time>Interval)
    {
        // your code
        time = 0;
    }
}

where you maintain the interval as a static variable in the master data or in a scriptable object and give reference to this in all the scripts to centralize your updates and repeat this code in every script
I do propose another way to do this using scriptable objects where you only need to use the above script once
Let’s analyze what behavior should a mono behaviour script that updates should have
1)It should have an update function.
2)It should have a fixed update function.
3)It should have a late update function.
It’s not like all mono behaviour scripts need all 3 types of updates
We also need some variable that tells which update function the script needs
So based on this lets make a interface called IUpdateable

 public interface IUpdateable
    {
        public int UpdateMask
        {
            get;
        }
        void update();
        void fixedUpdate();
        void lateUpdate();
    }

To check what types of update function needs to be implemented, we are gonna use a property called
update mask where
if first bit is on it means it needs update
if second bit is on it means it needs fixedupdate
if third bit is on it means it needs lateupdate
Based on above data we set the respective bits to true
Here in the code we check if the derived class overrides the function of parent class and set those overrides function to true
Now Let’s make the abstract class that implements IUpdateable and inherits from mono behaviour

 public abstract class UpdateableMonoBehaviour : MonoBehaviour, IUpdateable
    {
        #region Fields
        [SerializeField] protected UpdateV2 updater;
        #endregion Fields
        #region Properties
        public virtual int UpdateMask
        {
            get
            {
                int _updateMask = 0;
                if(this.GetType().GetMethod("update").DeclaringType == this.GetType())
                    _updateMask = _updateMask.setBitOn(0);
                if (this.GetType().GetMethod("fixedUpdate").DeclaringType == this.GetType())
                    _updateMask = _updateMask.setBitOn(1);
                if (this.GetType().GetMethod("lateUpdate").DeclaringType == this.GetType())
                    _updateMask = _updateMask.setBitOn(2);
                return _updateMask;
            }
        }
        #endregion Properties
        #region Methods
        protected void OnEnable() {
            if(updater!=null)
                updater.AddUpdateable(this);
        }
        protected void OnDisable() {
            if (updater != null)
                updater.RemoveUpdateable(this);
        }
        public virtual void finalUpdate()
        {
          
        }

        public virtual void fixedUpdate()
        {
          
        }

        public virtual void lateUpdate()
        {
          
        }
      
        public virtual void update()
        {

        }
        #endregion Methods
        #region Helpers
        #endregion Helpers
    }

We also add onEnable and onDisable functions to subscribe/unsubscribe itself to scriptable object container
We also added a virtual update method for each type if we need a specific update type we override that update function
Now let’s make the scriptable object to store these objects

[CreateAssetMenu(menuName = "MyScriptable/UpdateV2")]
    public class UpdateV2 : ScriptableObject
    {
        #region fields
        private readonly List<IUpdateable> _updateList = new List<IUpdateable>();
        private readonly List<IUpdateable> _fixedUpdateList = new List<IUpdateable>();
        private readonly List<IUpdateable> _lateUpdateList = new List<IUpdateable>();
        [SerializeField] float _updateTime = 1000;
        [SerializeField] float _fixedTime = 1000;
        [SerializeField] float _lateTime = 1000;
        #endregion fields

        #region properties
        public float UpdateTime { get { return _updateTime; }}
        public float FixedTime { get { return _fixedTime; }}
        public float LateTime { get { return _lateTime; }}
        #endregion properties
        #region methods
        public void AddUpdateable(IUpdateable updateable)
        {
            if(updateable.UpdateMask.checkIfBitIsOn(0))
            {
                if(!_updateList.Contains(updateable))
                    _updateList.Add(updateable);
            }
            if(updateable.UpdateMask.checkIfBitIsOn(1))
            {
                if(!_fixedUpdateList.Contains(updateable))
                    _fixedUpdateList.Add(updateable);
            }
            if(updateable.UpdateMask.checkIfBitIsOn(2))
            {
                if(!_lateUpdateList.Contains(updateable))
                    _lateUpdateList.Add(updateable);
            }
        }
        public void RemoveUpdateable(IUpdateable updateable)
        {
            if (updateable.UpdateMask.checkIfBitIsOn(0))
            {
                if (_updateList.Contains(updateable))
                    _updateList.Remove(updateable);
            }
            if (updateable.UpdateMask.checkIfBitIsOn(1))
            {
                if (_fixedUpdateList.Contains(updateable))
                    _fixedUpdateList.Remove(updateable);
            }
            if (updateable.UpdateMask.checkIfBitIsOn(2))
            {
                if (_lateUpdateList.Contains(updateable))
                    _lateUpdateList.Remove(updateable);
            }
        }
        public void update()
        {
            if(_updateList.Count!=0)
            for (int i = _updateList.Count - 1; i >= 0; i--) { _updateList[i].update(); }
        }
        public void fixedUpdate()
        {
            if (_fixedUpdateList.Count != 0)
            {
                for (int i = _updateList.Count - 1; i >= 0; i--) { _fixedUpdateList[i].update(); }
            }
        }
        public void lateUpdate()
        {
            if (_lateUpdateList.Count != 0)
            for (int i = _updateList.Count - 1; i >= 0; i--) { _lateUpdateList[i].update(); }
        }
        #endregion methods
    }

here we just make a data container to store all the IUpdateable objects.We create 3 lists for an update, a fixed update, a late update respectively.and a function to add and remove IUpdateable objects . In this functions we check if a specific bit is on or not and add them to specific lists.We also declare at what interval should it update for each update functions. We also define 3 functions to loop through each updates

Lets create a MonoBehaviour script to update our update functions

public class updaterScript : MonoBehaviour
{
    // Start is called before the first frame update
    [SerializeField] UpdateV2 updater;
    float time = 0;
    [SerializeField]float updateTime = 1000;
    [SerializeField]float fixedTime = 1000;
    [SerializeField]float lateTime = 1000;
    void Start()
    {
       
    }
    // Update is called once per frame
    void Update()
    {
        time = time + Time.deltaTime;
        if(time>updater.UpdateTime)
        {
            if(updater != null)
                updater.update();

            time = 0;
        }
    }
    void FixedUpdate()
    {
        time = time + Time.deltaTime;
        if (time > updater.FixedTime)
        {
            if (updater != null)
                updater.fixedUpdate();
            time = 0;
        }
    }
    private void LateUpdate()
    {
        time = time + Time.deltaTime;
        if (time > updater.LateTime)
        {
            if (updater != null)
                updater.lateUpdate();
            time = 0;
        }
    }

Lets make script that inherits from UpdateableMonoBehaviour that meows every 1000 frames

public class Meower : UpdateableMonoBehaviour
{  
    private new void OnEnable()
    {
        base.OnEnable();
        Debug.Log("lol");
    }
    // Update is called once per frame
    public override void update()
    {
        Debug.Log("meow");
       
    }
}

I am still a beginner learning new things so if I have made any mistakes or any improvements or new way of doing it . Please point it out
That’s it for today
May the code be with you
kuro out

Reference
1 - Efficient Updating - Take Control of Update Functions

This is an interesting approach for centralizing update functions in Unity, which can help reduce code duplication and simplify maintenance.

The idea is to define an interface IUpdateable with methods for update, fixed update, and late update, and a property UpdateMask that indicates which of these methods should be implemented. Then, an abstract class UpdateableMonoBehaviour is created, which inherits from MonoBehaviour and implements IUpdateable. UpdateableMonoBehaviour subscribes and unsubscribes itself to a ScriptableObject called UpdateV2, which stores a list of IUpdateable objects, organized by update type (update, fixed update, or late update).

The UpdateV2 scriptable object has methods to add or remove IUpdateable objects to the appropriate lists, depending on their UpdateMask, and properties to store the interval for each update type. The UpdateableMonoBehaviour class overrides the update methods for each update type, allowing derived classes to implement specific behavior for each one.

Overall, this approach provides a flexible way to organize update functions in Unity, and can help reduce code duplication and improve maintenance. However, it may add some complexity to the code, and care must be taken to ensure that all IUpdateable objects are added and removed correctly from the UpdateV2 list.