Como funcionam as habilidades em robôs de guerra





Olá! Meu nome é Vladimir Popov e sou um desenvolvedor cliente do projeto War Robots.



War Robots existe há vários anos: durante este tempo, dezenas de novos mechs surgiram no jogo. E, claro, nenhum deles seria único sem seu próprio conjunto de habilidades.



Contarei neste artigo como funciona o sistema de habilidades do nosso jogo e como evoluiu, de forma simples e sem nenhum detalhe técnico.



Primeiro, vamos mergulhar na história e olhar para a implementação antiga - agora ela não é mais usada no projeto.



As antigas habilidades eram muito triviais: eles tinham um componente que estava pendurado no robô. Foi uma construção monolítica em que o programador descreveu completamente como a habilidade funciona: seu fluxo, como e com o que ela interage. Toda a lógica é descrita dentro de um componente, que o designer do jogo poderia simplesmente pendurar no robô e ajustar os parâmetros. Não havia como alterar as habilidades de fluxo - os designers de jogos só podiam alterar os parâmetros e tempos.



A habilidade antiga só poderia existir em dois estados: ativo e inativo. Cada estado pode ter sua própria ação atribuída.







Considere o exemplo da habilidade Jammer. Ela já foi, por exemplo, o robô Stalker. Ela trabalhou da seguinte maneira:



  1. Se a habilidade estiver ativa, a animação é reproduzida e o robô entra no estado Jammer. Nesse estado, o robô não pode ser direcionado.
  2. Se a habilidade estiver inativa, nada acontece.
  3. Quando você tenta ativar a habilidade, é verificado se mais de n segundos se passaram desde a última ativação.
  4. A desativação ocorre automaticamente após m segundos.


Por muito tempo, essa funcionalidade foi suficiente para nós. Mas com o tempo, tudo mudou: tanto os designers de jogos quanto os programadores não estavam mais satisfeitos com essa abordagem. Era difícil para os programadores manter essas habilidades, porque o código se tornava monstruoso - com uma cadeia de herança muito longa, onde cada situação tinha que ser descrita. Os designers de jogos não tinham flexibilidade de sistema. Ou seja, para o bem de qualquer mudança em uma habilidade, eles tiveram que solicitar a revisão dos programadores, mesmo se exatamente a mesma funcionalidade existisse na habilidade vizinha.



Então percebemos que precisávamos mudar algo. E eles desenvolveram um novo sistema. Nele, cada habilidade passou a ser representada como um conjunto de diversos objetos relacionados. A função foi dividida em estados, habilidades e componentes de estados.



Como funciona?



Qualquer habilidade tem um mestre . Este é seu objeto central. Ele conecta o resto dos objetos de habilidade com o mundo externo e vice-versa. E ele também toma todas as decisões principais. Pode haver qualquer número de



estados . Em essência, o estado aqui não é muito diferente do estado "ativo" / "inativo" da versão antiga. Mas agora pode haver qualquer número deles, e seu propósito se tornou mais abstrato. Apenas um estado pode estar ativo por vez.



A principal inovação em relação ao antigo sistema eram os componentes . O componente descreve algum tipo de ação. Cada estado pode ter qualquer número de componentes.







Como funcionam as novas habilidades?



A habilidade só pode estar em um dos estados de cada vez. O mestre está empenhado em trocá-los. Os componentes que se vinculam ao estado reagem à ativação / desativação do estado e, dependendo disso, podem começar a executar uma ação ou parar de executá-la.



Todos os objetos agora são personalizáveis. O designer do jogo pode misturar estados e componentes entre si de qualquer maneira e, assim, obter uma nova capacidade dos blocos pré-instalados. Os programadores agora são necessários apenas para criar um novo componente ou estado, o que facilita muito a escrita de código. Agora eles trabalham com pequenas entidades, descrevem alguns elementos simples e não montam a habilidade sozinhos - os designers de jogos começaram a fazer isso.



O fluxo ficou assim:



  1. O mestre ativa o primeiro estado;
  2. ;
  3. ;
  4. ;
  5. ;
  6. ;
  7. .


Posteriormente, este procedimento é repetido várias vezes. Para facilidade de uso, um estado não é apenas um contêiner para componentes, mas também determina quando alternar para outro estado e pede ao mestre para alternar.



Com o tempo, isso se tornou insuficiente para nós, e o esquema da habilidade foi transformado da seguinte forma:







Mestre, estado e componentes permaneceram em seus lugares, mas novos elementos foram adicionados a eles.



A primeira coisa que chama sua atenção é que adicionamos condições a cada estado e componente. Para os estados, eles definem requisitos adicionais para deixar o estado. Para componentes, eles determinam se o componente pode executar sua ação.



Um contêiner de cargas (cargas) contém cargas, recarrega-as, interrompe a recarga quando necessário e fornece taxas aos estados para uso.



O cronômetro é usado quando vários estados devem ter um tempo de execução comum, mas seu próprio tempo de execução não está definido.



