2010-07-24 5 views
6

Ich schreibe ein Spiel-Projekt als ein Hobby, und bin auf der Suche nach einigen architektonischen Ratschläge darüber, wie am besten meine Spielobjekte und ihre verschiedenen Animationen zu organisieren.Animation Architektur Muster

Zum Beispiel habe ich eine Klasse namens Wizard, und eine Klasse namens Dragon. Ein Wizard hat mindestens 10 verschiedene spezifische Animationen, abhängig von seinem Status, und die gleichen für Dragon.

Also meine Frage ist: Gibt es ein Standardmuster für diese Art von Objekten zu organisieren, so dass es effizient ist und leicht zu erweitern (das heißt es sollte einfach sein, neue hinzuzufügen Animationen und neue Objekte)?

Ich habe verschiedene Ideen darüber, wie man sich auf diesem zu bewegen, aber ich möchte nicht falsch bekommen, da es ein so wichtiger Teil der Spielarchitektur ist. Es scheint einfach, das für ein kleines Spiel zu bekommen, aber ich habe Angst vor unüberschaubarer Komplexität, da es größer wird.

+0

Stehlen Sie Ideen aus vorhandenen Open-Source-Spielen. –

+0

std :: map - für internen Status-zu-Animation-Speicher und jedes offene Format für externen Speicher. – W55tKQbuRu28Q4xv

Antwort

1

Ich schlage vor, eine Schnittstelle wie "Character" zu haben, die definiert, was alle diese Entitäten tun können. Dann sind Ihre Dragon- und Wizard-Klassen nur Implementierungen. Eine andere Route besteht darin, eine Basisklasse zu verwenden, von der aus Sie die "hierarchische Ausbreitung", die mit großen Projekten verbunden ist, erweitern und verwenden können, indem Sie eine Hierarchie Ihrer Objekte erstellen und erweiterte Basisklassen identifizieren.

0

Nein, es gibt absolut kein Standardmuster.

Mein Rat ist es, den Anfänger OO Design Fallstrick zu vermeiden, zu versuchen, eine einzige gemeinsame "Basisklasse" -Schnittstelle für alles zu finden. Dein Drache unterscheidet sich erheblich von deinem Zauberer, und es gibt nichts zu gewinnen, wenn du versuchst, die beiden Schnittstellen zusammenzuführen, außer niedlichen Code-Abstraktionen. Denken Sie daran, Vererbung ist kein Werkzeug für die Wiederverwendung von Code.

Der einfachste Ansatz besteht darin, dass jedes Objekt seinen eigenen internen Zustand (wie bereits beschrieben) beibehält und diesen Zustand zeichnen kann. Dies ist, wo eine Old School Switch-Anweisung Mai klarer sein kann als Polymorphie für den gleichen Effekt verwenden. Beispiel:

class Dragon { 
enum State { asleep, flying, breathing_fire }; 
public: 
void draw() { /* old-school switch */ 
    switch (cur_state){ 
    case asleep: draw_asleep(); 
    case flying: draw_flying(); 
    case breathing_fire: draw_breathing_fire(); 
    } 
    } 
private: 
    void draw_asleep(); 
    void draw_flying(); 
    void draw_breathing_fire(); 
}; 

Erfahrene C++ Entwickler bei dem obigen Code keuchen werden (wie sie sollen), da die Switch-Anweisung fast genau das, was ein polymorpher Methodenaufruf erreichen würde - Laufzeit Versand. (Oder noch kryptischer: eine Tabelle mit Methodenadressen.) Meine persönliche Meinung ist, dass für diesen speziellen Typ von Klasse, dh eine einzige öffentliche Schnittstelle, die eine Zustandsmaschine kapselt, die switch-Anweisung klarer und wartbarer ist, weil sie die Zustandsmaschine macht springe explizit. Ich denke, es ist auch klar, dass ich das im Allgemeinen schlechte C++ Design erkennen.

Die Reibung dieses Entwurfs wird durch die Trennlinie zwischen der Zustandsmaschine und der einzelnen öffentlichen Schnittstelle verursacht. Ein schlafender Drache ist eindeutig nicht der gleiche wie ein fliegender Drache. In der Tat wird es so gut wie nichts gemeinsam haben. Aber das höhere Design sagt, dass die beiden der gleiche Drache sind. Was für ein Chaos! Erstellen Sie für jeden Status verschiedene Dragon-Objekte? Nein, denn das würde dem Anrufer das Zustandskonzept offen legen. Erstellen Sie für jeden Status verschiedene interne Helper-Objekte und senden Sie diese an? Möglicherweise, aber es wird schnell unordentlich. Der obige Ansatz ist ein Kompromiss zwischen den beiden.Denken Sie an die switch statement, um die Hässlichkeit zu isolieren. Die öffentliche Schnittstelle ist sauber, ebenso wie die private Schnittstelle. Nur die switch-Anweisung enthält das schmutzige Chaos. Betrachten Sie diesen Ansatz und ziehen Sie auch andere Vorschläge in Betracht.

Schließlich Ihren Assistenten und Ihre Drachen, eine einfache Wrapper-Vorlage oder Funktors wird zu ziehen genügen:

struct Draw { 
    template <class S> 
    void operator()(S& s) { s.draw(); } 
}; 

Der Punkt ist, dass man nicht nur zwei verschiedene Klassen verschmelzen muß, weil sie sowohl die Unterstützung gleiche logische Operation.