Algoritmo di tracciamento dinamico per il gioco di difesa della torre


16

Sto realizzando una Tower Defense e per questo ho bisogno di un buon algoritmo di tracciamento.

Ho pensato a Dijkstra ma ne ho bisogno che può essere dinamico; deve essere in grado di aggiornarsi quando un bordo viene rimosso o aggiunto senza un ricalcolo completo.

Sto codificando in C # se aiuta.

Risposte:


8

In genere vorrai usare A *, a meno che non ci sia qualcosa di molto diverso che stai cercando.


Se non avessi familiarità con A *, come affronterei ambienti che cambiano in modo dinamico? Ricalcola ad ogni frame? Alle collisioni?
Justin L.,

1
In genere, dovrai ripetere il percorso di ogni frame in un gioco semplice come questo. La griglia della mappa sarà probabilmente molto piccola e il numero di agenti nelle centinaia al massimo. Se alla fine fosse un grosso problema di prestazioni, in qualche modo potresti ottimizzarlo in seguito non ricostruendo l'albero se non quando necessario.
coderanger,

6
Se è lento, i miei consigli: non calcolare il percorso per ogni mob. Probabilmente, stanno tutti prendendo la stessa strada. Ricalco solo il posizionamento della nuova torre e la torre è nel percorso corrente . Anche allora, esegui un nuovo calcolo per i mostri nei punti del percorso prima del riquadro del blocco, non per i mob che lo hanno superato e quindi non se ne curano. E quindi, per accorciare il percorso, potresti limitarlo per trovare il modo di quadrare dopo il quadrato bloccato, poiché già conosci il percorso da lì.
seanmonstar,

4
In realtà, "mob" è un linguaggio industriale (e MMO / MUD) per "oggetto mobile".

3
Indipendentemente da ciò, è di vecchia data, risale al MUD1 e abbastanza standard da apparire in molte pubblicazioni. en.wikipedia.org/wiki/Mob_%28computer_gaming%29

19

Avevo bisogno di risolvere un problema simile: l'individuazione di percorsi su una grande griglia simile a un labirinto con "costi" e barriere in costante cambiamento.

Il fatto è che nel gioco di difesa della torre il numero di entità che devono risolvere il percorso per loro è di solito molto più grande del numero di nodi nel grafico. Un * non lo è l'algoritmo più appropriato per gestirlo, perché dovrai risolverlo di nuovo ogni volta che qualcosa viene cambiato. Bene, è appropriato se devi trovare solo un percorso, ma nel mio caso avevo bisogno di essere in grado di gestire entità che possono apparire in posizioni diverse e ognuna ha il suo percorso.

L' algoritmo di Floyd-Warshall è molto più appropriato, anche se nel mio caso ho scritto un algoritmo personalizzato che ogni volta che un nodo cambia, ricalcola il costo di quel nodo da tutti i suoi vicini, e quindi se i vicini sono stati cambiati viene invocato ricorsivamente su di loro.

Quindi all'inizio del gioco, accendo questo algoritmo su tutti i miei nodi "obiettivo". Quindi, ogni volta che cambia un singolo nodo (ad esempio, diventa non passabile), lo accendo solo su quel nodo e la modifica viene propagata a tutti i nodi che saranno interessati e quindi interrotta. Quindi non è necessario il ricalcolo globale e l'algoritmo è completamente indipendente dal numero di entità che richiedono l'individuazione del percorso.

Il mio algoritmo era sostanzialmente qualcosa di simile (pseudo-codice):

update_node method in Node class:
    $old <- $my_score
    find $neighbor node among all neighbors such that
        $neighbor.score + distance_to($neighbor) is minimal
    $my_score <- $neighbor.score + distance_to($neighbor)
    $next_node <- $neighbor
    if ($my_score != $old)
        for each $neighbor
            $neighbor.update_node()

Con il punteggio iniziale a seconda che il nodo sia un obiettivo o una sorta di barriera.


1
Inoltre sarebbe facile diffonderlo dinamicamente su frame man mano che il carico della CPU cambia.
tenpn

+1 per A * non è l'algoritmo giusto da usare.
Ricket,

5

L'algoritmo di rotta che ho usato sul mio TD era all'indietro rispetto al normale percorso A * a causa del numero di entità che avevo nel gioco. Invece di passare dall'obiettivo ai cattivi, ho indirizzato dall'obiettivo a ogni quadrato vuoto sul tabellone.

Questo non richiede molto tempo, continui a iterare la scheda fino a quando non hai trovato i tuoi "costi" e fornisce un buon feedback per i percorsi bloccati (se li stai facendo). L'uso dell'algoritmo di Floyd è veloce e compatibile con la cache rispetto ad A * in quanto non esegue ricerche dipendenti dai dati, si sta semplicemente caricando e operando sui dati nei flussi.

