Question

Dans un jeu, de nombreuses entités devraient être mis à jour chaque image. Im jouant avec des modèles de conception différents pour y parvenir. Jusqu'à présent, Ive a eu une classe de gestionnaire singleton auquel chaque instance Logic est ajouté. Mais Im considérant ce qui suit, une liste statique dans la classe logique elle-même. C'est agréable car il supprimerait une classe du projet. « Moteur » dans cet exemple serait la classe maître d'appeler le update_all.

class Logic
{
public:
    Logic() { all.push_back(this); }
    virtual ~Logic() { all.erase(this); }
    virtual void update(float deltatime) = 0;

private:
    friend Engine;
    static std::list<Logic*> all;
    static void update_all(float deltatime)
    {
        for (std::list::iterator i = all.begin(); i!=all.end(); ++i)
            (*i)->update(deltatime);
    }
};
  • Est-ce que ce modèle a un nom?
  • Estimez-vous que cette approche plus agréable qu'une classe de gestionnaire singleton?
  • Autres commentaires ou mises en garde?
Était-ce utile?

La solution

D'abord, vous devez utiliser au lieu de remove() erase() (ce dernier aurait besoin d'un itérateur comme argument)

Si vous utilisez une boucle légèrement différente comme

std::list<Logic*>::iterator it = all.begin();
while (it != all.end()) {
  Logic* current = *it;
  ++it;
  current->update(deltatime);
}

vous pouvez même régler le problème siukurnin mentionné (suppression d'un objet logique lors de la mise à jour ()). N'invalide list::remove() itérateurs sauf ceux pointant vers l'élément enlevé.

En dehors de cela, je vote aussi pour ce qui est une variante du modèle singleton. Et je suggère de maintenir la solution originale avec une classe de gestion séparée, juste au cas où vous voulez avoir deux boucles avec des temps de delta ou de soutien multithread explicite (différents objets logiques sur différents threads) ou tout autre à l'avenir.

est à mon avis un avantage général de la classe singleton par rapport aux méthodes statiques (que vous pouvez toujours utiliser): Vous pouvez facilement multiplier votre fonctionnalité si vous voulez faire à l'avenir ...

Autres conseils

Vous pouvez également utiliser modèle d'observateur pour cette

Je pense que toujours un singleton: « il ne peut y avoir qu'un seul »

Le singleton est un modèle, un concept: vous pouvez la mettre en œuvre différentes manières ...

Un membre de classe statique ou une instance globale sont deux implémentations possibles de la même idée.

La question est: pourquoi voulez-vous changer

?

Imho, il est un modèle d'observateur (cfr l'appel à tous les abonnés update), dans lequel le sujet se trouve être un Singleton.

La « mise en garde » désenregistrer en mettant à jour les observateurs est dur. Je me suis retrouvé aux prises avec plusieurs fois.

Une solution élégante à ce problème a été insinué dans cette réponse sur ma question à ce sujet: pour chaque observateur, ajoutez un intermédiaire « proxy » contenant un pointeur vers l'observateur « réel ». Désenregistrement est alors équivalent à la permutation (atomiquement) le pointeur du proxy. Après la mise à jour, toutes les procurations avec des pointeurs nuls peuvent être supprimés en toute sécurité.

En général, vous voulez passer par toutes les entités dans votre jeu chaque appel de mise à jour, vous pouvez donc aller de l'avant et d'utiliser un modèle composite où vous auriez un nœud racine. De là, vous iriez récursive par le noeud et appelez chaque méthode entité » mise à jour (). D'après ce que je peux voir à partir de votre code, vous avez déjà une liste, mais en utilisant le motif composite, vous seriez en mesure de faire des groupes d'entités à la place, ce qui pourrait simplifier la tâche.

D'après ce que je comprends, votre moteur tout simplement besoin d'appeler la méthode du nœud racine (si vous utilisez un motif composite) Update (). De là, le nœud racine appellera nœud suivant à l'aide de leur mise à jour (). À un certain moment à travers l'arbre composite, vous atteindrez qui leafs savent se mettre à jour correctement.

Vous aurez seulement besoin d'avoir un pointeur vers votre noeud racine dans votre moteur qui aura un UpdateAll de fonction () (ou autre) qui sera ensuite appeler rootNode-> Mise à jour (); qui à son tour, fera ce que je l'ai décrit dans le paragraphe précédent.

Une mise en garde serait que ce modèle (actuellement) ne marche pas permettre à des instances de logique à supprimer lors de l'appel à update_all, car il invaliderait le pointeur iterator.

Une solution pourrait être peut-être faire la mise à jour privée et de laisser destructor retourner un drapeau indiquant si l'instance doit être supprimé ou non?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top