Come progettare una classe per verificare se le figure geometriche si scontrano?

5

Sto facendo un gioco di base con figure geometriche.

Sto provando a progettare ora come calcolare se la figura collide con un'altra figura in un elenco di figure di array (chiamato entitiesList ).

Ho:

Class Entity {
   ...
   public boolean collidesWith(Entity anotherEntityInMap) {}
}

Ma non riesco a capire come dovrei farlo. Immagino di dover sapere che tipo di figura è anotherEntity . Ad esempio, posso avere quadrati, triangoli e cerchi. Ogni figura ha calcoli diversi e deve essere astratta.

    
posta JorgeeFG 05.06.2015 - 17:08
fonte

3 risposte

4

Il modo più accademicamente corretto per farlo sarebbe quello di avere una matrice bidimensionale di metodi di rilevamento delle collisioni, un metodo per ogni possibile coppia di figure, quindi ogni metodo dovrebbe conoscere esattamente quali sono le figure che vengono controllate, così come fare il controllo nel miglior modo possibile Sfortunatamente, questo è troppo lavoro per pochissimi benefici.

Il modo più veloce, più sporco, più semplice, più pericoloso e più impreciso per farlo sarebbe trattare tutte le forme allo stesso modo, considerarle tutte come cerchi, e basta controllare la distanza tra i loro punti centrali per determinare se si scontrano.

Una soluzione pratica che non è troppo difficile da implementare e fornisce risultati accurati consiste nel fare in modo che ogni forma contenga una rappresentazione poligonale di se stessa e semplicemente utilizzare un singolo algoritmo di rilevamento di collisione poligonale per rilevare la collisione tra le rappresentazioni poligonali di due forme.

    
risposta data 05.06.2015 - 17:26
fonte
1
  1. In primo luogo, puoi racchiudere una logica comune in tutte le forme.

    1. Cerca di vedere se gli oggetti si scontrano in base al loro AABB ; tutte le forme implementano getAABB() .
    2. Puoi anche chiamare getBoundingBox() o getBoundingSphere() prima di provare a verificare se si intersecano realmente.
  2. Quanto sopra dovrebbe consentire di filtrare rapidamente tutte le forme che certamente non collidono (le caselle di delimitazione sono sovrarappresentazioni delle forme). Ma se restano entità per le quali si sovrappongono le approssimazioni, non si può essere sicuri che esse scontrino non e tu debba essere più preciso. Puoi implementare il doppio invio:

    • In genere, questo viene fatto utilizzando un visitatore .
    • Ogni forma, Rectangle , Circle implementa collideWithRectangle , collideWithCircle e così via ...
    • Vuoi evitare di ripetere te stesso, quindi se implementi un test per Rectangle rispetto a Circle , puoi invertire gli argomenti quando controlli la collisione tra Circle e Rectangle e chiama il metodo esistente.
    • Le entità complesse sono per lo più facilmente rappresentate da un'unione di forme più semplici, ma puoi anche usare poligoni arbitrari.
risposta data 05.06.2015 - 17:29
fonte
1

Il commento di Robert Harvey sull'emissione di un cerchio dal centro per approssimare la forma era buono. In alternativa puoi usare rettangoli / triangoli su una superficie 2D, come nel gioco, o un prisma rettangolare / equivalente triangolare in un ambiente 3D. Puoi anche dividere ciascuna delle tue forme in una raccolta di queste forme più piccole per approssimare la forma reale su una scala più fine (usando forme ellittiche o con bordi dritti), e questo è fondamentalmente il modo in cui un sacco di giochi pesanti per CPU funzionano nel modo più efficiente lo fanno.

Detto questo, potresti far sì che tutti questi oggetti estendano la stessa classe base. Quindi in quella classe, ci sarebbe un metodo / proprietà overridable chiamato getCollisionComponentShapes , che restituirebbe un array o ArrayList delle forme. Queste sarebbero le forme ellittiche, i rettangoli e / oi triangoli menzionati in precedenza che verrebbero usati per approssimare il poligono. Ciò riduce tutto, diciamo, a tre funzioni, assumendo che tu ti limiti a seguire le forme a bordi rettilinei:

detectCollisionReRe(pRect1:Rectangle, pRect2:Rectangle):Boolean
detectCollisionReTr(pRect1:Rectangle, pTri2:Triangle):Boolean
detectCollisionTrTr(pTri1:Triangle, pTri2:Triangle):Boolean

Quindi nella tua classe base, ci sarebbe un metodo presumibilmente statico:

detectCollisionShapes(pBaseClassRef1:BaseClass, pBaseClassRef2:BaseClass):Boolean

e questo dovrebbe solo scorrere attraverso le forme di collisione di ogni istanza ed eseguire una delle tre funzioni sopra per ciascuna combinazione.

Questo sarebbe un grande modo per gestire il caso generale. Nel tuo gioco di geometria, consiglierei di andare avanti e di usare una sorta di forma ellittica generica con curvatura variabile per i tuoi componenti, oltre a rettangoli e triangoli. Anche con la curvatura variabile, puoi utilizzare la matematica a livello di secondo livello e questo porterà solo l'elenco fino a sei funzioni.

Come nota a margine, probabilmente non avresti bisogno di questo nel tuo gioco, ma se stavi progettando un gioco AAA, potrebbe essere utile cercare modi per memorizzare i risultati e tagliare gli angoli in altri modi.

    
risposta data 05.06.2015 - 17:47
fonte

Leggi altre domande sui tag