OO Ansatz für Strategie Spiel - Designfrage
-
Danke!
Muss ich mal googeln...Wo findet man eigentlich all die Patterns, und weiss wann man welches einsetzt. Ist das Erfahrung oder gibts da ein Schema F?
-
eine übersicht inklusive beispielen gibt es hier:
http://en.wikipedia.org/wiki/Design_pattern_%28computer_science%29
(es gibt auch noch ne deutsche version, eventuell ist die ja verständlicher. die englische ist auf jeden fall ausführlicher.)dann gibt es noch "das" referenzwerk von der "gang of four" mit dem gleichnamigen titel "design pattern". das buch ist allerdings ziemlich trocken, und schwer verständlich, wenn man nicht wirklich fit im objekt-orientiertem design ist. dafür aber sehr vollständig (was die enthaltenen patterns betrifft) und somit ein sehr gutes nachschlagewerk.
sehr viel lebendiger ist das buch von head first:
http://www.amazon.de/gp/product/0596007124/302-2971792-6420869?v=glance&n=52044011
Das gibts auch auf deutsch, ist aber 20€ teurer und bei übersetzungen weiss man nie so recht ;).auch nicht schlecht ist diese seite: http://www.dofactory.com/Patterns/Patterns.aspx. die erklärungen sind allerdings nicht besonders ausführlich, deswegen ist es auch eher als nachschlagewerk zu gebrauchen, für den fall, dass dir im forum ein "Abstract Factory" an den kopf geworfen wurde ;).
-
So, back again...
Danke mal soweit für die Hilfe
Also nun hab ich ne Factory Methode, wenigstens mal das Gerüst.
Die bau ich nun in mein Spiel ein.
Meine Grundfrage von vorhin bleibt aber, wo speichere ich die erzeugten Objekte?
In ner Extraklasse Village in nem Vector für Products?
Gibts da etwa noch ein Manager Pattern

Und ne andere Frage ist nun, ein Gebäude das sowohl Waren empfängt und bereitstellt (fast alle ausser der Farm) erbt doch nun von 3 Klassen allein durch die Observer und Factory Geschichten. Zusätzlich dachte ich ja an eine Basisklasse Building. Das wären dann 4 Basisklassen. Ist das nicht etwas komplex bzw. ein unnötiger Overhead?
Letzte Frage für den Moment: Gibt es die Funktion GetType().Name auch bei C++ oder nur bei C#?
-
Ooptimist schrieb:
Meine Grundfrage von vorhin bleibt aber, wo speichere ich die erzeugten Objekte?
In ner Extraklasse Village in nem Vector für Products?
Gibts da etwa noch ein Manager Pattern

