Sheduler conveniente rotina de funções de chamada, meu sistema de condicionamento

A ferramenta foi originalmente escrita para ajudá-lo a desenvolver jogos casuais simples no Unity, pelo menos aí foi bastante útil.



Mas acho que vou usar em outros projetos, e não só na unidade.



E, talvez, seja útil para você também!



Link da fonte






Então, para que serve ele?



Imagine uma situação: você escreveu um jogo casual simples no qual precisa tocar na tela dez vezes para completar um nível e o enviou para seu chefe (ou um cliente estragado) para visualização.



Seguido por tarefas uma a uma:



  1. Vamos adicionar anúncios no final a cada 1,5 minutos?
  2. E vamos depois disso em algum lugar no início haverá uma janela: "Compre um prêmio para que não haja publicidade"?
  3. Algo que esta janela pressiona bruscamente, mas que seja depois do anúncio, mas apenas quando o jogador pressionou iniciar e passou dois níveis?
  4. E vamos lá em 10, 20, 30 níveis, haverá uma janela "compartilhar com amigos"?
  5. E a partir do nível 10, a cada 2 níveis, haverá uma janela "Avalie-nos!"?
  6. E mais um monte!


Mesmo depois de passar por uma execução brutal e bloqueio interminável do seu filho, tendo realizado a centésima verificação da localização das janelas, mais cedo ou mais tarde você se deparará com esse problema: as janelas amarradas ao cronômetro podem se sobrepor às janelas amarradas aos próprios níveis!



Fica cada vez mais difícil refazer isso - afinal, as verificações condicionais já estão pesando no pescoço, e seu colega poderia adicionar suas próprias janelas com um código completamente ilegível! O que fazer?






Tarefa



Chame a janela em um determinado momento (por exemplo, pressionando um botão), e somente se todas as condições especificadas forem atendidas (o tempo passou, o ponto necessário foi alcançado, etc.)






Decisão



Para isso, criei uma classe Condition, aqui estão seus campos principais:



  1. timer int setedSeconds
  2. pula setedSkips int
  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,                                                                                
    }




Um objeto de condição o ajudará a fornecer rapidamente um conjunto de condições necessárias para a operação de qualquer função !!!



Se a sua tarefa no TK é um pouco mais difícil do que uma simples ligação, por exemplo, uma ligação alternada ou após algum tempo, já será útil recorrer à condição, porque isso é abstração e legibilidade - basta iniciá-la e verificar se está pronta.




Eu adicionei atributos de unidade úteis aos campos de condição para facilitar a inicialização através do inspetor!





O principal é a flexibilidade, e se de repente alguém vier com uma funcionalidade própria que não deve entrar em conflito com a sua condição, você só precisa criar um planejador geral ...






próxima tarefa



Adicione de forma flexível diferentes janelas (chamada de função) de diferentes locais no programa, mantenha a sincronização e evite conflitos de sobreposição!






Solução:



E agora chegamos à aula principal de Sheduler, nosso planejador de condição!

É melhor inicializar um objeto desta classe o mais cedo possível. Especificamente em uma unidade, é melhor que o objeto seja DontDestroyOnLoad .



Se você olhar dentro do Sheduler , verá os seguintes campos:



  1. Ponto de verificação atual int currentheckPoint
  2. Uma coleção de todas as condições adicionadas e seu comportamento Dictionary & ltCondition, Action & gt ConditionHandlers - para que o

    planejador saiba qual papel a condição finalizada deve desempenhar
  3. Dictionary &ltint,Condition&gt CheckPoints — Sheduler, Dictionary, , . .
  4. Queue &ltCondition&gt WaitingConditions ,



O Sheduler armazena o comportamento de cada condição e é acionado de acordo com esta classe, é definido no momento de adicionar a condição public void Add (Condition newCondition, Action CallBack) , onde há um delegado obrigatório nos argumentos. O próprio método lê o nome da condição e lança uma exceção se estiver vazio ou já tiver sido adicionado - isso é necessário caso por algum motivo você precise obter uma condição da programação chamada List & ltCondition & gt GetConditions (params string [] conditionName) . Além disso, o método add Add () executa imediatamente Start () da condição adicionada. Isso é útil se você executar Start ()a condição adicionada será esquecida por qual dos desenvolvedores, e também para evitar o constante descarte desta função do Sheduler. Se precisar de um local diferente para iniciar a condição, basta trabalhar com a condição como antes, você sempre pode alterar seus contadores. Esta é a beleza do Sheduler - ele trata onde a condição está pronta e onde mudou sua prontidão, e faz esse cálculo no momento de chamar seu método principal Condition Invoke (emblemas params Condition []) . Nos argumentos, pode-se especificar alguns emblemas, ou seja, aquelas condições que deveriam funcionar exclusivamente, e aquelas cuja vez chegou, porém, não constavam na lista de emblemas, então não funcionarão. Mas, se você não especificar nada, então, como esperado, todos têm o direito de ligar no pico da fila!



Certifique-se de pensar onde os pontos de verificação serão contados para Sheduler NextCheckPoint () , por exemplo, no método, no final ou no início da rodada, um

exemplo completo do que é necessário para trabalhar com o 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
    }





É assim que garantimos que as três funções de nossas condições sejam chamadas em lugares diferentes, enquanto se respeitam e não rastejam tudo em sequência, mas respeitam a fila (como uma fila digital moderna de cupons), e o usuário, saltando rapidamente da linha de chegada para o início do jogo , não se estenderá ao número de propostas. Com o Sheduler, ele mantém uma harmonia clara de simplicidade e flexibilidade, pois com o Sheduler e um delegado transmitido a ele através do método Add (Condition newCondition, Action CallBack) , é possível implementar qualquer conexão entre janelas.



Por exemplo, ao invocar um banner publicitário, uma oferta de compra Premium sem publicidade aparece após dois níveis:



    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(); //     
//    
        }


Assim mesmo, agora a cada 80 segundos será disparado um anúncio que não distraia (afinal, ele não é anunciado durante uma rodada importante, mas na linha de chegada) e também invoca uma oferta de compra de um anúncio quando for conveniente para você! E a melhor coisa é que agora qualquer desenvolvedor da equipe pode adicionar suas propostas ao Sheduler, e o Sheduler distribuirá tudo.



All Articles