Sheduler convenient function call routine, my conditioning system

The tool was originally written to help you develop simple casual games in Unity, at least there it was quite useful.



But I think I will use it in other projects, and not only in the unit.



And, perhaps, it will be useful to you too!



Source link






So, what is he for?



Imagine a situation: you wrote a simple casual game in which you need to tap the screen ten times to complete one level, and sent it to your boss (or a spoiled customer) for preview.



Followed by tasks one by one:



  1. Let's add ads at the finish every 1.5 minutes?
  2. And let's after it somewhere at the start there will be a window: "Buy a premium so that there is no advertising"?
  3. Something this window presses sharply, but let it be after the advertisement, but only when the player pressed start and passed two levels?
  4. And come on at 10, 20, 30 levels there will be a "share with friends" window?
  5. And come on from level 10 every 2 levels will there be a window "Rate us!"?
  6. And a bunch more!


Even after going through a cruel execution and endless blocking of your child, having carried out the hundredth check of the location of the windows, sooner or later you will face such a problem: windows tied to the timer can overlap the windows tied to the levels themselves!



It becomes more and more difficult to redo this - after all, conditional checks are already up to the neck, plus your colleague could have added their own windows with completely unreadable code! What to do?






Task



Call the window at a certain moment (for example, pressing a button), and only if all the specified conditions are met (time has passed, the required point has been reached, etc.)






Decision



For this, I made a Condition class, here are its main fields:



  1. timer int setedSeconds
  2. skips int setedSkips
  3. List &ltint&gt checkPoints


, , . .



, , . , , , NextSkip(). = 0, ,

. - , START() β€” .

, StartTimer() ResetSkips(). , IsReady()

true , (value > 0), START() .



: β€” ( ) setedSeconds, , , !



IsReady() , START() , , .



    public Condition myCondition;

    void Start(){
        myCondition = new Condition("");
        myCondition.setedSeconds = 120; // 2 
        myCondition.setedSkips = 5;
        myCondition.START(); //      
    }

    //    
    public void FinishRound(){
        myCondition.NextSkip(); //  ,  

        if (myCondition.IsReady())
        {
            //    ,      ...

            myCondition.START(); //   START()    . ,     IsReady == true
        }
    }


, , β€” List &ltint&gt checkPoints. - , , , ., , - . , : , ( , ). , Sheduler , , β€” .



    public Condition myCondition;

    void Start(){
        myCondition = new Condition("",new List<int> { 1, 2, 5 }); //    ,   
        myCondition.setedSeconds = 120;
        myCondition.setedSkips = 5;
        myCondition.START();
    }

    public void FinishRound(){
        myCondition.NextSkip(); 

        if (myCondition.IsReady() || myCondition.HasCheckPoint(currentLevel)) //          
        {
            //    ,      ...

            myCondition.START();
        }
    }


, , =) AutoInvoke(Action CallBack, int checkPoint = 0) , NextSkip() START() , START() .



    public Condition myCondition;

    void Start(){
        myCondition = new Condition("",new List<int> { 1, 2, 5 });
        myCondition.setedSeconds = 120;
        myCondition.setedSkips = 5;
        myCondition.START(); 
    }

    public void FinishRound(){

        myCondition.AutoInvoke(() => Debug.Log("hello World"), currentLevel); 
        //   currentLevel,                                                                                
    }




One condition object will help you quickly provide a set of necessary conditions for the operation of any one function !!!



If your task in the technical assignment is a little more difficult than a simple call, for example, a call every other time or after some time, it will already be useful to resort to condition, because this is abstraction and readability - you just have to start it and check its readiness.




I've added useful unit attributes to the condition fields for easy initialization through the inspector!





The main thing is flexibility, and if suddenly someone comes up with their own functionality that should not conflict with your condition, you just need to create a general planner ...






next Task



Flexibly add different windows (function call) from different places in the program, keep in sync and avoid overlay conflicts!






Solution:



And now we got to the main Sheduler class , our condition planner!

It is better to initialize an object of this class as early as possible. Specifically in a unit, it is better that the object is DontDestroyOnLoad .



