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:
- Vamos adicionar anúncios no final a cada 1,5 minutos?
- E vamos depois disso em algum lugar no início haverá uma janela: "Compre um prêmio para que não haja publicidade"?
- 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?
- E vamos lá em 10, 20, 30 níveis, haverá uma janela "compartilhar com amigos"?
- E a partir do nível 10, a cada 2 níveis, haverá uma janela "Avalie-nos!"?
- 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:
- timer int setedSeconds
- pula setedSkips int
- List <int> 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 <int> 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:
- Ponto de verificação atual int currentheckPoint
- 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 - Dictionary <int,Condition> CheckPoints — Sheduler, Dictionary, , . .
- Queue <Condition> 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.