É importante notar que todos os objetos de habilidade são opcionais. Tecnicamente, apenas o mestre e um estado são suficientes para a capacidade de trabalho.



Não há tantas habilidades que são completamente montadas sem o envolvimento dos programadores, mas o desenvolvimento em geral tornou-se visivelmente mais barato, porque os programadores agora escrevem coisas muito pequenas: por exemplo, um novo estado ou dois componentes, o resto é reutilizado.



Vamos resumir quais são as partes constituintes das habilidades que temos e quais são elas:



  • O mestre atua como uma máquina de estado. Ele fornece estados e componentes com informações sobre o mundo, e o mundo - informações sobre uma habilidade. O mestre serve como um elo entre os estados, componentes e peças de serviço de uma habilidade: cobranças e temporizadores externos.
  • O estado escuta os comandos de ativação e desativação do mestre e, consequentemente, ativa e desativa os componentes, e também pede ao mestre para mudar para outro estado. O estado decide quando ele precisa mudar para o próximo. Para fazer isso, ele usa sua condição interna: se o jogador clicou no botão de habilidade, se um certo tempo passou desde que o estado foi ativado, etc. - e condições externas vinculadas ao estado.
  • : . : , , .
  • , , . . , . , . — , .
  • Um contêiner de cargas contém cargas, as recarrega, interrompe a recarga quando necessário e concede encargos aos estados. É usado em habilidades de carga múltipla quando você precisa dar ao jogador a oportunidade de usá-lo várias vezes, mas não mais do que n vezes consecutivas.
  • O cronômetro é usado quando vários estados têm uma duração comum, mas não se sabe por quanto tempo cada um deles é válido. Qualquer estado pode iniciar um cronômetro de n segundos. Todos os estados interessados ​​se inscrevem no evento sobre o fim do cronômetro e fazem algo quando ele termina.


Agora vamos voltar ao diagrama de habilidade. Como ela começou a agir?



  1. No início do jogo, o mestre escolhe o primeiro estado e o ativa;
  2. O estado ativa todos os seus componentes;
  3. ;
  4. ;
  5. , ;
  6. ;
  7. .


Os estados podem usar cobranças como uma condição de transição adicional. Se essa transição ocorrer, o número de cobranças diminui. Além disso, os estados podem usar um cronômetro comum. Neste caso, o tempo total de sua execução será determinado pelo cronômetro, e cada estado individualmente pode durar a qualquer momento.



Não criamos algo completamente novo para a IU. Está organizado assim conosco.



O mestre tem sua própria IU. Ele define alguns elementos que sempre devem estar na IU e não dependem de qual estado está ativo no momento.



Cada estadohá alguns na IU. O estado da IU é exibido apenas quando seu estado está ativo. Ele recebe dados sobre seu estado e pode exibi-los de uma forma ou de outra. Por exemplo, os estados de duração geralmente têm uma barra e um texto em sua IU que representa o tempo restante.



No caso em que o estado está esperando por um comando externo para continuar a habilidade, sua IU exibe um botão. E pressioná-lo envia o comando para o estado.







Agora, vamos examinar o trabalho de habilidades usando exemplos específicos. Vamos começar com um robô chamado Inquisitor.



Temos quatro estados que mudam um após o outro. Acima dos estados, você pode ver sua exibição na IU. Em dois deles, você pode ver os componentes que se referem a eles. Os outros dois estados simplesmente não têm componentes.



Fluxo de trabalho da habilidade:



  1. WaitForClick. .
  2. , . WaitForGrounded.
  3. . , . , , Jammer, .
  4. .
  5. : Sound Jammer, Shake, n.
  6. Duration, n , .
  7. Duration, : .
  8. Após a conclusão, a habilidade retorna ao primeiro estado.






Outro exemplo é o Phantom. Muito acontece aqui de forma semelhante ao Inquisitor, mas ainda existem algumas nuances:



  1. Começamos com WaitForClick.
  2. Em seguida, a duração, na qual o teletransportador é definido, as estatísticas da mudança de mecanismo, som e animação são reproduzidos.
  3. Depois disso - DurationOrClick, em que as estatísticas de pele são alteradas, a animação e o FX são reproduzidos.
  4. Se for feito um clique, passamos para outra Duration, na qual o pelo é teletransportado, as estatísticas mudam, a animação, FX e sons são reproduzidos.
  5. Após este estado ou após o término do tempo DurationOrClick, vamos para Duration.


A principal diferença é que os estados ramificados aparecem aqui. DurationOrClick vai para o estado a se o tempo especificado passou, ou para o estado b , se o jogador teve tempo para clicar no botão de habilidade antes.







Assim, parece que nosso sistema evoluiu de simples para complexo, mas simplificou a vida de programadores e designers de jogos. A ajuda do primeiro agora é mais necessária ao adicionar pequenos componentes, enquanto o último recebeu maior autonomia e pode agora montar de forma independente novas habilidades a partir de estados e componentes existentes. Ao mesmo tempo, os jogadores também recebiam um lucro na forma de habilidades mais diversas e complexas dos mechs.



All Articles