Estou brincando com a escrita de um RPG tático muito ruim em C ++. Até agora, eu tenho um mapa em 2D e acabei de obter o algoritmo A * funcionando com base no pseudocódigo da wikipedia .
Mas RPGs táticos reais não apenas encontram o melhor caminho em um avião plano e se mudam para lá. Eles geralmente têm intervalos de movimento limitados e devem subir ou descer. Se você já jogou Final Fantasy Tactics, isso será afetado pelas estatísticas de Movimento e Salto. É aqui que eu me perco. Como altero o algoritmo A * para encontrar o melhor caminho em direção a um destino, mas o caminho tem apenas tantos blocos? Como devo levar em consideração as diferenças de altura e pular as estatísticas? Como faço para implementar pulando uma lacuna?
Se ajudar, agora meu mapa é representado por um objeto Vector of Tile. Cada bloco possui ponteiros para o bloco Norte, Sul, Leste e Oeste, que são definidos como nullptr se não existir nenhum bloco, como ao longo da borda do mapa ou se um bloco estiver definido como não passável.
fonte
Respostas:
Escalada e lacunas são apenas funções de custo diferentes. Para uma unidade que pode pular a lacuna, tem um custo normal (?), Enquanto para uma unidade sem salto, ela tem um custo arbitrariamente alto. Escalar custos extras, assim como terrenos difíceis, etc. O algoritmo A * é capaz de lidar com funções de custo; portanto, se sua implementação ainda não estiver sendo feita, pesquise no Google como implementar o A * com uma função de custo.
Dito isto, no entanto, não acho que A * seja uma abordagem particularmente boa para um RPG tático. Ou, mais precisamente, não é uma história completa. Você não quer que suas unidades mancem cegamente em direção ao seu objetivo, você quer que elas se posicionem para explorar cobertura, terreno elevado, o que quer que seja, enquanto progridem em direção ao objetivo final e procuram flanquear os oponentes e assim por diante. Portanto, o valor tático do ponto final de cada jogada é de enorme importância, não apenas o quão perto é a meta. Isso requer uma solução de problemas mais aprofundada do que a simples busca de caminhos.
fonte
Quando você quiser todas as opções de movimento possíveis de uma unidade, use o algoritmo de Dijkstra .
A diferença entre A * e Dijkstra é que Dijkstra oferece todas as rotas mais curtas possíveis com um determinado custo e, se nenhuma delas chegar ao seu destino, aumenta o custo em um e continua. A *, por outro lado, prefere calcular primeiro as rotas que têm boas chances de chegar ao destino.
Portanto, quando você deseja apenas o caminho mais curto do ponto A ao ponto B, A * é uma boa opção. Mas se você deseja todas as opções de movimento possíveis e o caminho mais curto para cada uma delas, o Dijkstra é exatamente o que você deseja.
Tudo o que você precisa fazer é executar o algoritmo do Dijksta sem um nó de destino específico, mas com um custo máximo que não deve ser excedido (a faixa de movimento da unidade). Quando viajar para um nó exceder o custo máximo, não o visite. Quando o algoritmo termina devido à falta de arestas não visitadas, cada nó no conjunto visitado é um destino possível, e os marcadores de nós anteriores dos nós formam uma lista vinculada que representa o caminho de volta ao nó inicial.
Em relação aos saltos: esses podem ser representados como mais uma vantagem em A * e Dijkstra. Eles podem ter o mesmo custo que atravessar uma borda regular ou outra. Você também pode passar um parâmetro "jump_height" para o algoritmo que diz ao algoritmo para ignorar as bordas do salto que excedem uma determinada altura.
fonte
A*
é apenas uma generalização de Dijkstra; portanto, se você entende um, não deve ser muito difícil entender o outro.As outras respostas têm algumas informações boas, portanto, leia-as.
No entanto, para responder à sua pergunta: com base no pseudocódigo ao qual você vinculou, você tem algum tipo de função
heuristic_cost_estimate
qual está calculando o custo do tileA ao tileB (assumindo que eles sejam adjacentes). Em vez de usar um flat (1) para esse custo, você teria que ajustá-lo para incluir as estatísticas de bloco e estatísticas de unidade e possivelmente estatísticas de borda.Por exemplo:
Isso lhe dará seu caminho. Então, você simplesmente moveria a unidade ao longo de seu caminho enquanto consumia pontos de movimento e os interrompeu quando restarPoints <edgeCost. Observe que isso pode não ser completamente ideal se você acabar com Pontos restantes = 1, mas deve ser bom o suficiente para um RPG de prática. Na realidade, você gostaria de ser mais tático, como Jack Aidley apontou!
Desafio:
Se você quer se tornar mais avançado, provavelmente deseja usar o Djikstras, conforme sugerido, para encontrar todos os espaços a uma distância X, então você deseja avaliar cada espaço nessa lista para um "melhor" lugar, com base na proximidade do alvo, na defesa poder, se você pode ou não ser atacado a partir dessa posição, etc. Com base nessas informações, você escolheria um ladrilho e depois seguiria para lá seguindo o caminho que você acabou de calcular usando Djikstras.
fonte
Escaladas e lacunas são bastante triviais, pois apenas modificam o custo. A busca de caminhos (e a maior parte da IA tática) consiste em resumir o custo em todos os nós a serem visitados e minimizar isso. Um penhasco intransitável terá um custo infinito (muito, muito alto), as encostas terão um custo mais alto do que o normal, etc.
Isso, no entanto, encontra o caminho ideal globalmente que não é a melhor solução, porque adversários reais geralmente não encontram o caminho ideal. É altamente irrealista, às vezes até um ponto óbvio para o jogador, e irritante (especialmente quando a IA como tal é basicamente invencível, porque também escolhe o ideal).
Boas simulações deliberadamente não encontram o melhor caminho. Um algoritmo muito melhor pode ser a busca hierárquica de caminhos - se nada mais, desenhando uma linha reta no mapa e pegando 4-5 waypoints, depois pathfinding de um waypoint para o próximo, considerando apenas os pesos dos nós até agora conhecido e definindo todos os outros pesos de nó como "indiferente". Como alternativa, você pode executar A * em uma grade mais grossa primeiro e depois encontrar o caminho de um nó grande para o próximo (mas acho que desenhar uma linha no mapa também é bom).
Isso é muito mais realista (e também consome uma fração da capacidade de processamento porque o gráfico é muito menor). Sim, isso pode significar que uma unidade se move em direção a um penhasco apenas para descobrir que não pode atravessar. Tudo bem, isso acontece com adversários reais também. Da próxima vez, isso não acontecerá novamente (porque agora o custo infinito é conhecido).
fonte