Come gestire correttamente la collisione in un gioco basato su componenti?


11

Cercando di avvolgere la mia testa intorno ai modi per gestire correttamente la collisione in un gioco progettato attorno ai componenti.

Vedo che molti esempi hanno una sorta di PhysicsComponentaggiunta all'elenco dei componenti dell'entità, ma l'implementazione effettiva mi sta confondendo.

Perché questo funzioni, PhysicsComponentdovrebbe avere accesso al mondo che lo circonda. Questo non ha senso intuitivo per me. Un componente non dovrebbe ignorare non solo il suo contenitore (l'entità), ma il contenitore del suo contenitore (il mondo)?

Per me, sembra che il livello o la scena debba mantenere un elenco di queste entità e ogni aggiornamento del gioco, scorrere tra le entità per determinare quale scontro.

La mia domanda è innanzitutto se questo è un buon progetto e, in secondo luogo, come determinare quali entità possono scontrarsi. Suppongo che entità solide possano implementare un'interfaccia IRigidBody vuota in modo che il livello possa determinare quali entità nell'elenco supportano la collisione. Ma questo sta rompendo il design dei componenti?

Invece, dovrebbero contenere un componente RigidBody vuoto? Questo potrebbe effettivamente essere migliore perché potrebbe non essere sempre vuoto e questo approccio è più a prova di futuro. L'unico problema è la complessità. La scena dovrebbe scorrere non solo tutte le entità, ma anche i componenti di ogni entità per determinare se avesse questo componente RigidBody.

In terzo luogo, quando si scontrano, entrambe le entità dovrebbero essere informate in qualche modo e non sono sicuro su come farlo.

Supponiamo che entrambe le entità contenessero un componente sanitario e quando si scontrassero entrambe le loro condizioni di salute sarebbero diminuite di un valore arbitrario, 5. Suppongo che sarebbe responsabilità della scena gestirlo quando rileva una collisione tra due entità?

Ma allora la scena è responsabile di troppo? Potrei vederlo sfuggire di mano e diventare ingombrante quando la scena è responsabile di molte cose a cui le entità non dovrebbero (?) Avere accesso.

Modifica: domanda aggiornata con maggiori dettagli.


4
Questa risposta sembra appropriata per il collegamento a: gamedev.stackexchange.com/questions/13797/…
Andrew Russell,

La risposta collegata di Andrew, la risposta di James e la risposta di Nick Wiggill meritano tutti +1. Pensa ai componenti più come dati che come una classe tipica con dati e metodi (non che non disporranno di metodi, ma non dovrebbero avere molta responsabilità). Guarda il sistema di componenti Artemis ( piemaster.net/2011/07/entity-component-artemis ) per un esempio di un buon framework di componenti.
michael.bartnett,

Risposte:


5

Onestamente, dal punto di vista della progettazione dei componenti, i miei componenti non si conoscono a meno che non debbano farlo (e questo è molto raro). Anche allora di solito preferisco che i componenti parlino direttamente con alcuni sistemi di gestione di tali componenti anziché con i componenti. (L'interfaccia di scripting sembra il suo oggetto da obiettare, ma non è nel motore reale, hehe).

A tal fine mi schiererei con quello che hai detto per la prima volta e andrei con componenti di fisica che esistono ovunque gli oggetti debbano essere testati per la loro collisione. Ora chiaramente questi oggetti potrebbero dover informare altri componenti di se stessi sulla risoluzione delle collisioni ma, come detto, è qui che preferisco l'evento stesso solo per uscire agli oggetti attraverso un'altra interfaccia (o un manager o un sistema di messaggistica degli eventi se ne hai uno per esempio).

Penso che tu sia sulla buona strada e hai solo bisogno di più di un "Sì, suona bene" Quindi ... Sì, suona bene.

Spero che sia di aiuto!


3

Normalmente i motori di gioco utilizzano una libreria di terze parti per rilevare le collisioni tra entità. In quello scenario si creano o registrano quelle entità che hanno il Componente Fisica nel mondo della "fisica". E ogni volta che rileva una collisione tra due entità (A e B), normalmente chiamerebbe un richiamo all'entità A informando che si è scontrato con l'entità B e lo stesso per l'entità B, informando che si è scontrato con l'entità A.

Per 2D, una nota libreria di fisica libera è Box2D. Vale anche la pena dare un'occhiata a Chipmunk. Per 3D, Bullet è gratuito (probabilmente il migliore gratuito che puoi trovare). Havok e PhysX sono famosi per essere utilizzati in molti giochi A tripli.


2

Il problema che stai riscontrando è vedere che il rilevamento delle collisioni (che è l'unica ragione per cui avresti bisogno di un'entità portatrice di componenti fisici per fare riferimento a un'altra di queste) viene fatto a un livello più alto, di solito o direttamente dal tuo circuito di gioco, o da una funzione / classe helper che lo fa. La mia risposta a qualcuno qualche settimana fa parla della rimozione di entità per motivi simili e tenendo presente che se una collisione provoca la distruzione di una delle tue entità, quella stessa risposta, nel suo contesto dato, sarà molto rilevante per te , poiché un "potere superiore" dovrà ancora gestire la pulizia dei corpi ... per così dire.

Fare nulla di tutto ciò solo tra entità non è generalmente praticabile. Esiste quasi sempre un proxy per tali cose, in un'architettura solida, sia tramite la gestione diretta come con il rilevamento delle collisioni, sia gli invii di eventi come ad es. un sistema di messaggistica per giocatori in cui un gestore di messaggistica lato client ascolta i messaggi inviati dai giocatori e li invia al server per essere ritrasmessi a tutti.


2

Ora sto affrontando esattamente lo stesso problema di te in un progetto. Il modo in cui ho deciso di affrontarlo è avere un "ColliderComponent" che trattiene il corpo dal motore fisico. I bodys sono definiti esternamente (definizioni di forma che vengono caricate in fase di esecuzione) e quindi aggiunti al mondo fisico e alle entità di gioco a cui appartengono.

Sto usando Box2D dove è possibile allegare un "listener di collisione" che verrà avvisato dalla collisione. Dato che aggiungo un puntatore al mio "ColliderComponent" ai dati dell'utente bodys, posso ottenere i miei due ColliderComponents che facevano parte della collisione.

Quindi la cosa che succede quando si verifica una collisione è la seguente: I componenti Collider che facevano parte della collisione invieranno un messaggio al loro oggetto proprietario (l'entità gioco) che a sua volta trasmetterà quel messaggio a tutti i suoi componenti.

Ogni componente può quindi reagire a quel messaggio, così il tuo "componente di salute" potrebbe rimuovere 5 punti dalla salute, ecc.


+1: sto usando un approccio molto simile. Come si determina l'entità del danno da causare in base al tipo di entità in collisione?
Den,

@Den invio diversi messaggi (o dati del messaggio) in base alla collisione avvenuta. Questo funziona bene per me, poiché non ho molti casi diversi da gestire.
Bummzack,

0

Creare un sistema di collisione che conosca il "mondo" di collisione. Quindi, nel componente di collisione, dire al sistema di collisione di lanciare un raggio dal punto A al punto B e rispondere in caso di collisione o meno.

In bocca al lupo. Trovo che il sistema di collisione sia una delle parti più noiose del motore di gioco.

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.