Afin d'obtenir des composants pour pouvoir mettre à jour chaque trame (et laisser cette fonctionnalité hors des composants qui n'en ont pas besoin), j'ai eu l'idée de créer un composant UpdateComponent. D'autres composants comme MovableComponent
(qui détient la vitesse) hériteraient de la IUpdatable
classe abstraite. Cela oblige MovableComponent
à implémenter une Update(gametime dt)
méthode et une autre RegisterWithUpdater()
qui donne UpdateComponent
un pointeur vers le MovableComponent
. De nombreux composants pourraient le faire et UpdateComponent
pourraient ensuite appeler toutes leurs Update(gametime dt)
méthodes sans avoir à se soucier de qui ou de ce qu'ils sont.
Mes questions sont:
- Cela semble-t-il quelque chose de normal ou utilisé par quelqu'un? Je ne trouve rien sur le sujet.
- Comment pourrais-je maintenir l'ordre des composants comme la physique puis changer de position? Est-ce même nécessaire?
- Quels sont les autres moyens de garantir que les composants qui doivent être traités à chaque image sont effectivement traités?
EDIT
Je pense que je vais réfléchir à la façon de donner au gestionnaire d'entités une liste de types pouvant être mis à jour. Ensuite, TOUS les composants de ce type peuvent être mis à jour plutôt que gérés par entité (qui ne sont de toute façon que des index dans mon système).
Encore. Mes questions restent valables pour moi. Je ne sais pas si c'est raisonnable / normal, ou ce que les autres ont tendance à faire.
De plus, les gens d' Insomniac sont géniaux! /ÉDITER
Code réduit pour l'exemple précédent:
class IUpdatable
{
public:
virtual void Update(float dt) = 0;
protected:
virtual void RegisterAsUpdatable() = 0;
};
class Component
{
...
};
class MovableComponent: public Component, public IUpdatable
{
public:
...
virtual void Update(float dt);
private:
...
virtual void RegisterWithUpdater();
};
class UpdateComponent: public Component
{
public:
...
void UpdateAll();
void RegisterUpdatable(Component* component);
void RemoveUpdatable(Component* component);
private:
...
std::set<Component*> updatables_;
};
la source
Réponses:
L'un des principaux avantages d'un système de composants est la possibilité de tirer parti des modèles de mise en cache - bonne icache et prédiction car vous exécutez le même code plusieurs fois, bon dcache car vous pouvez allouer les objets dans des pools homogènes et parce que les vtables, si tout, restez au chaud.
De la façon dont vous avez structuré vos composants, cet avantage disparaît complètement et peut en fait devenir un handicap de performance par rapport à un système basé sur l'héritage, car vous effectuez beaucoup plus d'appels virtuels et plus d'objets avec vtables.
Ce que vous devez faire est de stocker des pools par type et d'itérer chaque type indépendamment pour effectuer des mises à jour.
Ce n'est pas aussi courant dans les grands jeux car ce n'est pas avantageux. C'est courant dans de nombreux jeux, mais ce n'est pas techniquement intéressant, donc personne n'écrit à ce sujet.
Le code dans des langages comme C ++ a un moyen naturel pour ordonner l'exécution: tapez les instructions dans cet ordre.
En réalité, cela n'a pas de sens car aucun système physique robuste n'est structuré de cette façon - vous ne pouvez pas mettre à jour un seul objet physique. Au lieu de cela, le code ressemblerait davantage à:
la source
Je pense que ce dont vous parlez est raisonnable et assez courant. Cela pourrait vous donner plus d'informations.
la source
J'aime ces approches:
En bref: évitez de conserver le comportement de mise à jour dans les composants. Les composants ne sont pas un comportement. Le comportement (y compris les mises à jour) peut être implémenté dans certains sous-systèmes à instance unique. Cette approche pourrait également aider à traiter par lots des comportements similaires pour plusieurs composants (peut-être en utilisant les instructions parallel_for ou SIMD sur les données des composants).
L'idée IUpdatable et la méthode Update (gametime dt) semblent un peu trop restrictives et introduisent des dépendances supplémentaires. Cela peut être bien si vous n'utilisez pas l'approche des sous-systèmes, mais si vous les utilisez, IUpdatable est un niveau de hiérarchie redondant. Après tout, le MovingSystem doit savoir qu'il doit mettre à jour les composants Location et / ou Velocity directement pour toutes les entités qui ont ces composants, il n'y a donc pas besoin d'un composant IUpdatable intermédiaire.
Mais vous pouvez utiliser le composant Updatable comme mécanisme pour ignorer la mise à jour de certaines entités bien qu'elles aient des composants Location et / ou Velocity. Le composant Updatable pourrait avoir un indicateur booléen qui peut être défini
false
et qui signalerait à chaque sous-système prenant en charge Updatable que cette entité particulière ne devrait actuellement pas être mise à jour (bien que dans un tel contexte, Freezable semble être le nom le plus approprié pour le composant).la source