Inizia con la tua scheda impostata su un costo infinito, quindi imposta la casella obiettivo su costo zero, quindi esegui l'iterazione sulla scheda controllando se una cella vicina costa meno del costo corrente più il costo del viaggio. Il costo del viaggio è dove hai messo la tua euristica (nel mio caso, il costo del viaggio in diagonale era infinito, ma il costo del viaggio attraverso una torre era alto, quindi gli era permesso di mangiare attraverso le torri, ma a meno che non avessero scelta)

Una volta ottenuta la griglia dei costi, è possibile creare rapidamente una griglia "flusso" da quella testando il gradiente di costo più ripido sulle celle. Questo funziona davvero bene per enormi quantità di cattivi perché nessuno di loro deve mai trovare il percorso, seguono solo le indicazioni virtuali.

Un altro vantaggio è che in questo modo devi solo eseguire questo compito ogni volta che aggiusti gli ostacoli (o nel mio gioco, quando un brivido si nutre attraverso una delle tue torri). Non ogni volta che un creep / mob entra nel campo (che con migliaia di mob e decine al secondo sarebbe stato piuttosto un mal di testa).


4

Il pathfinding è veloce e su qualcosa delle dimensioni di un normale gioco di difesa della torre, non avrai problemi a eseguire un passaggio A * o Dijkstra completo ogni volta che qualcosa cambia. Stiamo parlando bene sotto un millisecondo per un aggiornamento completo. Qualsiasi tipo di tracciamento adattivo finisce in modo orribilmente complicato. Fallo nel modo più semplice, a meno che tu non stia realizzando la più grande griglia di difesa della torre al mondo.


1
Vale la pena notare che Tower Defense è popolare sui telefoni cellulari, dove il rilevamento dei percorsi non è veloce. Soprattutto su dispositivi leggermente più vecchi, come Sidekick o Android 1.6.
seanmonstar,

1
Per decenni gli sviluppatori hanno utilizzato algoritmi di pathfinding come A * e Dijkstra su hardware molto meno potente (pensa a Game Boy). Qualsiasi telefono abbastanza nuovo da avere uno schermo adeguato per i giochi non dovrebbe avere problemi, a condizione che l'implementazione sia ragionevolmente efficiente. Ci sono alcune ottimizzazioni interessanti discusse qui: harablog.files.wordpress.com/2009/06/beyondastar.pdf
Mike Strobel

+1. Sono arrivato alla stessa conclusione quando stavo sviluppando il mio clone DTD. Ho provato ad aggiornare i percorsi in modo incrementale ma l'algoritmo è diventato troppo complesso. Dopo aver trascorso un giorno su di esso, sono passato a un ricalcolo completo per ogni modifica. Funzionò e con alcune modifiche sono riuscito a farlo abbastanza velocemente.
Finnw,


2

Questo potrebbe essere eccessivo per la tua soluzione, ma pensa al routing all'indietro anziché in avanti.

In una partita TD, i nemici generalmente cercano di raggiungere un obiettivo specifico. Rotta all'indietro da quell'obiettivo al primo nemico, quindi memorizza nella cache quel percorso. Nella generazione del percorso per i nemici successivi, usa il primo percorso come punto di partenza e così via. Se hai più punti di accesso nemici o più obiettivi, puoi iniziare da una serie di percorsi pre-memorizzati nella cache.


1

Il pathpoint di waypoint sarebbe probabilmente il migliore per un gioco td, perché generalmente basato sul livello che l'IA segue un percorso diretto. Fondamentalmente si impostano i nodi o i waypoint quindi si ha il punto "ai" verso il waypoiny e si cammina verso di esso, una volta che si avvicina abbastanza da farlo andare al waypoint successivo, affrontarlo e spostarsi verso di esso.


Funziona solo con quei giochi TD in cui puoi posizionare solo torrette ai lati del percorso, non giochi che consentono il posizionamento di torri in qualsiasi punto del tabellone.
Iain,

sì, inizialmente l'autore non ha specificato quale tipo voleva, quindi ho assunto non dinamico.
Loktar,

1

Da quando qualcuno lo ha chiesto, ti rivolgi ad ambienti che cambiano in modo dinamico ricalcolando il percorso ogni volta che il giocatore posiziona o rimuove una torre e nel frattempo memorizzi quel percorso in memoria. L'ambiente non cambia su ogni frame.

Nota che alcuni giochi TD hanno un percorso prestabilito e non ti consentono di posizionare torri su di esso, quindi risolvono il pathfinding in modo semplice: codificando un percorso e non lasciandolo bloccare :)


1

Una soluzione semplice è imbrogliare.

Progetta la mappa in anticipo per assicurarti che non ci siano vicoli ciechi. Quindi in ogni incrocio, aggiungi un grilletto che induca il personaggio a scegliere una rotta (esempio: gira sempre a sinistra, gira sempre a destra o a caso).


1
Presumibilmente sta parlando di qualcosa come Desktop TD in cui l'utente sta creando la mappa al volo. Ancora per i nemici "stupidi" che potrebbero essere una buona soluzione in modo da poter aumentare i nemici con un'intelligenza artificiale migliore.
coderanger,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.