ECS? In realtà suggerirò che potrebbe non essere prematuro se è così per riflettere molto sul lato orientato ai dati del design e confrontare diverse ripetizioni perché potrebbe avere un impatto sui progetti dell'interfaccia e quest'ultimo è molto costoso cambiare in ritardo il gioco. Inoltre, ECS richiede solo molto lavoro e pensato in anticipo e penso che valga la pena utilizzare un po 'di quel tempo per essere sicuro che non ti darà un peggioramento delle prestazioni a livello di progetto più in basso, dato come sarà al centro del tuo intero motore pazzesco. Questa parte mi abbaglia:
unordered_map<string,[yada]>
Anche con ottimizzazioni di stringhe di piccole dimensioni, è presente un contenitore di dimensioni variabili (stringhe) all'interno di un altro contenitore di dimensioni variabili (unordered_maps). In realtà, le piccole ottimizzazioni stringa potrebbe essere in realtà nocivo come utile in questo caso, se il tavolo è molto scarsa, dal momento che la piccola ottimizzazione stringa implicherebbe che ogni indice non utilizzata della tabella hash sarà ancora possibile utilizzare più memoria per l'ottimizzazione SS ( sizeof(string)
sarebbe essere molto più grande) al punto in cui il sovraccarico di memoria totale della tua tabella hash potrebbe costare di più di qualsiasi cosa tu stia memorizzando in esso, specialmente se si tratta di un componente semplice come un componente di posizione, oltre a incorrere in più mancate cache con il passo falso per passare da una voce nella tabella hash alla successiva.
Suppongo che la stringa sia una specie di chiave, come un ID componente. In tal caso, ciò rende già le cose notevolmente più economiche:
unordered_map<int,[yada]>
... se vuoi i vantaggi di poter avere nomi facili da usare che gli script possono usare, ad esempio, le stringhe internate possono darti il meglio di entrambi i mondi qui.
Detto questo, se riesci a mappare la stringa su un intervallo ragionevolmente basso di indici densamente usati, potresti essere in grado di farlo:
vector<[yada]> // the index and key become one and the same
Il motivo per cui non considero questo prematuro è perché, di nuovo, potrebbe influire sulla progettazione dell'interfaccia. Il punto di DOD non dovrebbe essere quello di cercare di fornire le rappresentazioni dei dati più efficienti che si possano immaginare in una volta IMO (che dovrebbero essere raggiunte in modo iterativo secondo necessità), ma di pensarci abbastanza per progettare interfacce in cima per lavorare con quello dati che ti lasciano abbastanza spazio per il profilo e l'ottimizzazione senza cambiamenti a cascata del design.
Ad esempio ingenuo, un software di elaborazione video che abbina tutto il suo codice a questo:
// Abstract pixel that could be concretely represented by
// RGB, BGR, RGBA, BGRA, 1-bit channels, 8-bit channels,
// 16-bit channels, 32-bit channels, grayscale, monochrome,
// etc. pixels.
class IPixel
{
public:
virtual ~IPixel() {}
...
};
Non andrà lontano senza una riscrittura potenzialmente epica, poiché l'idea di astrarre a livello di singolo pixel è già estremamente inefficiente (lo vptr
stesso costa spesso più memoria dell'intero pixel) rispetto all'astrazione a livello di immagine (che rappresentano spesso milioni di pixel). Quindi metti abbastanza in anticipo le tue rappresentazioni dei dati in modo da non dover affrontare uno scenario da incubo, e idealmente non più, ma qui penso che valga la pena pensare a questa roba in anticipo poiché non vuoi costruire un motore intricato intorno al tuo ECS e scopri che l'ECS stesso è il collo di bottiglia in modi che richiedono di cambiare le cose a livello di progettazione.
Per quanto riguarda gli errori della cache ECS, a mio avviso gli sviluppatori spesso si sforzano troppo per rendere la loro cache ECS compatibile. Comincia a dare troppo poco botto per il dollaro per provare ad accedere a tutti i tuoi componenti in modo perfettamente contiguo, e spesso implica la copia e lo shuffle dei dati ovunque. Di solito è abbastanza buono, per esempio, semplicemente radicare gli indici dei componenti prima di accedervi in modo da accedervi in un modo in cui almeno non si sta caricando una regione di memoria in una linea di cache, solo per sfrattarla e quindi caricare tutto di nuovo nello stesso loop solo per accedere a una parte diversa della stessa linea di cache. E un ECS non deve fornire un'efficienza straordinaria su tutta la linea. Non è che un sistema di input ne tragga vantaggio tanto quanto una fisica o un sistema di rendering, quindi consiglio di puntare a "bene" efficienza su tutta la linea e "eccellente" proprio nei luoghi in cui ne hai davvero bisogno. Detto questo, l'uso diunordered_map
e string
qui sono abbastanza facili da evitare.