Problema dei pool di componenti di elaborazione - Sottosistema entità


8

Descrizione dell'architettura

Sto creando (progettando) un sistema di entità e ho riscontrato molti problemi. Sto cercando di mantenerlo il più possibile orientato ai dati ed efficiente. I miei componenti sono strutture POD (array di byte per la precisione) allocate in pool omogenei. Ogni pool ha un ComponentDescriptor: contiene solo il nome del componente, i tipi di campo e i nomi dei campi.

L'entità è solo un puntatore all'array di componenti (dove l'indirizzo si comporta come un ID entità). EntityPrototype contiene il nome dell'entità e la matrice dei nomi dei componenti. Infine sottosistema (sistema o processore) che funziona su pool di componenti.

Problema reale

Il problema è che alcuni componenti dipendono da altri (Modello, Sprite, PhysicalBody, Animazione dipende dal componente Trasforma), il che crea molti problemi quando si tratta di elaborarli.

For example, lets define some entities using [S]prite, [P]hysicalBody and [H]ealth:
Tank:   Transform, Sprite, PhysicalBody
BgTree: Transform, Sprite
House:  Transform, Sprite, Health

and create 4 Tanks, 5 BgTrees and 2 Houses and my pools will look like:

TTTTTTTTTTT // Transform pool
SSSSSSSSSSS // Sprite pool
PPPP        // PhysicalBody pool
HH          // Health component

Non è possibile elaborarli utilizzando gli indici. Passo 3 giorni a lavorarci e ancora non ho idee. Nei progetti precedenti TransformComponent era legato all'entità, ma non era una buona idea. Potete darmi qualche consiglio su come elaborarli? O forse dovrei cambiare il design generale? Forse dovrei creare pool di entità (pool di pool di componenti), ma suppongo che sarà un incubo per le cache della CPU.

Grazie


Multiplayer? (È rilevante)
Jonathan Dickinson,

Risposte:


2

Disclaimer: andare semplicemente al di fuori delle mie conoscenze di classe sui sistemi.

Inizialmente pensavo, perché non usare semplicemente una funzione hash sull'ID entità per il tuo indice?

In questo modo otterresti

T[A]nk:   Transform, Sprite, PhysicalBody
B[G]Tree: Transform, Sprite
H[O]use:  Transform, Sprite, Health

and create 4 Tanks, 5 BgTrees and 2 Houses and my pools will look like:

OGAGAGGOGGG // Entity pool (letters corresopnding to entity type)
TTTTTTTTTTT // Transform pool
SSSSSSSSSSS // Sprite pool
P P P  P    // PhysicalBody pool
H      H    // Health component

O comunque erano le entità a essere posizionate. È possibile disporre di pool per tutti i componenti e per le entità e utilizzare il pool di entità come "master", in modo tale che le collisioni vengano verificate sulla matrice di entità. Ma ovviamente hai il problema del riciclaggio di componenti ed entità.

Se il design del tuo gioco lo consente, puoi pianificare in anticipo dove va ogni tipo di entità in modo da ottenere l'imballaggio più efficiente possibile. Supponiamo che le entità 0-20 siano riservate ai carri armati, le entità 21-30 per le case e 31-60 per BGTrees. Potresti non essere in grado di generare in modo efficiente infiniti baddos e un po 'sconfigge il dinamismo dei sistemi componenti, ma risolverebbe il problema. Non vedo un modo per avere la tua torta e mangiarla.

Stavo pensando a modi per accelerare forse il passaggio di rendering in cui hai un file RenderingComponentche contiene tutti i dati di cui il sistema di rendering ha bisogno, quindi è in grado di passare attraverso una serie di queste cose, ma poi c'è un sovraccarico di copia dei dati. Inoltre, ogni volta che fai riferimento a un puntatore stai pensando se è ancora nella cache.

Se vuoi un gioco super veloce, direi di pianificare la tua assegnazione. Se desideri un'architettura di gioco flessibile, implementa gli hashtable e gli ID stringa. Ogni volta che si desidera flessibilità, è necessario creare l'astrazione, e quindi dovrà sostenere spese generali.

TL; DR;
Sulla base di ciò che hai descritto, creerei un livello superiore RenderComponentcon puntatori Spritee Transformcomponenti e gli darei i riferimenti necessari quando inizializzi l'entità.

(Chiedo scusa per qualsiasi sconclusione percepita, ci ho pensato anche nel mio sistema, quindi questa è stata un'opportunità per pensarci)


Non so se le mappe hash siano così efficaci. Voglio avere un sistema di entità in cui i sottosistemi contengano funzioni DOD come: void update(u32 n, PhysicalBodyComponents* bodys, Transform* transforms)Voglio lavorare su molti input e dividere questa funzione su più core. È possibile con hashmaps?
mani3xis

Gli hashaps sono semplicemente un modo per identificare le relazioni tra entità e componenti. Questo dipende da come è impostato il tuo gioco, ma non vedo un modo efficiente per garantire che il tuo bodyse l' transformsarray si allineeranno. Questo è solo qualcosa su cui non puoi aggirare senza aggiungere uno strato di astrazione o pianificare la tua allocazione. Sento di non avere le competenze per parlare di ridimensionamento su più core. Forse trovare una domanda su threading e ridimensionamento o scrivere il proprio.
michael.bartnett,

Il ridimensionamento è semplice quando le funzioni funzionano su array lineari: posso impostare un intervallo per ciascun core ed eseguirlo. Ecco perché sto cercando di evitare gli hashmaps. Proverò a ridisegnare questo sistema di entità. Devo stare molto attento con i caches misses - PS2 ha una RAM molto limitata, ecc. BTW: Niente è impossibile :)
mani3xis

Niente è impossibile, ma non tutto è fattibile;). Puoi cercare semplicità ed eleganza nell'implementazione, velocità di esecuzione e consumo di memoria: scegli due. Quando trovi la tua soluzione, ti preghiamo di pubblicarla come risposta. Sono certo che non sono l'unico a cui piacerebbe vederla.
michael.bartnett,
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.