Entity Component System - Come implementare la trasformazione di un oggetto?


11

Nel progettare un sistema di componenti entità per il mio motore, mi sono imbattuto in un piccolo ostacolo nel modo di memorizzare e recuperare un particolare tipo di componente.

Prima di tutto, lasciami chiarire un po 'di terminologia che userò in questa domanda:

  • Chiamo " Component " una struttura di dati che memorizza i dati rilevanti per un determinato sistema.
  • Chiamo " Sistema " un'aggregazione di metodi e strutture di dati che utilizza Componenti per aggiornare lo stato / l'interfaccia del gioco con l'utente.
  • Un " Entity " è fondamentalmente solo un ID utilizzato per recuperare componenti specifici e modificare i loro dati nella logica di gioco.

Ogni sistema possiede un array (mappato ID) del suo tipo di Componente (es. Fisica-> PhysicsComponent, AI-> AIComponent, Rendering-> RenderingComponent), in modo che possa iterare efficacemente sui dati.

Tuttavia, non tutti i componenti sono specificamente di proprietà di un sistema. Ad esempio, un componente Trasforma memorizza la posizione, la rotazione e la scala di un oggetto. È una delle parti più importanti di un'entità (Unity lo rende obbligatorio, anche), poiché viene utilizzato da molti sistemi, ad esempio Fisica, AI, Rendering, ecc.

Questo è praticamente il problema che sto affrontando. Poiché Transform è utilizzato da molti altri sistemi, come devo fare per recuperarne uno da utilizzare per ciascun componente? Una possibile soluzione che vedo è quella di fare in modo che ciascun componente memorizzi il proprio ID entità. Sarebbe facile recuperare qualsiasi componente come questo, ma non sarebbe così efficiente e andrebbe anche contro il concetto di un Componente come un insieme isolato e indipendente di dati, che non è a conoscenza di nessun altro.

C'è un modo corretto per risolvere questo problema? Transform dovrebbe anche essere un componente?


3
+1 per "In primo luogo, vorrei chiarire un po 'di terminologia che userò in questa domanda:"
Vaillancourt

Mi piacerebbe vedere questo tipo di domande più in questo sito. +1
S. Tarık Çetin

Memorizza tutti i componenti come variabili globali
Miles Rout

Risposte:


2

Questa è una domanda piuttosto ampia, la cui risposta dipende fortemente dalla tua architettura. Cercherò comunque di darti una risposta generale.

I tuoi sistemi fisici e di rendering richiederanno sicuramente la trasformazione, tuttavia il sistema AI non lo farà. Pertanto, ha senso incapsulare la trasformazione nella propria classe componente. Tutti questi sistemi interessati utilizzerebbero gli stessi dati, quindi ha senso che l'entità abbia un puntatore all'oggetto di trasformazione o un ID per un oggetto di trasformazione memorizzato altrove.

Se si sceglie quest'ultima soluzione, ogni sistema interessato a una trasformazione richiederà l'accesso a qualsiasi oggetto di trasformazione memorizzato.

Se scegli il primo, tutto ciò che ciascun sistema deve fare è accedere all'entità stessa e richiedere la trasformazione.

Nel primo caso, il problema diventa come concedere l'accesso alla memoria per le trasformazioni di ciascun sistema, senza infrangere le regole OOP, se ti interessano tali cose.

Quest'ultimo caso non presenta tali problemi, ma richiede la modifica della progettazione dell'oggetto entità per memorizzare i puntatori sugli oggetti anziché gli ID degli oggetti componenti.

La mia preferenza personale è quella di progettare la classe di entità per memorizzare i puntatori agli oggetti componenti, poiché semplifica molti problemi di progettazione. In questo modo, ogni sistema che richiede una trasformazione può richiederlo all'entità e ignorarlo se non lo fa. Tuttavia, questo comporta un sovraccarico computazionale inerente ai puntatori, che rappresenta il costo dei cache mancati.

Dai un'occhiata a questa panoramica ECS per ulteriori informazioni al riguardo.

Alla fine della giornata, spetta a te decidere quale è più importante per te: facilità di sviluppo o prestazioni.

Vorrei sottolineare, infine, che la tua domanda è un eccellente esempio delle domande di progettazione a cui pensano i sostenitori di ECS e che non esiste una soluzione definitiva per i proiettili d'argento.


Grazie per i vostri suggerimenti. Ho una domanda, però: perché il sistema di intelligenza artificiale non dovrebbe avere la posizione di un oggetto?
CRefice

Stai confondendo la posizione (vettore di 3 float) con una traduzione (trasforma la matrice costruita da un vettore di posizione). Una matrice di trasformazione è costruita da trasformazioni di traslazione, rotazione e scala. Queste sono molte più informazioni di quelle di cui un sistema di intelligenza artificiale avrebbe bisogno, sebbene tu possa certamente estrarre il vettore di posizione da esso. Personalmente, avrei separato posizione, orientamento e dimensioni nel loro componente e li avrei usati per creare e aggiornare la Trasformazione.
Ian Young,

@IanYoung Separarli potrebbe fare più male che bene, potenzialmente se trovi che hai bisogno di posizione e orientamento insieme più spesso di quanto tu faccia o orientamento separatamente. In tal caso, l'inserimento degli attributi dei dati di posizione e orientamento in un singolo componente può migliorare le prestazioni della cache.
Naros,

1
La mia preferenza è quella di combinare tutti e tre, posizione, orientamento e scala in un singolo componente e nei casi in cui uno specifico subsystsem richiede solo una posizione o un orientamento, raccomanderei di duplicare i dati e sincronizzarli in punti chiaramente definiti nel loop del gioco .
Naros,

@Naros sì, questo è ciò che intendevo: due componenti, Transform e (nel mio framework) SpatialData, che contiene posizione, velocità, orientamento e velocità angolare. La posizione e l'orientamento vengono utilizzati per costruire e aggiornare la trasformazione.
Ian Young,
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.