Como gerenciar todos os objetos NPC / AI no servidor?

8

Estou escrevendo um MMO simples e atualmente tenho a arquitetura servidor-cliente em funcionamento para que vários usuários se vejam e possam se movimentar juntos ... agora é hora de adicionar inimigos.

Estava imaginando se alguém tinha links para artigos que discutiam a melhor maneira de lidar com as centenas de objetos NPC que precisam ser gerenciados no mundo. Eu fiz algumas pesquisas e não consegui encontrar muita informação sobre como isso normalmente é feito.

Os dois métodos de estruturação da implementação que posso pensar:

  1. Manter todos os objetos NPC instanciados em uma lista e fazer com que um Thread do NPC faça um loop neles sequencialmente e verifique se cada um possui alguma lógica que precise ser processada e execute as ações necessárias. Não tenho certeza se o desempenho desse design seria suficiente?
  2. Sistema baseado em eventos. Crie um método na classe NPC que processe o AI / Logic nele, faça com que esse método seja chamado quando um evento associado for sinalizado, seja em um cronômetro para a funcionalidade do AI não interagida (como vagar), ou sinalize o evento externamente a partir do pacote manipulador (jogador se movendo nas proximidades ou atacando dentro do alcance).

Uma dessas abordagens é a maneira correta? Que outros métodos para fazer isso existem?

dgo
fonte

Respostas:

5

Como sempre, a arquitetura depende de seus requisitos. Quantos mobs você vai ter? Quão complexa é a IA deles? A que reage? Com que frequência ele muda de estado? Responda a essas perguntas e você entenderá muito melhor o que deseja e como obtê-lo.

Geralmente, você deseja ter pelo menos algum tipo de sistema de eventos. A IA é geralmente definida em termos de eventos: "Quando A acontecer, faça B"; e se você não tiver eventos no código real, teria que traduzir essas definições de alguma forma.

Na minha experiência, você pode se dar bem com uma implementação de loop simples quando tiver poucos e realmente simples mobs (ao contrário do que a outra resposta parece sugerir). Por exemplo, em nosso jogo atual, temos centenas de pequenas instâncias, cada uma com 10 mobs no máximo. E essas multidões são estúpidas; A IA de 99% deles pode ser descrita em uma frase: "Estou atacando alguém? Se não, ataque o jogador mais próximo". Nesse caso, um loop simples é mais do que suficiente - duas vezes por segundo, procuramos um novo alvo (e algumas outras coisas para os raros mobs "inteligentes"), e é isso.

No entanto, quando você tem mobs mais e / ou mais inteligentes, a abordagem ingênua para de funcionar. Para que a IA reaja a algum estímulo, você precisa escrever um código que o detecte dentro do loop da AI. Por exemplo: suponha que sua turba faça algo "quando atingida por um jogador". Com uma abordagem em loop, não há uma maneira fácil de determinar se a multidão foi atingida. Quando a IA está em execução, você pode verificar se a saúde da multidão diminuiu desde o último tick ou se a multidão está atualmente sendo alvo de alguém. Mas você não pode detectar hits reais sem recorrer a hacks, como salvar cada informação de hit em algum lugar para a IA acessá-las posteriormente.

Em segundo lugar, um loop ingênuo sempre é executado, não importa o que aconteça. Quando você tem muitos mobs, deseja que a IA seja executada o mais rápido possível .. e o código mais rápido é o código que nunca é executado. Se você tem mobs que não estão ativos, deseja que eles não executem a IA ou executem apenas esporadicamente (como no caso, a IA da multidão errante só deve ser executada quando decidir para onde ir).

Com a abordagem baseada em eventos, você pode solicitar que outros subsistemas enviem eventos de IA sempre que conveniente, eliminando o problema de "detecção de ocorrências". Certamente, alguns eventos ainda exigiriam a detecção de código: o exemplo mais notável é o evento "abordagem". E quando você não executa sua rotina de IA em loop quando nada acontece, você obtém desempenho.

Você também pode usar uma abordagem híbrida. Em vez de manipular eventos de IA imediatamente, você pode colocá-los em algum tipo de fila. Em seguida, quando a rotina do AI é executada (em um loop), ela remove os eventos dessa fila e os lida um por um. Com essa arquitetura, o desempenho da IA ​​pode ser um pouco mais lento, mas é mais previsível; Além disso, você pode garantir que toda a IA seja executada em um único segmento (o que pode ser complicado). Esse tipo de loop também pode ser facilmente controlado, ignorando alguns eventos (por exemplo, cada iteração de IA lida apenas com os três eventos mais recentes, descartando o restante). Ou os eventos podem ser priorizados e os menos importantes descartados se a IA estiver atrasada.

No geral, a abordagem "loop com fila de eventos" é provavelmente a mais flexível. Mas quero reiterar: não o escolha cegamente como "o melhor". Pense primeiro nos seus requisitos, e uma abordagem mais simples pode se tornar melhor.

deixa pra lá
fonte
e apenas para concluir esta resposta, você sempre pode adicionar mobs ou removê-los do seu loop de verificação. por exemplo. quando não há ninguém para observar o que uma multidão está fazendo, não é lógico fazer tudo o que o NPC faria naquele momento. assim você pode facilmente filtrar muitos mobs e apenas verificar se os mais importantes (normalmente aqueles perto o suficiente para os jogadores) precisam nenhuma atualização
Ali1S232
Uma "multidão" é um grupo de inimigos ou um único inimigo?
Richard Marskell - Drackir
"mob" é um único inimigo. O termo foi cunhado por Richard Bartle no MUD1, e é a abreviação de "mobile" - porque os mobs meio que se movem, ao contrário de outros objetos.
Nevermind
2

Vai depender do número de inimigos que você tem e de quão ativos eles serão.

Se você tem muitos inimigos, mas eles não fazem muito na maioria das vezes, um sistema de eventos pode ser melhor. Se você tem inimigos que geralmente estão fazendo algo, o loop pode funcionar melhor, pois leva em consideração a complexidade do sistema de eventos e porque, se os eventos estivessem no local, eles constantemente disparariam.

Nate
fonte