ECS? Je vais en fait suggérer qu'il n'est peut-être pas prématuré, si c'est le cas, de réfléchir beaucoup au côté orienté données de la conception et de comparer les différents représentants, car cela pourrait avoir un impact sur vos conceptions d'interface , et ce dernier est très coûteux à modifier tard dans la le jeu. De plus, ECS exige juste beaucoup de travail et de réflexion en amont et je pense que cela vaut la peine d'utiliser une partie de ce temps pour vous assurer que cela ne vous causera pas de problèmes de performances au niveau de la conception plus loin étant donné la façon dont cela va être au cœur de votre tout le moteur flippant. Cette partie me regarde:
unordered_map<string,[yada]>
Même avec de petites optimisations de chaînes, vous avez un conteneur de taille variable (chaînes) à l'intérieur d'un autre conteneur de taille variable (unordered_maps). En fait, les petites optimisations de chaînes pourraient être aussi nuisibles qu'utiles dans ce cas si votre table est très clairsemée, car l'optimisation de petites chaînes impliquerait que chaque index inutilisé de la table de hachage utilisera toujours plus de mémoire pour l'optimisation SS ( sizeof(string)
serait être beaucoup plus grande) au point où la surcharge de mémoire totale de votre table de hachage peut coûter plus cher que tout ce que vous y stockez, en particulier si c'est un composant simple comme un composant de position, en plus d'engendrer plus de ratés de cache avec l'énorme foulée pour passer d'une entrée de la table de hachage à la suivante.
Je suppose que la chaîne est une sorte de clé, comme un ID de composant. Si c'est le cas, cela rend déjà les choses considérablement moins chères:
unordered_map<int,[yada]>
... si vous voulez avoir les avantages d'avoir des noms conviviaux que les scripteurs peuvent utiliser, par exemple, alors les chaînes internes peuvent vous donner le meilleur des deux mondes ici.
Cela dit, si vous pouvez mapper la chaîne à une plage raisonnablement faible d'indices densément utilisés, vous pourrez peut-être le faire:
vector<[yada]> // the index and key become one and the same
La raison pour laquelle je ne considère pas cela prématuré est que, encore une fois, cela pourrait avoir un impact sur la conception de votre interface. Le but du DOD ne devrait pas être d'essayer de proposer les représentations de données les plus efficaces imaginables en une seule fois IMO (qui devraient généralement être réalisées de manière itérative si nécessaire), mais de les penser suffisamment pour concevoir des interfaces sur le dessus pour travailler avec cela. des données qui vous laissent suffisamment de marge de manœuvre pour profiler et optimiser sans modifier la conception en cascade.
À titre d'exemple naïf, un logiciel de traitement vidéo qui couple tout son code à cela:
// 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() {}
...
};
Ne va pas loin sans une réécriture potentiellement épique, car l'idée d'abstraire au niveau d'un seul pixel est déjà extrêmement inefficace ( vptr
elle - même coûterait souvent plus de mémoire que le pixel entier) par rapport à l'abstrait au niveau de l' image (ce qui représentent souvent des millions de pixels). Donc, réfléchissez suffisamment à vos représentations de données à l'avance pour ne pas avoir à faire face à un tel scénario de cauchemar, et idéalement pas plus, mais ici, je pense que cela vaut la peine de penser à ce genre de choses dès le départ car vous ne voulez pas construire un moteur complexe autour de votre ECS et constatez que l'ECS lui-même est le goulot d'étranglement d'une manière qui vous oblige à changer les choses au niveau de la conception.
En ce qui concerne les échecs de cache ECS, à mon avis, les développeurs s'efforcent souvent trop de rendre leur cache ECS convivial. Cela commence à céder trop peu pour que l'argent essaie d'accéder à tous vos composants de manière parfaitement contiguë, et impliquera souvent de copier et de mélanger les données partout. Il est généralement suffisant, par exemple, de simplement trier les index des composants avant de les accéder afin que vous y accédiez de manière à ne pas charger au moins une région de mémoire dans une ligne de cache, uniquement pour l'expulser, puis charger tout à nouveau dans la même boucle juste pour accéder à une partie différente de la même ligne de cache. Et un ECS n'a pas à fournir une efficacité incroyable à tous les niveaux. Ce n'est pas comme si un système d'entrée en bénéficiait autant qu'un système de physique ou de rendu, je recommande donc de viser «bon» efficacité à tous les niveaux et "excellente" seulement là où vous en avez vraiment besoin. Cela dit, l'utilisation deunordered_map
et string
voici assez facile à éviter.