Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Having multiple cool down timers for different effects

Discussion in 'Scripting' started by Merrick20, Jun 13, 2018.

  1. Merrick20

    Merrick20

    Joined:
    Feb 20, 2015
    Posts:
    4
    Hi everyone,

    I'm making a game where I have A LOT of different effect that have cool down. (Items, spells, attacks, etc...).

    So It occurred to me that I could have an event based system where a class counts the cooldown for all of them, so I wouldn't have a lot of instantiated objects counting their own cooldown. So I thought about creating a class that receives an event "Start cool down" counts the time and sends an event call "Cool Down Finish"

    It should look something like this


    Code (CSharp):
    1. void Update () {
    2.  
    3.             //Count time      
    4.     }
    5.  
    6.         //This function will be triggered by an event from the effect that sends it's name along the time of cooldown
    7.         public void StartCooldown(float coolDownTime, string sender)
    8.         {
    9.             //Count time
    10.             FinishCooldown (sender);
    11.         }
    12.  
    13.         public void FinishCooldown(string receiver)
    14.         {
    15.             EventManager.BroadcastTimePassed(string receiver);
    16.             //The receiver will check if the name here is the same as it's own and act acordingly
    17.         }
    18.  
    The thing is that if two effects happens to have the cooldown activated at the same time, they would override on the counter. Right?

    How would you handle this?

    Do you think this method is way too complicated? How would you make a multiple cool down counter system.

    Thanks in advance, and sorry for my bad english.
     
  2. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    I think I would prefer a coroutine to running through an Update every frame. Also, you will need to store the cool downs in a collection. As you already said, the one you choose will have to cater for multiple things potentially having exactly the same cool-down time. That means if you use a Dictionary or a SortedList, the value would have to be lists.

    I have been playing around with this for little while now because it just seems that there must be a really simple few lines of code to do this. But I can't work it that way. :) So below is what I have come up with (note: this is untested code) but I feel sure that someone will know a better solution.
    Code (CSharp):
    1. public interface ICoolDownItem
    2. {
    3.     void CooledDown();
    4. }
    5.  
    6. public class CCoolDownManager : MonoBehaviour
    7. {
    8.     void AddItem(
    9.           ICoolDownItem item
    10.         , float timeToCool)
    11.     {
    12.         CItems addThis = new CItems(item, timeToCool);
    13.  
    14.         if(m_items.Count != 0 && addThis > m_items[0])
    15.         {   // Insert new item at the appropriate point.
    16.             m_items.Insert(m_items.FindIndex(pos => pos > addThis), addThis);
    17.         }
    18.         else
    19.         {   // New item is sooner than the first in the list.  Restart from beginning of the list.
    20.             m_items.Insert(0, addThis);
    21.             StopCoroutine(m_coolDownTimer);
    22.             m_coolDownTimer = StartCoroutine(NotifyAll());
    23.         }
    24.     }
    25.  
    26.     IEnumerator NotifyAll()
    27.     {
    28.         while(m_items.Count > 0)
    29.         {
    30.             var nextItem = m_items[0];
    31.             yield return new WaitForSeconds(nextItem.timeCooled - Time.time);
    32.             nextItem.thisItem.CooledDown();
    33.             m_items.RemoveAt(0);
    34.         }
    35.     }
    36.  
    37.     class CItems
    38.     {
    39.         public CItems(
    40.               ICoolDownItem item
    41.             , float timeToCool)
    42.         {
    43.             thisItem = item;
    44.             timeCooled = Time.time + timeToCool;
    45.         }
    46.  
    47.         public static bool operator <(CItems first, CItems second)
    48.         {
    49.             return first.timeCooled < second.timeCooled;
    50.         }
    51.  
    52.         public static bool operator >(CItems first, CItems second)
    53.         {
    54.             return first.timeCooled > second.timeCooled;
    55.         }
    56.  
    57.         readonly public ICoolDownItem thisItem;
    58.         readonly public float timeCooled;   // An absolute time.
    59.     }
    60.  
    61.     List<CItems> m_items = new List<CItems>();
    62.     Coroutine m_coolDownTimer;
    63. }
     
  3. Merrick20

    Merrick20

    Joined:
    Feb 20, 2015
    Posts:
    4
    Thanks for this! I have a few question about your code

    This is a good one. If I use a Coroutine, I could start it multiple times for every item right? Would this have any performance issue if I don't know... I start the Coroutine 10 times?

    Not if I use coroutines, right? As every cooldown item would start the Corotoutine separatedly... then I wouldn't have to start the timer for every cooldown item.

    Why did you implement the interface here? I don't see the need for it... you did gave a lot of ideas to think about and test. I don't know if anyone will come up with a better solution, but in the meantime I'll see what I can achieve by myself.

    Thanks again.
     
  4. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    You mean one coroutine per item? Yes, I believe this is possible. From Googling, there is a small garbage overhead, so you may want to be careful if you are generating a great many of them.

    Just simple polymorphism to allow for loose coupling. Any item that needs to cool down merely needs to inherit from this interface. Then it can be given to the CCoolDownManager via the
    AddItem
    method.