If you look inside Sheduler , you can see the following fields:



  1. Current checkpoint int currentheckPoint
  2. A collection of all added conditions and their behavior Dictionary & ltCondition, Action & gt ConditionHandlers - so that the

    planner knows what role the finished condition should play
  3. Dictionary &ltint,Condition&gt CheckPoints β€” Sheduler, Dictionary, , . .
  4. Queue &ltCondition&gt WaitingConditions ,



Sheduler stores the behavior of each condition and works according to this class, it is set at the time of adding the condition public void Add (Condition newCondition, Action CallBack) , where the arguments have a required delegate. The method itself reads the condition name and throws an exception if it is empty or has already been added - this is needed in case for some reason you need to take a condition from the schedule named List & ltCondition & gt GetConditions (params string [] conditionName) . Also, the add method Add () Immediately runs Start () of the added condition. This is useful if you run Start ()the added condition will be forgotten by which of the developers, and also in order to avoid the constant throwing out of this function from Sheduler. If you need a different place to start the condition, you just work with the condition as before, you can always change its counters. This is the beauty of Sheduler - it handles where the condition is ready, and where it has changed its readiness, and makes this calculation at the time of calling its main method Condition Invoke (params Condition [] badges) . In the arguments, you can specify some badges, that is, those conditions that should work exclusively, and those whose turn came, however, they did not appear in the list of badges, then they will not work. But, if you do not specify anything, then, as expected, everyone has the right to call at the peak of the queue!



Be sure to think of where the checkpoints will be counted for Sheduler NextCheckPoint () , for example, at the method, at the finish or at the start of the round, a

complete example of what is required to work with Sheduler:



    public Condition OfferBuyVip;
    public Condition OfferToShareWithFriends;
    public Condition OfferToVisitSite;

    public Sheduler OfferSheduler;

    public void Start(){
        OfferSheduler = new Sheduler(currentLevel); //      

        /*
         *         
         */

        OfferSheduler.Add(OfferBuyVip, () => Debug.Log("     VIP"));
        OfferSheduler.Add(OfferToShareWithFriends, () => Debug.Log("    "));
        OfferSheduler.Add(OfferToVisitSite, () => Debug.Log("     ,   "));
    }

    public void FinishRound(){
        OfferSheduler.NextCheckPoint(currentLevel); //  ,      
        OfferSheduler.Invoke(OfferBuyVip, OfferToShareWithFriends) //      ,    
    }

    public void StartRound(){
        OfferSheduler.Invoke(OfferToVisitSite); //     
        //   ,   ,           Sheduler
    }





This is how we ensured that the three functions of our conditions are called in different places, while they respect each other and do not crawl out everything in a row, but respect the queue (like a modern digital queue for coupons), and the user, quickly jumping from the finish line to the start of the game , will not strain from the number of proposals. With Sheduler, it maintains a clear harmony of simplicity and flexibility, because with Sheduler and the delegate passed to it via the Add (Condition newCondition, Action CallBack) method , it is possible to implement any connection between windows.



For example, when invoking an advertising banner, an offer to purchase Premium without advertising appears after two levels:



    void Start(){
        OfferSheduler = new Sheduler(currentLevel);

        callAddBanner = new Condition(" ");
        callAddBanner.setedSeconds = 80; //    80 
        OfferBuyVip = new Condition("  VIP  ");

        OfferSheduler.Add(callAddBanner, 
            delegate()
            {
                Debug.Log(" ");
                OfferBuyVip.setedSkips = 2; //   
                OfferBuyVip.START();  // 
            }
           );
        OfferSheduler.Add(OfferBuyVip,
            delegate ()
            {
                Debug.Log("     VIP");
                OfferBuyVip.setedSkips = 0; //  !  
 //,  
            }
           );
        }
        
        void Finish(){
            OfferSheduler.NextCheckPoint(currentLevel); //    
// 
            OfferSheduler.Invoke(); //     
//    
        }


Just like that, now every 80 seconds a non-distracting advertisement will be triggered (after all, it is called not during an important round, but at the finish line) and also invoke an offer to buy an advertisement when it is convenient for you! And the best thing is that now any developer in the team can add their proposals to Sheduler, and Sheduler will distribute everything.



All Articles