Tempo de carregamento pré-jogo vs. tempo de carregamento do jogo

9

Estou desenvolvendo um jogo no qual um labirinto aleatório está incluído.
Existem algumas criaturas de IA, espreitando o labirinto. E eu quero que eles sigam algum caminho de acordo com a forma do labirinto.

Agora, existem duas possibilidades para eu implementar isso, a primeira maneira (que eu usei) é calcular vários caminhos ocultos desejados quando o labirinto é criado.
A segunda é calcular o caminho que uma vez precisou ser calculado, quando uma criatura começa a espreitar.

Minha principal preocupação é o tempo de carregamento. Se eu calcular muitos caminhos na criação do labirinto, o tempo de pré-carregamento é um pouco longo, então pensei em calculá-los quando necessário.
No momento, o jogo não é 'pesado', portanto, não é perceptível o cálculo de caminhos no meio do jogo, mas temo que assim que ficar mais complicado.

Quaisquer sugestões, comentários, opiniões serão de grande ajuda.

Editar:

Por enquanto, pseja o número de caminhos pré-calculados, uma criatura tem a probabilidade de 1/pseguir um novo caminho (o que significa um cálculo de caminho) em vez de um existente.
Uma criatura não inicia sua patrulha até que o caminho esteja totalmente calculado, é claro, então não há necessidade de se preocupar com a morte dele no processo.

Guardador
fonte
8
Nesse ponto, seria pré-otimizado. Eu deixaria como está até que haja um problema.
9788 John McDonald
3
E para falar um pouco com o @JohnMcDonald, se você pode calcular esses caminhos no meio do jogo e isso não é perceptível, qual o fator de contribuição que eles podem ter no tempo de carregamento?
James

Respostas:

6

BerickCook expressou a idéia corretamente. Deixe os cálculos onde estão, se funcionar corretamente agora.

Se você pode fazer o cálculo antes e tiver certeza de que não precisará deles no meio do jogo, faça-o antes. Caso contrário, faça-o após o carregamento. Se o cálculo durante o jogo for imperceptível, você poderá fazê-lo lá. Se em algum momento a complexidade evoluir e os cálculos se tornarem pesados ​​demais, comece a otimizar.

Mas uma coisa: se seus cálculos forem implementados para rodar no meio do jogo, você sempre poderá forçá-los a serem executados durante o carregamento de qualquer maneira.

Existem inúmeras soluções:

  • calcular / carregar os caminhos durante a criação / carregamento do nível
  • use um segundo encadeamento para calcular os caminhos
  • otimize seus algoritmos
  • use um sistema interruptível se você não tiver acesso ao encadeamento.

Eu já vi e usei a última opção em um jogo de mercado de massa. Simplesmente certifique-se de salvar corretamente todos os dados necessários para o cálculo ser retomado e verifique regularmente o tempo / operações restantes durante o cálculo.

Dependendo do seu caso, o sistema interruptível pode fornecer soluções preliminares e parciais que podem ser usadas antes do término do cálculo.


Editar : respondendo a @Keeper

O "algoritmo interruptível" foi útil apenas por causa das restrições que tínhamos. Basicamente, paliamos a falta de multithreading.

Em um ponto, tivemos um jogo em que a IA precisava calcular grandes quantidades de movimentos com base em vários dicionários. Durante esse cálculo, todas as animações parariam porque os dicionários foram expandidos com mais dados e o conjunto de dados contendo os dados foi alterado e menos eficiente quando o jogo foi adaptado para multiplayer (onde a IA tinha que interagir mesmo para os movimentos do jogador). Tínhamos apenas um segmento disponível para o loop do jogo (o imperativo é o código de multiplataformas ser executado em todas as plataformas suportadas). Nesse ponto, foi decidido interromper o algoritmo de cálculo para podermos interrompê-lo. Portanto, não podíamos simplesmente usar o sistema recursivo existente, pois as variáveis ​​não podiam ser salvas. As funções foram substituídas por objetos que simplesmente continham todas as variáveis ​​e indicadores necessários para objetos pai e filho. Eu não'

  • salvar o status de seus cálculos atuais
  • interrupção no final de um loop ou durante um loop (quando um objeto filho interrompe)
  • sair quando o tempo acabar
  • continue onde parou de reiniciar um loop no índice correto ou de chamar o objeto filho atualmente no topo de sua pilha filho.
  • limpe tudo se o cálculo for interrompido
  • dê o melhor resultado parcial.

Apenas as operações mais caras foram divididas em objetos separados e levou algum tempo para encontrar os lugares certos onde poderíamos parar os cálculos, mas no final funciona muito bem.

Perdemos o desempenho, mas o desempenho percebido foi muito melhor para o usuário, pois as animações rodavam sem problemas em todas as plataformas; todas as plataformas podiam usar dicionários maiores sem sofrer animações ou congelamentos irregulares. Além disso, isso nos permitiu executar várias instâncias em paralelo quando precisávamos disso mais tarde.

Claro que agora no iPhone e iPad o jogo não precisa disso, usar um segundo segmento seria o ideal. Mas suspeito que o código ainda esteja lá.

Coiote
fonte
Obrigado, isso parece muito interessante. Você pode, por favor, elaborar sobre o conceito de "sistema interruptível" (por que e como). (pesquisar no Google não foi tão útil ..). Vou adicionar alguns detalhes à pergunta.
Depositário
@ Keeper Espero ter respondido sua pergunta sobre a parte interruptível. É uma tarefa difícil mas não é relevante na maioria dos sistemas modernos.
Coiote
Mesmo que eu não vá usar esse método por enquanto, você abriu meus olhos para algo novo. Sua resposta merece ser aceita.
Keeper
8

Por enquanto, como calcular os caminhos no meio do jogo é imperceptível, essa é a abordagem ideal. Se / quando chegar ao ponto em que a jogabilidade é interrompida pelos cálculos, passe para o cálculo dos caminhos antes do carregamento do nível.

Tempos de carregamento iniciais mais longos são perdoáveis, mas flutuações aleatórias no FPS durante o jogo geralmente não são.

BerickCook
fonte
2

Uma possibilidade, se você precisar, é mover os cálculos para um segundo segmento, pois quase todos os PCs têm mais de um núcleo de CPU atualmente.

O processo básico seria:

  • Quando uma criatura solicita um caminho, adicione a solicitação a uma fila de solicitações seguras de threads e sinalize a thread.
  • A criatura fica ociosa enquanto aguarda o fio sair da entrada dessa fila, processá-la e colocá-la em uma lista completa.
  • Cada quadro verifica a lista completa do tópico principal e atribui caminhos completos às criaturas.

Você também deve observar alguns casos extremos extras (por exemplo, e se a criatura morrer antes do processamento da solicitação).

Adão
fonte
2
Se você não deseja introduzir o encadeamento, também pode calcular seu caminho de forma incremental (por exemplo, calcule algumas etapas a cada quadro).
bummzack