Designfrage



  • Reth schrieb:

    evtl. sollte ein Design-Unterforum eingerichtet werden, in das man solche Beiträge posten kann und in dem man dann evtl. auch besser suchen kann?

    Die Idee an sich ist nicht schlecht, andererseits hängt das sehr oft mit der zugrunde liegenden Sprache zusammen, ich weiß nicht, ob man da mit Java,Perl oder was weiß ich einen gemeinsamen Nenner findet 🙂

    Und meiner Erfahrung nach sollte beim Design generell jede Klasse so wenig wie möglich von anderen abhängig sein.



  • Reth schrieb:

    Stört an dieser Stelle denn nicht, dass fast alle Objekte der 2. Klasse eine implementierte Methode mit sich tragen, die nie benötigt wird (derzeit wird sie für genau 1 Objekt dieser Klasse benötigt)?

    Nicht wirklich. Methoden werden nur einmal pro Klasse angelegt und dann je nach Bedarf verwendet.

    (btw, schau dir mal die komplette Schnittstelle von Klassen wie std::string oder std::vector an - wieviele dieser Methoden hast du tatsächlich schon benutzt?)



  • Dein Erklärungsansatz mit "ich hab 2 Klassen" ist schonmal schlecht. Denn uU liegt da ein Designproblem schon begraben. Vielleicht nicht, vielleicht schon.

    Deshalb: wenn du Design Tipps haben willst musst du abstrakt das Problem erklären. Denn woher sollen wir wissen was besser ist, wenn wir nur einen kleinen Ausschnitt kennen?

    Manche Sachen deiner Erklärung klingen sehr komisch. Denn warum braucht nur ein Objekt ein gewisses Interface und alle anderen nicht? Ich meine: wenn die Anforderungen an die Objekte so grundverschieden sind, warum haben sie dann den selben Typ?

    Das sind so Fragen die man mit einem kleinen Ausschnitt des großen Bildes nicht beantworten kann - man braucht mehr rundherum info.



  • ließe sich mit dem klassischen observer pattern lösen. klassen, die benachrichtigt werden sollen, implementieren ein interface (bzw. nutzen es als basisklasse), welches im grunde nur eine (virtual) benachrichtigungsmethode deklariert (notify). eine andere klasse (im klassischen pattern subject genannt) wacht darüber, ob es notwendig ist, die observer zu benachrichtigen (kann dazu z.b. eine öffentliche methode bereitstellen). was die observer sonst noch für methoden besitzen, ist dieser "benachrichtigungsklasse" im grunde egal, für die ist nur die eine methode wichtig. ob eine klasse nun die benachrichtigung nutzt oder nicht, sollte sie intern selbst regeln. objekte der klasse A führen immer ihre aufgabe durch, wenn sie angestoßen werden. objekte der klasse B haben ihre benachrichtigungsmethode anders implementiert und fragen, sobald sie angestoßen werden, irgendwelche parameter anderer objekte ab o.ä., um zu entscheiden, ob sie auch aktionen durchführen.

    das ist grundsätzlich sauberes design und es ist auch durchaus üblich, dass sich ungleichförmige objekte bei derselben benachrichtugungsklasse anmelden.



  • thordk schrieb:

    ließe sich mit dem klassischen observer pattern lösen. klassen, die benachrichtigt werden sollen, implementieren ein interface (bzw. nutzen es als basisklasse), welches im grunde nur eine (virtual) benachrichtigungsmethode deklariert (notify). eine andere klasse (im klassischen pattern subject genannt) wacht darüber, ob es notwendig ist, die observer zu benachrichtigen (kann dazu z.b. eine öffentliche methode bereitstellen). was die observer sonst noch für methoden besitzen, ist dieser "benachrichtigungsklasse" im grunde egal, für die ist nur die eine methode wichtig. ob eine klasse nun die benachrichtigung nutzt oder nicht, sollte sie intern selbst regeln. objekte der klasse A führen immer ihre aufgabe durch, wenn sie angestoßen werden. objekte der klasse B haben ihre benachrichtigungsmethode anders implementiert und fragen, sobald sie angestoßen werden, irgendwelche parameter anderer objekte ab o.ä., um zu entscheiden, ob sie auch aktionen durchführen.

    das ist grundsätzlich sauberes design und es ist auch durchaus üblich, dass sich ungleichförmige objekte bei derselben benachrichtugungsklasse anmelden.

    Hm so ähnlich ist ja das Design des Ansatzes mit der abstrakten Basisklasse.
    Diese spiegelt ja die Benachrichtigungsmethode wieder. Die Klasse, welche dann diese Benachrichtigungsmethode ruft (in dem Fall ne Activityklasse, die wiederum immer dann aktiviert wird, wenn das System eine zeitgesteuerte Nachricht generiert hat - evtl. hat das Design hier schon zu viele Stufen), stellt in dem Fall ja das Subjekt dar (oder hab ich das völlig falsch verstanden?).

    Ciao



  • Shade Of Mine schrieb:

    Dein Erklärungsansatz mit "ich hab 2 Klassen" ist schonmal schlecht. Denn uU liegt da ein Designproblem schon begraben. Vielleicht nicht, vielleicht schon.

    Deshalb: wenn du Design Tipps haben willst musst du abstrakt das Problem erklären. Denn woher sollen wir wissen was besser ist, wenn wir nur einen kleinen Ausschnitt kennen?

    Manche Sachen deiner Erklärung klingen sehr komisch. Denn warum braucht nur ein Objekt ein gewisses Interface und alle anderen nicht? Ich meine: wenn die Anforderungen an die Objekte so grundverschieden sind, warum haben sie dann den selben Typ?

    Das sind so Fragen die man mit einem kleinen Ausschnitt des großen Bildes nicht beantworten kann - man braucht mehr rundherum info.

    Hm aber wie weit soll ich da gehen (um nicht zuviel zu beschreiben)?

    Ich probiers mal und wenns immer noch zu wenig ist, gebt Bescheid:

    Also für mein Spiel benötige ich unterschiedliche Objekte: Graphische (Animationsobjekte) und nicht-graphische (Gebäude, Spieler etc.) und noch ein paar andere Dinge. (Die Gebäude haben natürlich auch ein graphisches Objekt als Member).

    Nun sollen alle Gebäudeobjekte und ein graphisches Objekt in regelmäßigen Intervallen Aktionen ausführen (die Gebäude ggf. neue Rohstoffe einfahren und das graphische Objekt ggf. einen neuen Frame seiner Animation blitten, wenn es sichtbar ist).

    Die Besonderheit, dass derzeit nur ein graphisches Objekt zeitlich getriggert ist liegt in Folgendem:

    Ich unterscheide meine graphischen Objekte nicht. Sie können alle das gleiche.
    Nun wird aber eins davon hergenommen, um nach Klick auf Spielaktionen ggf. am Mauscursor eine animierte Grafik darzustellen, welche die gewählte Aktion bis zu ihrer endgültigen Ausführung repräsentiert (kennt man ja aus AOE, C&C etc.).
    Die anderen graphischen Objekte repräsentieren derzeit die Gebäudegrafiken. Diese werden aber nicht aufgrund zeitlicher Aktionen getriggert, sondern wenn sich der Zustand des Gebäudes ändert (z.B. bei Beschädigung).
    Das führt also dazu, dass graphische Objekte unterschiedliche getriggert werden und daher nicht alle von einer zeitlichen Steuerung (als Interface gesehen) profitieren.

    Ciao



  • Da wäre es evnetuell eine bessere Lösung, dein "aktives Grafik-Objekt" hinter einem Spiel-Objekt (Cursor) zu verpacken, der sich auch um die Darstellung kümmert.

    (btw, wie realisierst du eigentlich die Animationen der Spielobjekte, wenn die dargestellten Grafiken nicht getimert werden (Soldaten laufen über den Bildschirm, eine Radar-Schüssel rotiert, etc)?



  • CStoll schrieb:

    Da wäre es evnetuell eine bessere Lösung, dein "aktives Grafik-Objekt" hinter einem Spiel-Objekt (Cursor) zu verpacken, der sich auch um die Darstellung kümmert.

    Hm nur hab ich leider keinerlei Attribute oder Methoden, die ich diesem Spielobjekt Cursor verpassen könnte! Ist alles schon im graphischen Objekt beinhaltet (s. dazu auch Beantwortung unten!).

    (btw, wie realisierst du eigentlich die Animationen der Spielobjekte, wenn die dargestellten Grafiken nicht getimert werden (Soldaten laufen über den Bildschirm, eine Radar-Schüssel rotiert, etc)?

    Derzeit sind solche Animationen, die eine zeitliche Steuerung benötigen noch gar nicht/wenig vorhanden und geplant (aufgrund von Performance etc.).
    Aber jetzt wo Du es erwähnst fällt mir ein, dass ich einen Fall habe, der auch eine zeitliche Steuerung graphischer Objekte erfordert (und zwar zusätzlich zur zustandsgetriggerten Steuerung)! Hatte ich fast vergessen!
    Daher ist wohl eher der Ansatz mit der gemeinsamen abstrakten Basisklasse von Vorteil!

    Meine graphischen Objekte sind ziemlich kompliziert aufgebaut, weil ich mir Felxibilität gönnen wollte. Durch das eben erwähnte ist mir aber aufgefallen, dass ich nun ggf. ein Problem bekomme, wenn ein und dasselbe graphische Objekt über Zustände und später zeitlich gesteuert werden soll. Dann muss es intern wissen, wann welche Steuerung passieren muss.

    Hier mal kurz der Aufbau und die gedachte Verwendung der graphischen Objekte:

    • zuunterst FrameObjekte, jedes stellt eine Grafik (BitMap) mit den benötigten Attributen dar
    • darüber Animationen, die aus einer Reihe von Frames bestehen, die entweder in einer bestimmten Reihenfolge oder zufällig abgespielt werden können (bin mir gerad nicht sicher, ob in diesen Objekte schon die Intervalle zw. den Frames definiert werden, wenn eine Animation ein Signal bekommt sich zu aktualisieren, glaub aber schon - kann gerad nicht auf den Source zugreifen)
    • zuoberst Animationsobjekte enthalten mehrere Animationen zu einem "Thema" (z.B. zu einem Gebäude), zwischen denen je nach Bedarf gewechselt werden kann

    Sinn dahinter soll der sein, dass z.B. ein Gebäudeanimationsobjekt alle für eine Gebäude notwendigen Animationen (z.B. für die Entstehung, Normalzustand, Beschädigung, zerstörter Zustand) beinhalten soll und das Gebäude je nach seinem Zustand die Animation in dem ihm zugewiesenen Animationsobjekt umschaltet.
    Zusätzlich muss aber eine Gebäudeanimationsobjekt auch zeitlich gesteuert werden, da ja innerhalb einer Animation nach einem bestimmten Intervall ein neuer Frame dargestellt werden muss (auch wenn das Gebäude seinen Zustand nicht wechselt).

    Heh! Gut dass wir darüber sprechen, nun seh ich das Ganze schon etwas klarer!

    Ciao



  • Reth schrieb:

    CStoll schrieb:

    Da wäre es evnetuell eine bessere Lösung, dein "aktives Grafik-Objekt" hinter einem Spiel-Objekt (Cursor) zu verpacken, der sich auch um die Darstellung kümmert.

    Hm nur hab ich leider keinerlei Attribute oder Methoden, die ich diesem Spielobjekt Cursor verpassen könnte! Ist alles schon im graphischen Objekt beinhaltet (s. dazu auch Beantwortung unten!).

    Da sind die Grafik-Objekte wohl etwas zu mächtig geworden 😉

    Hmm, wenn ich mir das so ansehe, würde ich Grafik und Speilgeschehen weitgehend unabhängig voneinander verwalten (inklusive eigener Zeitschleifen für beides).

    • Auf Spiel-Ebene hast du Spiel-Objekte, die auf verschiedene Ereignisse (ausgewählt, Angriff, Zeit-Trigger etc) reagieren können und so die Spiel-Logik beeinflussen
    • Auf Grafik-Ebene hast du die Animationen, die jeweils eine Serie von Einzelbildern haben und periodisch anzeigen - in einem festen Zeittakt werden alle Animationen zum Gesamtbild zusammengesetzt.
    • Jedes Spiel-Objekt hat einen Zeiger zu "seiner" aktiven Animation und kann diese je nach Aktionen auch beeinflussen (z.B. wird die komplette Bildsequenz ausgetauscht, wenn die Gebäude-Hitpoints unter einen bestimmten Wert fallen).


  • CStoll schrieb:

    Reth schrieb:

    Hm nur hab ich leider keinerlei Attribute oder Methoden, die ich diesem Spielobjekt Cursor verpassen könnte! Ist alles schon im graphischen Objekt beinhaltet (s. dazu auch Beantwortung unten!).

    Da sind die Grafik-Objekte wohl etwas zu mächtig geworden 😉

    Naja zumindest nach meinem Plan und der beschriebenen Architektur nicht.
    Der Cursor kann unterschiedliche Zustände haben (aus, Aktion1, Aktion2, ...). Diese können direkt durch Animationen und das Animationsobjekt dargestellt werden (ausschalten, Animation1, Animation2, ...). Daher gibt es (noch) kein Cursorobjekt.

    Hmm, wenn ich mir das so ansehe, würde ich Grafik und Speilgeschehen weitgehend unabhängig voneinander verwalten (inklusive eigener Zeitschleifen für beides).

    • Auf Spiel-Ebene hast du Spiel-Objekte, die auf verschiedene Ereignisse (ausgewählt, Angriff, Zeit-Trigger etc) reagieren können und so die Spiel-Logik beeinflussen

    Sind ja so schon vorhanden.

    • Auf Grafik-Ebene hast du die Animationen, die jeweils eine Serie von Einzelbildern haben und periodisch anzeigen - in einem festen Zeittakt werden alle Animationen zum Gesamtbild zusammengesetzt.

    Animationen sind vorhanden, werden aber wahrscheinlich nicht alle auf einmal pro Zeittakt aktualisiert (jede entscheidet selbst, ob sie einen neuen Frame blitten muss oder nicht).

    • Jedes Spiel-Objekt hat einen Zeiger zu "seiner" aktiven Animation und kann diese je nach Aktionen auch beeinflussen (z.B. wird die komplette Bildsequenz ausgetauscht, wenn die Gebäude-Hitpoints unter einen bestimmten Wert fallen).

    Ist so ähnlich gelöst: Spielobjekte haben nen Zeiger zu ihren Animationsobjekten, diese enthalten (als Zeiger bzw. Referenz bzw. Objekt) wiederum alle für das Spielobjekt (z.B. Gebäude) notwendigen Animationen. Das Spielobjekt aktiviert die für seinen Zustand notwendige Animation selbst.

    Ciao



  • Bleibt aber noch die Frage: Wie sage ich meinem grafischen Objekt, ob es auf zeitliche Ereignisse reagieren soll, oder nicht (dieser Eigenschaft kann sich zur Laufzeit ändern)?



  • Geh einfach davon aus, daß jedes grafische Objekt auf Zeitereignisse reagieren soll (nicht-animierte Objekte haben nur einen Frame, den sie anzeigen können - und damit etwas weniger zu tun).



  • Hm, die Frameanzahl liegt hinter den Animationsobjekten (die "mittlere" Schicht).
    Die eigentlichen graphischen Objekte können mehrere dieser Animationsobjekte haben und daher immer unterschiedliche Frameanzahlen.

    Hab aber gestern gesehen, dass ich den graphischen Objekten doch keine Zeitereignisse zukommen lassen kann und zwar aus einem anderen "Designgrund":

    Alle graphischen Objekte werden in einer Managerklasse erzeugt, sich in dieser gemerkt (mit Position und z-Ebene), und bei deren "Zerstörung" auch wieder freigegeben.

    Diese Managerklasse hat auch die Methode zum Neuzeichnen der graphischen Objekte. In dieser wird auf Überdeckung geprüft, der Clipbereich berechnet und die Damagelist erstellt.
    Die Methode erhält das graphische Objekt, das sich gerade neu zeichnen will.

    Wenn ich den graphischen Objekten nun zeitgesteuert erlauben will sich neu zu zeichnen, müssten diese ja wiederum auch auf ihre Managerklasse zugreifen können (quasi ne Art doppelte Verkettung), um die entsprechende Methode aufzurufen!
    Das gefällt mir nicht so sehr, so dass ich denke, für die graphischen Objekte eine Klasse zu machen, die ne Liste dieser Objekte enthält, die alle zeitgesteuert werden wollen und ebenso nen Verweis auf die Managerklasse zum Aufruf des Neuzeichnens.

    Nun muss ich aber immer noch dafür sorgen, dass sich die graphischen Objekte zur Laufzeit "umentscheiden" können, ob sie zeitlich gesteuert aktiviert werden wollen oder nicht (die einzelnen Animationen wissen es, werden ja aber nach Thema in einem AnimationsObjekt [z.B. Gebäude]zusammengefasst).

    Vielleicht wäre das dann ein Ansatzpunkt für das von Dir (CStoll) beschriebene Verfahren:
    Alle Animationsobjekte bekommen die Möglichkeit der zeitlichen Steuerung und "fragen" ihre aktive Animation, ob diese zeitlich oder über andere Ereignisse gesteuert werden will!

    Ciao



  • Wenn da jemand zeitgesteuert arbeitet, sollte das wohl der Grafik-Manager sein.

    Ansonsten: Nur um einen gemeinsamen Nenner zu haben

    • Frame: ein einzelnes Bild (aus den einzelnen Frames wird das gesamte Bild zusammengepuzzelt)
    • Animation: eine Folge von Frames, die zyklisch dargestellt werden sollen (z.B. die einzelnen Bewegungsschritte der Radarschüssel)
    • Grafisches Objekt: eine Sammlung von Animationen, von denen je nach Situation eine aktiv sein kann (z.B. Baustelle, intaktes Gebäude, leicht beschädigtes Gebäude...)
    • Spielobjekt: das Gebäude oder eine Einheit aus spiellogischer Sicht (kann produzieren, laufen/fahren, angreifen etc je nach Typ)

    Kommt das so ungefähr hin?



  • CStoll schrieb:

    Wenn da jemand zeitgesteuert arbeitet, sollte das wohl der Grafik-Manager sein.

    Ansonsten: Nur um einen gemeinsamen Nenner zu haben

    • Frame: ein einzelnes Bild (aus den einzelnen Frames wird das gesamte Bild zusammengepuzzelt)
    • Animation: eine Folge von Frames, die zyklisch dargestellt werden sollen (z.B. die einzelnen Bewegungsschritte der Radarschüssel)
    • Grafisches Objekt: eine Sammlung von Animationen, von denen je nach Situation eine aktiv sein kann (z.B. Baustelle, intaktes Gebäude, leicht beschädigtes Gebäude...)
    • Spielobjekt: das Gebäude oder eine Einheit aus spiellogischer Sicht (kann produzieren, laufen/fahren, angreifen etc je nach Typ)

    Kommt das so ungefähr hin?

    Völlig korrekt!

    Aber wie soll denn der Manager zeitgesteuert arbeiten. Ich seh ihn so, dass es ihm egal sein kann, was die graphischen Objekte anstellen. Er erzeugt sie, verwaltet sie und auf Anweisung zeichnet er sie neu (mit Rücksicht auf Überdeckung etc.).

    Hm...



  • Reth schrieb:

    Aber wie soll denn der Manager zeitgesteuert arbeiten. Ich seh ihn so, dass es ihm egal sein kann, was die graphischen Objekte anstellen. Er erzeugt sie, verwaltet sie und auf Anweisung zeichnet er sie neu (mit Rücksicht auf Überdeckung etc.).

    Wenn du eine halbwegs flüssige Grafik haben willst, sollte er die Anweisung zum Neuzeichnen schon in rechten kurzen Zeittakten erhalten (so ca. 25..50 mal pro Sekunde). Und dabei kann er dann von den Animationen auch das jeweils nächste Frame anfordern.



  • CStoll schrieb:

    Wenn du eine halbwegs flüssige Grafik haben willst, sollte er die Anweisung zum Neuzeichnen schon in rechten kurzen Zeittakten erhalten (so ca. 25..50 mal pro Sekunde). Und dabei kann er dann von den Animationen auch das jeweils nächste Frame anfordern.

    Ich weiß. Wenn ich dem Manager aber zeitlich gesteuert sage: Neuzeichnen, muss er alle AnimationsObjekte abgrasen, fragen, ob ein neuer Frame ansteht und wenn ja dieses Objekt zum Neuzeichnen aufnehmen.

    Da die Animationen selbst wissen, wann sie ein neues Frame zeichnen wollen (z.B. da gewisse Zeit abgelaufen ist oder sich ein Zustand geändert hat) wollte ich ein neuzeichnen nur für die Objekte veranlassen, die das gerade brauchen und die entsprechende Methode dann gezielt aufrufen.

    Die Animationen haben wenn sie zeitgesteuert laufen sollen einen internen Timer, der wenn man die Animation oft genug fragt (25..50 Mal pro Sekunde) feststellt, ob seit dem letzten Neuzeichnen genug Zeit verstrichen ist und nun ein neuer Frame an die Reihe kommt.
    So kann ich gewährleisten, dass unterschiedliche Animationen unterschiedliche Frameabstände (zeitlich gesprochen) haben können und damit unterschiedlich schnell ablaufen.

    Daher müsste ich beim derzeitigen Stand in der Klasse, welche die zeitlich gesteuerten AnimationsObjekte bekommt alle abgrasen, sie fragen, ob sie sich neu zeichnen möchten und wenn ja die Managerklasse mit der entsprechenden Methofe aufrufen.
    Da aber alle Animationsobjekte eine zeitliche Steuerung bekommen, kann ich das entsprechende Interface (abstrakte Basisklasse) für die zeitliche Steuerung auch in der Managerklasse implementieren! Haste Recht! (und wieder ne Klasse gespart!)

    Ciao


Anmelden zum Antworten