Brauchst du gar nicht. Du wirst ja irgendwo die ganzen Daten des Spielers abspeichern (z.B. auch die Position des Hauptgebäudes, das Volk, Statistiken etc.). Da kannst du einen Gebäude-Vektor einfügen. Aufgrund der Verwendungsart als Container ausschließlich polymorpher Objekte solltest du ptr_vector verwenden. IIRC funktioniert der auch mit Boost.Serialization, sehr praktisch für Spielstände.
Ooptimist schrieb:
Und ne andere Frage ist nun, ein Gebäude das sowohl Waren empfängt und bereitstellt (fast alle ausser der Farm) erbt doch nun von 3 Klassen allein durch die Observer und Factory Geschichten. Zusätzlich dachte ich ja an eine Basisklasse Building. Das wären dann 4 Basisklassen. Ist das nicht etwas komplex bzw. ein unnötiger Overhead?
Du kannst noch einige Abstraktionen machen, z.B. eine Producer-Klasse die von Building abgeleitet ist und eine Receiver-Klasse, die wiederum von Producer abgeleitet ist (die "Ist-ein" Beziehung ergibt sich aus der Spiellogik, wenn du dich an die Siedler-Regeln hältst, sollte aber dennoch gut dokumentiert sein. Militärgebäude sind zwar auch Empfänger, aber wenn du nur deshalb Receiver nicht von Producer ableiten würdest, dann müsstest du Producer und Receiver virtuell ableiten, was hier aber nicht praktisch ist. Militärgebäude "verarbeiten" die ankommenden Rohstoffe ja auch ganz anders.
Ooptimist schrieb:
Letzte Frage für den Moment: Gibt es die Funktion GetType().Name auch bei C++ oder nur bei C#?
Nein. Es gibt nur typeid(typ).name, aber das ist nicht eindeutig. Wenn du so etwas haben willst, dann implementier es als virtuelle Methode.
-
Danke für den Tipp mit Serialization. Werd ich dann auch verwenden für Spielstände, aber soweit bin ich noch nicht. Boost hat ja noch einiges aufm Kasten

.filmor schrieb:
Ooptimist schrieb:
Und ne andere Frage ist nun, ein Gebäude das sowohl Waren empfängt und bereitstellt (fast alle ausser der Farm) erbt doch nun von 3 Klassen allein durch die Observer und Factory Geschichten. Zusätzlich dachte ich ja an eine Basisklasse Building. Das wären dann 4 Basisklassen. Ist das nicht etwas komplex bzw. ein unnötiger Overhead?
Du kannst noch einige Abstraktionen machen, z.B. eine Producer-Klasse die von Building abgeleitet ist und eine Receiver-Klasse, die wiederum von Producer abgeleitet ist (die "Ist-ein" Beziehung ergibt sich aus der Spiellogik, wenn du dich an die Siedler-Regeln hältst, sollte aber dennoch gut dokumentiert sein. Militärgebäude sind zwar auch Empfänger, aber wenn du nur deshalb Receiver nicht von Producer ableiten würdest, dann müsstest du Producer und Receiver virtuell ableiten, was hier aber nicht praktisch ist. Militärgebäude "verarbeiten" die ankommenden Rohstoffe ja auch ganz anders.
Ok sorry, ich kapiers nicht mehr

Im Observer-Pattern hab ich Observers und Observables, in der Factory hab ich Creators und Products. Kann ich die Factory und Observer Methoden nicht in die Basisklasse der Bereitsteller und Empfänger einfügen? Ich hab ja sonst ewig viele Abhängikeiten und Dateien, ich hab einfach keinen Überblick mehr, was wo ist
-
Habe nun nochmal die Hierarchie überdacht:
Factory Observer Creator Product Subject Observer | | | | | | | | | | | | Builder ---->Building | | | | | | | | | | | ---------------| | --------| | | Pure Pure | Producer Receiver | | | | | | | | | | | | ----| |----- | | | Processor | | | | | | | | | | | | | Farm* Builder ------------>Farm Mill/Bakery Storage *needed for each spec. Building TypeMacht das Sinn so? Kritik wäre toll!

-
Nochmal, willst du dich wirklich genau an die Siedler II halten? Dann gibt es keine Pure Receiver (außer Militärgebäude). Das ist das worauf ich beim letzten eingehen wollte.
Das Farm ein Pure Producer ist ist genauso falsch (eine Farm nimmt Wasser an), wie dass Storage ein Pure Receiver ist (Lagerhäuser musst du definitiv gesondert behandeln).
Zusätzlich heißt ein Pattern benutzen nicht zwingend, dass du deine Klassen auch direkt von den Observable etc. ableiten musst (hast du auch nicht getan und richtig erkannt) Das gehört in die (richtige) Basisklasse, dann ergibt sich alles implizit aus der Vererbungshierarchie. Deshalb hast du eine (fast) lineare Vererbung und daher fast keinen Overhead. Um virtuelle Methoden wirst du eh nicht herumkommen.
Der sinnlose und unschöne Overhead ergibt sich erst, wenn du sowohl von Pure Receiver als auch Pure Producer ableitest (wie hier bei Mill/Bakery), such zu dem Thema mal nach dem "deadly diamond". Siehe auch mein letztes Posting.
-
Hallo Ooptimist,
schau dir doch einmal www.widelands.org an. Widelands ist ein Spiel, das Siedler II sehr sehr ähnlich ist. Das Spiel ist Opensource, du kannst dir also einmal den Quellcode herunterladen und ansehen wie dort das Klassendesign realisiert wurde.
Ciao
-
.filmor schrieb:
Nochmal, willst du dich wirklich genau an die Siedler II halten?.
Nein eigentlich nicht. Schongar nicht Siedler II, wenn schon das erste
Habe nur das Prinzip gemeint, Bauspiel mit Wirtschaftssystem und Transport etc. aber ohne Milität. Ich mags friedlich..filmor schrieb:
Dann gibt es keine Pure Receiver (außer Militärgebäude). Das ist das worauf ich beim letzten eingehen wollte.
Das Farm ein Pure Producer ist ist genauso falsch (eine Farm nimmt Wasser an), wie dass Storage ein Pure Receiver ist (Lagerhäuser musst du definitiv gesondert behandeln).Ok, habs nicht genau genug gelesen. Du meintest die Reciever vom Producer ableiten. So gehts dann natürlcih. In meinem System soll es aber reine Produzenten geben, die Farmen, denn Wasser regnets vom Himmel
Am Ende der Kette stehen Konsumenten. Die werd ich dann wohl nochmal extra machen und nur vom Observer ableiten..filmor schrieb:
Zusätzlich heißt ein Pattern benutzen nicht zwingend, dass du deine Klassen auch direkt von den Observable etc. ableiten musst (hast du auch nicht getan und richtig erkannt) Das gehört in die (richtige) Basisklasse, dann ergibt sich alles implizit aus der Vererbungshierarchie. Deshalb hast du eine (fast) lineare Vererbung und daher fast keinen Overhead. Um virtuelle Methoden wirst du eh nicht herumkommen.
Der sinnlose und unschöne Overhead ergibt sich erst, wenn du sowohl von Pure Receiver als auch Pure Producer ableitest (wie hier bei Mill/Bakery), such zu dem Thema mal nach dem "deadly diamond". Siehe auch mein letztes Posting.Den "deadly diamond" kenn ich, ist mir gar nicht aufgefallen in meinem "Diagramm". Gibt halt noch keine UML Tags für dieses Forum

-
Factory Observer Builder Product Subject Observer (Creator) | | | | | | | | | | | | Building | | | | | | | | | | | ---------------| | / \ | | | | \ | Producer | \ | | | | | | | | | | | | ----| |----- | | | | | | | | Fabricator | | | | | | | | | | | | | Farm* Builder ------------>Farm Mill/Bakery Consumer *needed for each spec. Building TypeAlso jetzt aber

-
Ooptimist schrieb:
.filmor schrieb:
Nochmal, willst du dich wirklich genau an die Siedler II halten?.
Nein eigentlich nicht. Schongar nicht Siedler II, wenn schon das erste
Habe nur das Prinzip gemeint, Bauspiel mit Wirtschaftssystem und Transport etc. aber ohne Milität. Ich mags friedlich.Hey, was ist gegen S2 einzuwenden? Außerdem unterscheidet sich das Regelwerk doch iirc nicht besonders ...
Ooptimist schrieb:
Ok, habs nicht genau genug gelesen. Du meintest die Reciever vom Producer ableiten. So gehts dann natürlcih. In meinem System soll es aber reine Produzenten geben, die Farmen, denn Wasser regnets vom Himmel
Am Ende der Kette stehen Konsumenten. Die werd ich dann wohl nochmal extra machen und nur vom Observer ableiten.Welche Konsumenten?! Ohne Militärgebäude sind nur die Lagerhäuser "Konsumenten".
Ooptimist schrieb:
Den "deadly diamond" kenn ich, ist mir gar nicht aufgefallen in meinem "Diagramm". Gibt halt noch keine UML Tags für dieses Forum

Man braucht kein UML, dass musst du spüren, junger Padawan ;). Im Ernst, wenn es zwei Vererbungspfade zur Basisklasse gibt hast du automatisch den "Diamanten des Todes" (klingt cooler ;)) und den gilt es imo zu vermeiden.
/edit Joa, das letzte Diagramm sieht gut aus. Übrigens, die Creator Objekte (bitte nicht Builder, dass ist mehrdeutig) kannst du schön in ein Template verfrachten.
-
Hehe, ganz ruhig. Ich hab die ganze Siedler Reihe bis 4 durchgezockt, inklusive allen Mission CDs. Das 5 ist mir zu weit weg vom Original und der Charme ging auch verloren. 2 ist sicher das beste, nach 1 natürlich. :p
Naja, die Konsumenten halt. Irgendjemand geht dann zum "Bäcker" und kauft sich ein "Brot" und "isst" das dann. ( Auf den Farmen wächst kein Wheat sondern Weed, aber pssst..
)Ich finds halt graphisch dargestellt viel übersichtlicher, machs bei mir aber immer auf Papier. Nix UML. Mit Ascii Art ist halt etwas unschön, aber Du bist ja draus gekommen

