Come trovare le celle della griglia 2D spazzate da un cerchio in movimento?


9

Sto realizzando un gioco basato su una griglia 2D, con alcune celle passabili e altre no. Gli oggetti dinamici possono muoversi continuamente, indipendentemente dalla griglia, ma devono scontrarsi con celle impraticabili.

Ho scritto un algoritmo per tracciare un raggio contro la griglia, che mi dà tutte le cellule che il raggio interseca. Tuttavia, l'oggetto reale non ha dimensioni in punti; Attualmente li sto rappresentando come cerchi. Ma non riesco a capire un algoritmo efficace per tracciare un cerchio in movimento. Ecco una foto di ciò di cui ho bisogno: inserisci qui la descrizione dell'immagine

I numeri mostrano in quale ordine il cerchio si scontra con le celle della griglia. Qualcuno conosce l'algoritmo per trovare queste collisioni? Preferibilmente in C #.

Aggiorna Il cerchio può essere più grande di una singola cella della griglia.


mmh perché 3 si scontrano PRIMA di 4?
FxIII,

@FxIII In realtà ho spostato il cerchio nella foto, e ha colpito 3 prima di 4. Solo a malapena, ma ancora prima.
Nevermind,

Risposte:


6

Penso che il tuo disegno sia un po 'fuorviante perché hai scelto di tracciare tratti dal punto del cerchio tangente alla tua direzione di movimento. Vedo che le collisioni ai bordi della griglia si verificano quando i punti TOP e LEFT del cerchio toccano un bordo.

Lascia che C sia il tuo centro e r il raggio in modo che P ' = C + ( r , 0) e P " = C + (0, r).

Se D è il tuo vettore di direzione (il verso) hai due linee:

R '= D · t + P' ,

R "= D · t + P"

Devi semplicemente trovare l'intersezione di quelle linee con le linee dell'equazione:

y = i e y = i che sono i bordi della griglia!

La soluzione sono facile, perché bisogna considerare semplicemente il xo la componente y di R' e R". Troverete il t valore di s per ogni insersection, ed i punti per thoose t s, semplicemente sorta coloro punto per t e si sono fatti.

Credo che puoi facilmente dire quale cella viene colpita se conosci il punto di intersezione.

Funziona se r <1 (la larghezza e l'altezza della cella).

Funziona anche per gli altri casi semplicemente prendendo in considerazione P ' e P " . Scegliamo TOP e LEFT a causa della direzione, BOTTOM e RIGHT dovrebbero essere considerati per la direzione opposta, capisci perché.

Ora guarda questa immagine: grande cerchio

Il cerchio è più grande di una singola cella e supponiamo che stia andando nella stessa direzione del tuo disegno. P1 è il primo punto che toccherà, P2 è il secondo, P3 è inutile perché è nella metà inferiore. Quello che devi fare è proiettare i raggi da P1 e P2 come abbiamo visto prima e fare lo stesso per le linee verticali.

In generale avrai altri punti di partenza insieme a quelli TOP e LEFT da dove sparano i tuoi raggi, più grande è il tuo cerchio, più raggi da lanciare.

Ad essere sincero, puoi evitare di sparare a tutti quei raggi facendo qualche considerazione geometrica, ma ciò può rendere le cose più difficili da capire.


Sì, ho pensato personalmente ai punti P 'e P ", ma non sono riuscito a capire cosa fare quando il cerchio è più grande di una singola cella. I punti aggiuntivi hanno davvero senso (e ovviamente ho solo bisogno di aggiungere raggi tra P' e P ")
Nevermind,

Considerazioni geometriche possono essere fatte per semplificare i calcoli ma l'utilizzo dell'esecuzione può portare agli stessi risultati per esperienza.
FxIII,

È chiaro che devi testare le linee della griglia orizzontale e verticale separatamente?
FxIII,

Penso che devi anche controllare quando il cerchio copre un vertice della griglia, perché il cerchio si scontrerà con la cella adiacente in diagonale al suo angolo, ma non sarà necessariamente il punto superiore / sinistro / inferiore / più a destra sul cerchio che lo tocca per primo (e rileverete la collisione troppo presto.) Esempio: quadrati 3,4,5 nel diagramma di esempio nella domanda. Vengono colpiti in ordine (3, quindi 4, quindi 5), ma l'algoritmo rileverà 4 e 5 contemporaneamente.
finnw,

@finnw si toccano contemporaneamente solo se il ciclo si sposta esattamente nella direzione della bisettrice.
FxIII,

1

Se si desidera utilizzare l'algoritmo di collisione del raggio, è possibile scegliere otto punti su ciascun cerchio (con incrementi di 45 gradi, allineati con la griglia quadrata) e utilizzare la collisione del raggio tra punti corrispondenti (ovvero dalla parte superiore di uno cerchio in cima all'altro). L'unione di tutte queste collisioni di raggi è l'intero insieme di cellule intersecate.

Probabilmente potresti migliorare un po 'questo, ad esempio usando il segmento di linea dal centro di un cerchio al centro dell'altro, ma esteso su entrambi i lati dal raggio del cerchio, così come i segmenti di linea parallela su entrambi i lati alle estremità dei cerchi.


8 raggi probabilmente garantiranno tutte le intersezioni, ma non le daranno nel giusto ordine. E per le collisioni ho bisogno di ordine, non solo di un elenco di celle.
Nevermind,

Aumenta il tuo algoritmo di collisione del raggio per mantenere un valore t per ogni collisione. Quando ottieni l'unione di celle, puoi ordinare il valore t per ottenere l'ordine corretto.
TreDubZedd,

Ma come posso confrontare il valore t di raggi diversi ?
Nevermind,

Se provieni sempre dallo stesso cerchio, i tuoi punti di intersezione saranno distanti da quel cerchio. Quando arrivi in ​​una cella che hai già visto, se il valore t della collisione corrente è più piccolo di quello precedente, usalo ... altrimenti, scarta l'intersezione (mantenendo l'originale).
TreDubZedd,

1
Potresti riuscire a cavartela con solo due raggi ai lati del cerchio perpendicolare al movimento, quindi puoi vedere quali tessere vengono colpite dai raggi e puoi controllare il resto per vedere se i loro centri cadono tra i due raggi. Le uniche cose che dovrebbero mancare sarebbero le cose che si scontrano all'inizio o alla fine del cerchio, ma sono solo due cerchi e possono essere gestiti facilmente. Potrebbe essere un po 'più lento di otto raggi, non ne sono certo; ma non dovrai ridimensionare il numero in base alla dimensione del cerchio.
Lunin,

1

Non sto dicendo che questa sia un'analogia perfetta, ma potresti pensare all'algoritmo di linea di Bresenham . Una modifica di questo algoritmo o di una delle sue estensioni potrebbe essere utile, specialmente se lo abbini ad alcuni degli altri post e commenti. In genere, questo algoritmo non si occupa dell'ordinamento, ma penso che saresti in grado di aggiungerlo abbastanza banalmente.


Ci stavo anche pensando, ma secondo me non è l'algoritmo giusto. Bresenham sceglie solo un pixel, ha bisogno di tutto. E sarebbe difficile adattare bresenham al cerchio di un solo pixel.
Zacharmarz,

Il ray tracciante che uso è in realtà un po 'basato sull'algoritmo di Bresenham. Ho difficoltà a generalizzarlo da una linea sottile a una "grassa", specificamente spazzata dal cerchio.
Nevermind,
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.