Trabalhe com status de personagem. Experiências Unity

Ao desenvolver um jogo no Unity, deparei-me com uma tarefa interessante: como criar um tempo extensível de ação com efeitos negativos ou positivos em um personagem.

Em resumo, tenho um personagem ao qual certos efeitos podem ser aplicados, como enfraquecimento, ganho, aumento de velocidade, diminuição de velocidade e outros. Para notificar o jogador sobre o efeito de um efeito, o jogo fornece uma linha de status.

As primeiras versões desta linha continham ícones escuros de todos os status e, quando o efeito ocorreu, o desejado acendeu.

imagem

Cada status tinha corutin, que cancelou o efeito após um determinado período de tempo.
Há um sinal menos importante nessa decisão. Se, como resultado de certos eventos no jogo, o mesmo efeito for aplicado ao personagem após um tempo menor que a duração do efeito similar anterior, poderá haver duas versões dos eventos.

  1. Muito errado: um segundo corutin é lançado em paralelo com o primeiro. Quando o primeiro é concluído, ele retorna aos seus valores originais, ou seja, o efeito é removido antes que a segunda corotina termine o trabalho.

    imagem
  2. Também errado, mas em alguns casos aceitável: Cancele a primeira corotina e execute a segunda. Nesse caso, a duração do efeito será igual à duração do primeiro efeito até que a corotina seja cancelada + a duração da segunda corotina.

    imagem

Ambos os métodos são inaceitáveis ​​para minha tarefa, pois preciso estender a duração do efeito, para obter a soma da duração de cada efeito, independentemente de quantas vezes o efeito seja aplicado.

Se o personagem pisar nos espinhos, sua perna está danificada condicionalmente e ele não pode continuar se movendo na mesma velocidade. Digamos que a velocidade diminua em 5 segundos. Se após 3 segundos o personagem pisar em outros picos, a velocidade deverá ser reduzida em mais 5 segundos. Ou seja, 3 segundos se passaram, 2 + 5 segundos restantes dos novos picos. A duração do efeito deve durar mais 7 segundos a partir do momento do ataque nos segundos picos (10 no total).

E com a ajuda da corotina, não encontrei uma solução para o problema, pois é impossível descobrir o tempo restante até a conclusão da corotina para adicioná-lo à nova corotina.

A solução que encontrei para esse problema é usar um dicionário. Sua vantagem sobre a lista é que o dicionário tem uma chave e um valor, o que significa que eu posso acessar qualquer valor por chave. Além disso, esta solução permite que você se livre dos ícones de status permanentes na linha e inclua os necessários, conforme necessário, e defina-os nas posições da linha na ordem em que ocorrem.

Dictionary<string, float> statusTime = new Dictionary<string, float>(); 

O dicionário nesse caso é mais vantajoso do que usar a fila, pois ela funciona de acordo com os princípios de Primeiro a entrar, mas a duração dos efeitos é diferente, o que significa que o status que precisa ser removido pode não ser o primeiro na fila.

Para isso, adicionei três métodos.

Addstatus

Adicione o status desejado ao dicionário, se esse status já existir no dicionário e adicione a duração. Se não houver status, calculamos o horário final e o adicionamos ao dicionário.

 private void AddStatus(string status, float duration) { if (statusTime.ContainsKey(status)) { statusTime[status] += duration; } else { float endTime = Time.timeSinceLevelLoad + duration; statusTime.Add(status, endTime); } } 

RemoveStatus

Excluímos o status do dicionário, restauramos os valores originais.

 private void RemoveStatus(string status) { statusTime.Remove(status); RestoreStats(status); } 

Status de verificação

Se houver status no dicionário, verificaremos se o tempo deles expirou.

Se expirado, exclua o status do dicionário. Como alterar o dicionário no loop torna impossível sincronizar os valores do dicionário, jogamos as chaves do dicionário aqui em uma lista comum.

 private void CheckStatuses() { if (statusTime.Count > 0) { float currTime = Time.timeSinceLevelLoad; List<string> statuses = new List<string>(statusTime.Keys);  foreach (string stat in statuses) { if (currTime > statusTime[stat]) { RemoveStatus(stat); } } } } 

Das vantagens, obviamente, este é um tempo de efeito extensível. Ou seja, o problema está resolvido.
Mas um sinal menos significativo está presente aqui. A verificação de status é feita em Atualizar todos os quadros. No meu jogo, existem no máximo 4 jogadores, o que significa que esse método será executado a cada quadro 4 vezes em paralelo. Com 4 caracteres, acho que isso não é crítico, mas tenho certeza que com mais caracteres, isso pode causar problemas de desempenho. Também é importante notar que o método é protegido, verificando a presença de elementos no dicionário e, com um dicionário vazio, a carga deve ser reduzida.

Olhando para o futuro (que ainda está completamente nebuloso para este jogo), também estou confiante nessa decisão no modo online, pois uma verificação do status do jogador ocorrerá apenas para o atual jogador local e não para todos os jogadores instanciados.

Source: https://habr.com/ru/post/pt426305/


All Articles