Rilevamento più rapido della collisione 2D


13

Di recente ho lavorato su uno sparatutto in 2D frenetico e ho riscontrato un grosso problema. Rilevazione di collisioni. Certo, funziona, ma è molto lento. Il mio obiettivo è: avere molti nemici sullo schermo e fare in modo che non si tocchino. Tutti i nemici inseguono l'entità giocatore. Molti di loro hanno la stessa velocità così prima o poi finiscono per occupare lo stesso spazio mentre inseguono il giocatore. Questo lascia davvero cadere il fattore divertente poiché, per il giocatore, sembra che tu sia inseguito da un solo nemico. Per impedire loro di occupare lo stesso spazio, ho aggiunto un rilevamento delle collisioni (un rilevamento 2D di base, l'unico metodo che conosco) che è.

Enemy class update method
    Loop through all enemies (continue; if the loop points at this object)
        If enemy object intersects with this object
            Push enemy object away from this enemy object

Funziona benissimo. Finché avrò solo <200 entità nemiche. Quando mi avvicino a 300-350 entità nemiche il mio frame rate inizia a calare pesantemente. Per prima cosa ho pensato che fosse un cattivo rendering, quindi ho rimosso il call call. Questo non ha aiutato affatto, quindi ovviamente ho capito che era il metodo di aggiornamento. L'unica parte pesante nel loro metodo di aggiornamento è questa parte di ogni nemico. Quando mi avvicino a 300 nemici, il gioco esegue 90000 (300x300) passaggi. Mio mio ~

Sono sicuro che ci deve essere un altro modo per ottenere questo rilevamento delle collisioni. Anche se non ho idea di come. Le pagine che trovo riguardano come eseguire effettivamente la collisione tra due oggetti o come controllare la collisione tra un oggetto e una piastrella. Conosco già queste due cose.

tl; dr? Come posso applicare il rilevamento delle collisioni tra LOTTI di entità?

Modifica rapida: se è di aiuto, sto usando C # XNA.


Mi chiedo come hai ottenuto per andare a 90K in primo luogo. il mio soffoca a 20K (sto facendo il rilevamento completo di MTV SAT). Ma passare in rassegna tutti i nemici è l'unica cosa che sembra possibile. Quello che devi fare, tuttavia, è verificare se sono già stati controllati, perché se fai come dici tu, allora tutti vengono testati con tutti due volte.
Delusional Logic,

3
Questo è un possibile duplicato di gamedev.stackexchange.com/questions/39931/…
Markus von Broady

C'è un'ottima risposta alla domanda che @MarkusvonBroady ha collegato.
Cypher

Risposte:


11

Hai già colpito il tuo problema proprio sulla testa, stai facendo controllare ogni entità contro ogni altra entità. Quello che vorrai è un tipo di sistema 'Level of Detail' (è un grafico di scena molto semplice, lo stai usando solo per cose diverse dal rendering :)) dove i candidati alla collisione sono meglio selezionati.

In genere faccio tre raccolte per sistemi come questo. E quando stai parlando del numero di entità che stai cercando di avere, potresti anche dover andare con un grafico completo della scena per questo poiché i dati di tracciamento (3 elenchi per entità con una voce per ogni altra entità) possono uscire rapidamente di controllo.

Fondamentalmente anche se hai tre elenchi. Il primo dovrebbe essere un elenco molto piccolo di entità che verificherai con interazioni ogni frame. Si determina questo perché rientrano nell'intervallo X dell'entità in questione. Come accennato, il punto di questo elenco è di contenere ogni entità che può ragionevolmente scontrarsi con un altro questo frame.

L'elenco seguente è quelli che si troverebbero in un intervallo di buffer che potrebbe spostarsi nell'intervallo dell'entità senza troppi sforzi. Chiameremo questo intervallo X * 1.5 solo per ragioni di argomento. Questa è una lista a intervalli di tempo in cui ne aggiornerai solo una manciata per fotogramma, ma ti assicurerai che li stai attraversando abbastanza velocemente da mantenere l'aspetto delle cose senza intoppi.

Il terzo elenco è l'elenco "tutto il resto" e un modo per evitare di avere questo potrebbe valere la pena (Scansionare l'intero elenco di entità e forse controllare per vedere se si trova in uno degli altri elenchi prima di procedere forse? A seconda delle dimensioni dell'elenco questo potrebbe funzionare, o potrebbe peggiorare le cose.) Gli oggetti in questo elenco vengono controllati meno di tutti poiché dovrebbero sicuramente essere necessari più di alcuni frame per essere inseriti in uno degli altri due elenchi.

Quello che dovrai anche fare per mantenerlo è quando stai facendo i test di collisione, assicurati di aggiornare la lista in cui si trovano le entità. Quelli che si spostano fuori dal raggio dovrebbero essere declassati e allo stesso modo quelli che si avvicinano dovrebbero essere aggiornati in un elenco controllato più attivamente.