Jetzt ists aber besser oder?
-
[quote=".filmor]/edit Joa, das letzte Diagramm sieht gut aus. Übrigens, die Creator Objekte (bitte nicht Builder, dass ist mehrdeutig) kannst du schön in ein Template verfrachten.[/quote] Ah ja? Was müsste ich für Parameter haben? Doch nur den Gebäudetyp oder?
-
[quote=".filmor]/edit Joa, das letzte Diagramm sieht gut aus. Übrigens, die Creator Objekte (bitte nicht Builder, dass ist mehrdeutig) kannst du schön in ein Template verfrachten.[/quote] Ah ja? Was müsste ich für Parameter haben? Doch nur den Gebäudetyp oder?
-
template <typename T> struct generic_creator { T* operator () () { return new T; } };Das kannst du dann bei deiner Factory als Standardparameter nehmen:
template <typename Product> class Factory { public: // ... typedef boost::function0<Product*> creator_type; // ... template <typename T> void register_ (id_type id, creator_type f = generic_creator<T>()) { register_creator (id, f); } };register_creator ist dabei deine "normale" Registrierfunktion.
Undfac.register_<Farm> ("Farm");sieht doch nett aus und ist leicht in ein Makro zu fassen (auch wenn man damit sehr vorsichtig sein muss).
Du kannst diesen "generic_creator" und den creator_type natürlich noch abändern, so dass er Parameter entgegen nimmt (hier ist der einzig sinnvolle wohl der Bauplatz).
-
Ui! Danke wiedermal.
Hätt ich nicht erwartet dass Du mir gleich den Code servierst, super
Sieht wirklich nett aus

Hab mein Compiler grad nicht dabei, versuchs grad im Kopf einzubauen.
Ist id_type ein Typ von Boost, oder ist der zum Selberbasteln?
Was meinst Du mit "meine normale Registerfunktion"? Hab ich bis jetzt gar keine.
Meine Implementation sieht momentan etwa so aus: http://www.c-plusplus.net/forum/viewtopic-var-t-is-153908.html
-
Nuja, da hast du Creators und Products. Ich seh da keine Factory.
id_type sollte normalerweise ein typedef auf einen entsprechenden Template-Parameter sein, ist meistens ein int oder string. Ziel des Factory-Patterns in diesem Zusammenhang wäre ja so ein Aufruf:player.build ("Farm", location); // entspricht (nach ggf. nötigen Prüfungen) in etwa player._buildings.append (factory("Farm") (location)); // oder player._buildings.append (factory.create ("Farm", location));wobei _buildings z.B. vom Typ ptr_vector<Building> wäre. Damit so etwas funktioniert, musst du die Typen, die die Factory ausspuckt erst registrieren. Schau dir mal die Implementierung aus Loki an (lass dich nicht von den ganzen typedefs und Überladungen abschrecken, das wichtige ist relativ übersichtlich unten) und besorg dir vielleicht auch das zugehörige Buch.
-
Hmm, da hab ich wohl was nicht komplett verstanden. Das UML Diagramm auf Wikipedia und anderen Seiten hat eben nur 4 Klassen Creator und Product plus die konkreten Ableitungen.
Da weiss ich ja nun was ich zu lesen hab
Danke mal soweit, ich hab sicher bald die nächste Frage..
-
.filmor schrieb:
..Damit so etwas funktioniert, musst du die Typen, die die Factory ausspuckt erst registrieren. Schau dir mal die Implementierung aus Loki an (lass dich nicht von den ganzen typedefs und Überladungen abschrecken, das wichtige ist relativ übersichtlich unten) und besorg dir vielleicht auch das zugehörige Buch.
Puh abschrecken ist gut, es verwirrt auf jedenfall ganz schön. Ich kapiers irgendwie nicht. Kennst Du nicht eine andere gute Bsp. Implementierung?
Oder ev. kannst Du mir noch mal mit etwas Code helfen, zur Factory?
Wäre spitzenmässig!
-
Zeig was du hast. Jetzt bin ich zu Hause, da hab ich meine "eigene" Implementierung auch zur Hand
