2017-01-22 41 views
0

Ich entwerfe eine Game-Engine in C++. Ich arbeite gerade daran, die verschiedenen Entitäten im Spiel zu kategorisieren. Meine Basisklasse ist SpriteObject, von der zwei Klassen MovableObject und FixedObject erben. Nun, wenn ich zum Beispiel eine Instanz eines MovableObject erstellen und in einem Vektor von Sprite hinzufügen möchten, und einem Vektor von MovableObject ich tun gerade:Automatisches Hinzufügen eines Objekts zu einem Vektor dieses Objekts Eltern

Vector<Sprite*> sprites; 
Vector<MovableObject*> movableObjects; 
MovableObject* movingObject = new MovableObject(); 
sprites.push_back(movingObject); 
movableObjects.push_back(movingObject); 

Da aber die verschiedenen Kategorien und Einheiten wachsen wird der Code erhalten groß (und es würde ermüdend sein, jede Entität zu jedem Vektor hinzuzufügen, zu dem es gehört). Wie füge ich automatisch ein Objekt zu dem Vektor hinzu, zu dem es gehört, wenn es erstellt wird?

EDIT 1: Ich denke, ich kam gerade mit einer Lösung, was ist, wenn ich nur eine globale statische Klasse Entities, die alle Vektor der Entitäten in der Szene hält. Jede Entität könnte Zugriff auf diese Klasse haben und wenn eine Entität erstellt wird, fügt sie nur eine Zeigerversion von sich selbst zu dem/den entsprechenden Vektor (en) in dieser globalen Klasse hinzu.

EDIT 2: Aber ich habe vergessen, dass meine Lösung erfordert, dass ich noch manuell jede Entity zu ihrem passenden Vektor hinzufüge. Ich habe die Arbeit einfach unter die verschiedenen Entitäten aufgeteilt.

+0

Sie könnten es nur zu 'sprites' hinzufügen und einfach herausfinden, ob es ein' MoveableObject' ist, indem Sie eine Membervariable abfragen. –

+2

Haben Sie eine Möglichkeit, auf diese Listen zuzugreifen (zum Beispiel würde jede Komponente einen statischen Vektor aller ihrer Instanzen haben) und sich in einem Konstruktor einer bestimmten Komponente zu richtigen Listen anmelden. Obwohl ich diesen Ansatz nicht empfehle. Eher mit Fabriken gehen, die alle notwendigen Logik, die Tracking/Registrierung von Komponenten erfordert. –

+0

Warum nicht stattdessen virtuelle Funktionen und Polymorphie verwenden? Dann brauchen Sie nur eine Sammlung Ihrer Objekte. –

Antwort

2

Das ist ein schönes Problem.

Ich denke, dass ich es so implementieren würde: Es wird eine addToVector() Methode in Sprite Klasse geben, und jede abgeleitete Klasse überschreibt es, um sich dem entsprechenden Vektor hinzuzufügen.

+0

Vielen Dank! Dies löste mein Problem vollständig :) – Bonbin

+1

Einfache und nette Lösung, ich werde nur einen Kommentar hinzufügen. Es könnte verlockend sein, den Aufruf von addToVector() im Konstruktor dieser abgeleiteten Klassen hinzuzufügen, aber dies ist nicht sicher, um virtuelle Funktionen in Konstruktoren aufzurufen und zu undefiniertem Verhalten führen. Eine dedizierte Factory-Funktion, die ein Objekt erzeugt und dann den addToVector auf einer Instanz aufruft, scheint eine gute Lösung zu sein, so dass der Benutzer dies nicht vergisst. –

1

Ich würde einen anderen Ansatz vorschlagen. Aber bevor ich anfange, möchte ich eine Sache mit Ihrem aktuellen Design bemerken.

Ich würde die Erstellung dieser Objekte hinter einer Fassade verstecken. Nennen Sie es eine Szene oder was auch immer. Die manuelle Verwendung von new ist aus mehreren Perspektiven schlecht. Vor allem, wenn Sie entscheiden, dass Sie das Schema ändern möchten, wie Sie Ihre Objekte zuweisen/konstruieren, müssen Sie es überall im Code ändern. Wenn Sie eine Fabrik wie Scene haben, ändern Sie einfach die Implementierung und die Anrufe zu scene->CreateObject<Sprite>() bleiben überall sonst gleich. Dies kann wichtig werden, sobald Sie beginnen, Dinge wie benutzerdefinierte Speicherzuweisungsschemata, Objektpools usw. hinzuzufügen, und Sie werden es irgendwann tun, wenn Sie mit dem Wachstum Ihrer Engine beginnen. Auch wenn es sich nur um ein Übungsprojekt handelt, möchten wir alle so machen, wie es tatsächlich gemacht wurde, richtig;)?

Nun geht es zurück zum Kern - missbrauche die Vererbung nicht.

MovableObject ist kein Sprite. Static Object ist auch kein Sprite. Sie sind das, bewegliche und statische Elemente.

Ein Sprite kann beweglich oder statisch sein, also verhält es sich wie ein dynamisches oder statisches Element.

Verwenden Sie stattdessen die Komposition. Machen Sie ein Sprite-akzeptierendes Verhalten oder besser eine Liste von Verhaltensweisen. Tatsächlich ist der Sprite selbst nur ein Verhalten auf einem Game-Objekt, er steuert nur die Art, wie er dem Benutzer präsentiert wird.

Was wäre, wenn Sie ein Objekt hätten, an das mehrere Verhaltensweisen angehängt werden könnten, wie die Tatsache, dass es sich um ein dynamisches Objekt handelt, es hat eine Sprite Präsenz in der Szene und noch mehr ist ein Sound Emitter!

Wenn Sie diese Verhaltensweisen zum Objekt hinzufügen, müssen Sie sie zuerst erstellen. Sie können, wenn sie konstruiert werden, entscheiden, zu welcher Liste sie sich anmelden sollen.

Dies ist alles Metaphern für ein wirklich bekanntes System, das nachweislich gut funktioniert und tatsächlich in den meisten Game-Engines heutzutage verwendet wird. Es ist ein Entity-Komponenten-System.

Sie Objekt mit Verhalten sind Entitäten, Komponenten sind diese Verhaltensweisen und jeder von ihnen wird von einem System gesteuert, das die Komponente kennt und weiß, wie man sie aktualisiert/behandelt.

Objekte in der Szene sind lediglich eine Reihe von Komponenten, die an ihnen angebracht sind und auf sie wirken.

+0

Ich plante tatsächlich, etwas namens Templates zu verwenden, das mir erlauben würde, ein Verhalten (wie Kollision) auf mehrere Objekte anzuwenden. Aber wie ich im Kommentar erwähnte, ist dies ein Schulprojekt mit sehr strengen Richtlinien, die angeben, dass ich die Vererbung verwenden muss, damit der aktuelle Ansatz beibehalten werden muss.Meine Frage wurde bereits beantwortet, aber ich gebe dir +1 für einen sehr informativen Beitrag und ich werde wahrscheinlich in das Designmuster schauen, das du in zukünftigen Projekten beschreibst :) – Bonbin

Verwandte Themen