Supponendo che stai mantenendo le cose abbastanza semplici questo dovrebbe soddisfare le tue esigenze. Se riesci a inserire informazioni aggiuntive in un grafico di scena di rendering esistente (supponendo che tu ne abbia uno) in modo da poterlo interrogare per ottenere un elenco di entità ragionevolmente all'interno dell'intervallo che sarebbe ancora migliore poiché questo è l'intero punto di un grafico di scena comunque (accesso rapido a un elenco di dati rilevanti basato su una posizione). Questo richiederebbe potenzialmente più lavoro da fare e dovresti sempre considerare ciò che devi fare rispetto a ciò che dovresti praticamente fare.

Spero che sia di aiuto.


1
Questa è una risposta vaga. E possiamo accettare di perdere alcune collisioni ?? Molto più semplice, usa una struttura di dati che farà il partizionamento della superficie per te, come il Quad Tree di cui parlo qui. Anche un Quad Tree ha bisogno di una piccola messa a punto per evitare il sovraccarico, quindi non riesco a immaginare la complessità della "soluzione" di cui parli. Regola di programmazione di base: basta usare la giusta struttura di dati.
GameAlchemist

@VincentPiel Un grafico di scena non è più complesso di un albero quad.
Cypher

@James: ovviamente è più complesso. Se non ti dispiace afferrare tutta la velocità di QuadTree, puoi ottenere una lib QuadTree in rete e farla funzionare perfettamente in un paio d'ore. Nessuna domanda del tipo: cosa inserisco nella prima lista, nella seconda, nella terza, come decido di inserire un'entità in un'altra lista ... e nessuna collisione persa. Perché usare una bicicletta quando puoi avere una macchina?
GameAlchemist,

@VincentPiel Penso che intendevi @ il tuo commento a Cypher invece che a me qui. Qualunque albero dei quad sia solo un tipo di grafico di scena e devi ricordare che stai correndo a X fotogrammi al secondo. Se si notano collisioni perse, è necessario regolare le soglie di portata per bilanciare meglio le cose. La mia soluzione è solo un approccio molto semplice per assicurarmi di controllare solo le cose in ogni frame che hanno la possibilità di essere scontrati e quindi fare aggiornamenti in background / limitati sul resto per vedere se si qualificano per una priorità ancora più elevata.
James,

6

Devi gestire le collisioni con una struttura di dati ordinata, quindi puoi avere n * log (n) volte anziché il terribile n ^ 2. E n * log (n) è quasi lineare come potresti sapere. Un esempio (classico) è un quadrifoglio, qui c'è un tutorial abbastanza semplice e ben scritto, con grafica e codice (Java):

http://gamedev.tutsplus.com/tutorials/implementation/quick-tip-use-quadtrees-to-detect-likely-collisions-in-2d-space/

Rq: è abbastanza facile trovare un'implementazione per QuadTrees in qualsiasi lingua. Tuttavia, devi pensare alla giusta "granularità" per l'albero, e maggiore è la dimensione dell'albero, più abbiamo entità che non rientrano in un nodo.
Rq 2: poiché il partizionamento dello spazio viene eseguito solo per il rilevamento delle collisioni, hai la libertà perfetta di dividere lo spazio come preferisci. Ad esempio, non vorrei dividere in quattro parti egali ma piuttosto userei il baricentro delle entità di livello attuale come centro per la nuova divisione. 1) l'algoritmo è ancora n * log (n), 2) perdi la possibilità di "ricostruire" la scena dall'albero - ma non ti interessa - e 3) hai un albero molto più bilanciato, meno sovraccarico .
Rq3: Una volta che hai il tuo albero, una 'collisione' tra lo schermo e le entità ti dà ... le entità visibili !! in un momento più simile a log (n), quindi perché non se n è grande? (il caso peggiore è ovviamente un momento in n per questo approccio.)


Sì, un albero quad è solo un tipo di grafico di scena. Suppongo sempre che le persone che sono qui vogliono scrivere le cose da sole, non usare la libreria di qualcun altro, nel qual caso perché fermarsi a un albero di quad, basta trovare una libreria di collisioni completa.
James,

0

albero delle partizioni di spazio binario, quadrifoglio, ottetto (per 3D) sono possibili alberi che è possibile generare (o mantenere, se si è ambiziosi) ad ogni chiamata di aggiornamento per ogni oggetto che si desidera applicare la collisione.


3
È più appropriato essere un commento. Valuta di aggiungere altro alla tua risposta.

0

Sono abbastanza ingenuo quando si parla di quad o oct tree. Ma penso che questo metodo dovrebbe fare:

Dovrai modificare la struttura / classe del giocatore. Aggiungi un array / vettore di puntatori alla struttura dell'altro giocatore.

Ogni secondo controlla la distanza tra ogni due giocatori. Se è così basso che è possibile raggiungere entro 1 secondo, aggiungi il puntatore di quel giocatore all'array di collisione del giocatore corrente.

Ora controlla solo la collisione tra giocatori nella lista degli altri.

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.