ENGLISH VERSION |
|
Links | | | Forum | | | Kommentare | | | News melden |
Chat | | | Umfragen | | | Newsticker | | | Archiv |
amiga-news.de Forum > Programmierung > Steuerung zwischen GUI und "Ausführern"? | [ - Suche - Neue Beiträge - Registrieren - Login - ] |
-1- | [ - Beitrag schreiben - ] |
15.06.2010, 23:19 Uhr Reth Posts: 1858 Nutzer |
Hallo zusammen, ich habe gerade ein grundsätzliches Problem beim Design im OO-Umfeld. Ich arbeite gerade an einem Spiel mit C++ und habe das Problem, wie ich von den Klassen, welche die Steuerung durch den menschlichen Spieler abarbeiten die entsprechenden Aufgaben an die ausführenden Klassen bekomme! Das akute Beispiel: Durch das Klicken eines Buttons signalisiert man dem Programm, dass man ein Gebäude errichten will. Dieses wird aber auf dem Spielfeld erst errichtet, wenn man mit der Maus in das Zielgebiet klickt. (Ein weiterer Klick auf den Button nimmt die Aktion wieder zurück.) Nun sind an dieser Aktion als Objekte neben dem Button - und einer zugeordneten Aktion bei seiner Aktivierung - der Cursor und der menschliche Spieler beteiligt. Beim Betätigen des Buttons wird die Aktion ausgelöst und der Cursor bekommt die Form des Gebäudes, die am Mauszeiger blinkend dargestellt wird. Nun die Frage: Wie bekomme ich am Besten die finale Aktion des Bauens dieses Gebäudes an den menschlichen Spieler (und weitere Objekte)? Der Button und seine Aktion sind daran nicht mehr beteiligt. Der Bau soll beginnen, wenn nun mit der Maus ins Zielgebiet geklickt wird. Wo speichere ich denn aber diesen "Zwischenzustand" ab? Meine bisherige Idee ist dies im Spielerobjekt zu tun. Also bei Aktivierung des Buttons wird im Spieler vermerkt, dass dieser das entsprechende Gebäude errichten möchte. Beim Klick ins Zielgebiet wird dann erst die endgültige Aktion ausgeführt. Der Nachteil an dieser Sache ist, dass man das Spielerobjekt demzufolge an vielen Stellen mitgeben muss! Das Ganze gilt ja auch für andere Aktionen (v.a. des menschlichen Spielers)! Gibt es da vielleicht irgendwelche guten Patterns o.ä.? Oder wie könnte man das eleganter lösen? Vielen Dank schon mal! Ciao [ - Antworten - Zitieren - Direktlink - ] |
16.06.2010, 09:34 Uhr Thore Posts: 2266 Nutzer |
Du kannst ein "Automat" entwerfen, der auf Status basiert. Jeder Spieler hat dann seine eigenen Status. Wird eine Aktion gemacht, wird ein Flag gesetzt: sbKampf, sbBau, sbAbriss, etc pp (als Bitfelder leicht zu realisieren). Klickst Du in das Ziel, dann muss nur der Status geprüft werden, welcher gesetzt ist. 1. Klick auf einen Button --> Status setzen (damit ist der Automat im nächsten Schritt) 1a. Klick auf einen anderen Button --> neuen Status setzen (überschreiben) 2. Klick auf Ziel --> Status auswerten und entsprechend reagieren, Status wieder resetten, Automat nun wieder im "Auswahlzustand") Klickt man nur auf eine Fläche und ist kein Status gesetzt, dann wird auch keine Aktion ausgeführt (oder ein Auswahl-Modus für Gebäude, Fahrzeuge etc, so ein Standardmodus eben) Vorteil: Du kannst auch mehrere Status setzen, falls Du dies wünschst, so bist Du sehr flexibel was die Aktionen betrifft. [ - Antworten - Zitieren - Direktlink - ] |
16.06.2010, 11:14 Uhr Holger Posts: 8116 Nutzer |
Zitat:Na, wer muss denn etwas von diesem Zustand wissen? Offensichtlich muss die Kette "Mausklick auf die Karte/das Spielfeld"->Handler->"finale Aktion" zu dem gewünschten Ergebnis führen, also muss da irgendwo auch die Aktion bekannt sein, Zitat:Du musst dem Spielfeld mindestens etwas Abstraktes, das aus einem Mausklick die gewünschte Aktion erzeugt mitgeben. Ob das Spielfeld wissen muss, dass das ganze mit einem Spieler-Objekt assoziiert ist, steht auf einem anderen Blatt. Allerdings ist es doch sehr wahrscheinlich, dass das GUI, oder zumindest ein Teil davon durchgängig einem Spieler zugeordnet ist, also warum soll dieser Teil keine Referenz auf diesen Spieler besitzen? Zitat:Entscheidend ist nicht die Menge an möglichen Aktionen, sondern die Menge an gleichzeitig aktiven Aktionen. Typisch wäre beispielsweise eine Aktion, die mit dem nächsten Linksklick der Maus ausgeführt wird, eine mit dem nächsten Rechtsklick und eine mit der Escape-Taste. Wobei letztere eine Aktion wäre, die die Mausknopf-Aktionen wieder auf Standard zurücksetzt. Zitat:Unnötig kompliziert. Eine Referenz auf die aktive Aktion reicht vollkommen aus und ist nur 32 Bit groß, auch dann, wenn es hundert verschiedene Möglichkeiten gibt. Zitat:Nicht wirklich. Mehrere gesetzte Bits würden nur dazu führen, dass man zusätzliche Informationen darüber benötigt, welche der Aktionen nun auszuwählen wäre. Wenn es mehrere aktive Aktionen geben kann, ist es wesentlich sinnvoller, diese mit dem jeweiligen Trigger zu verknüpfen, und dort dann eindeutig. Beispiel: Eine eindeutige Aktion für den linken Mausknopf, eine eindeutige Aktion für den rechten. oder Eine eindeutige Aktion für einen Klick auf die Grundfläche der Karte, eine eindeutige Aktion für einen Klick auf eine Einheit. -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
16.06.2010, 21:39 Uhr Reth Posts: 1858 Nutzer |
Danke für die Tips! @Thore: Das mit dem "Zustandsautomaten" entspricht ja ungefähr dem, was ich beschrieben hatte: Im Spielerobjekt wird die geplante Aktion vorgemerkt und entweder dann ausgeführt oder zurück gesetzt. @Holger: Die Aktion, die am Button hängt hat nix mehr mit der darauf folgenden zu tun. Die Aktion am Button hat die Semantik: Spieler will Gebäude errichten. Diese Aktion kann dann auch hinter einen Menüpunkt oder einen Hotkey gelegt werden. Die Aktion, die ausgeführt wird, wenn dann ins Spielfeld geklickt wird wäre eine andere. Semantik: Spieler errichtet Gebäude. Die Aktionen sind also schon etwas sauberer trennbar. Das Problem besteht allerdings immer noch: Wie "verbinde" ich die einzelnen Aktionen? D.h., wie weiss die Aktion "Spieler errichtet Gebäude", dass sie ausgeführt werden soll? Eine Möglichkeit, die mir nicht so zusagt wäre, dass die Aktion "Spieler will Gebäude errichten" als nächste Aktion auf einen Linksklick die Aktion "Spieler errichtet Gebäude" hinterlegt (also das, was Du mit nächster aktiver Aktion meintest). Das passt mir aber konzeptionell nicht in mein Intuition-Handling! Ein Klick auf die Kartengrundfläche kann allerdigns unterschiedliche Aktionen bedeuten: Gebäude errichten oder Landschaft manipulieren etc. etc. Welche die gerade aktive ist wäre dann durch die Vorgänger-Aktion zu definieren (z.B., welcher Button gedrückt wurde). Das bringt mich auf die Idee: Vielleicht mache ich so ne Art Aktionsstack? Dieser kann allerdings immer nur eine aktive Aktion haben und diese kann entweder zurückgenommen werden, oder durch eine neue Aktion ersetzt werden. Dazu müssten dann aber einige Aktionen, die selbst nie auf dem Stack landen alles über die Aktionen wissen, die sie auf den Stack legen müssen! Beispiel die Button-Aktion "Spieler will Gebäude errichten" wird nie selbst auf den Stack gelegt, sondern wenn sie durch Knopfdruck ausgelöst wird legt sie die Aktion "Spieler errichtet Gebäude" für den menschlichen Spieler auf den Stack (der Computerspieler kann diese Aktion ja auch durchführen). Gefällt mir, die Idee! Nun stellen sich mir gleich wieder die Designfragen dazu: - Sollen die Aktionsobjekte für den Stack immer neu erzeugt und nach Ablauf wieder zerstört werden, oder eher während des gesamten Programmablaufes erhalten bleiben? Tendiere zu Letzterem, da z.B. eine Aktion wie "Spieler baut Gebäude" ja immer wieder ausgeführt werden kann. U.U. für andere Spieler, aber dennoch. - Dann so Themen wie: Definiert man die Aktionen für den Stack als eigene Klassen, oder als eine Aktionsklasse, deren Objekte sich anhand einer Typkennzeichnung unterscheiden (was ja nicht sehr OO ist)? usw. usf.! [ Dieser Beitrag wurde von Reth am 17.06.2010 um 09:26 Uhr geändert. ] [ - Antworten - Zitieren - Direktlink - ] |
17.06.2010, 09:46 Uhr DrNOP Posts: 4118 Nutzer |
Zitat:Nur, daß das was Thore beschrieben hat, nicht unbedingt ein Zustandsautomat ist. Und das, was du vorhattest, sowieso nicht - auch dein Aktionsstack nicht. Deine Beschreibung ist komplizierter als ein Automat sein müßte, und bei Thores Beschreibung könnten mehrere Zustände aktiv sein. Ein Merkmal eines Zustandsautomaten ist, daß zu jeder beliebigen Zeit exakt ein Zustand aktiv ist. D.h., du mußt dir vorher Gedanken über alle möglichen Aktionen machen, was du als Implementer sowieso tun mußt, und daraus die jeweiligen Zustände bilden. Jeder dieser Zustände kann nur über einen bestimmten Satz von Aktionen erreicht und verlassen werden. Das sind deine Übergangsbedingungen. Dann weißt du immer genau, was als nächstes passieren darf. Um im Bild zu bleiben: Dein Spieler hat den Knopf gedrückt "Will Gebäude errichten". Dein Automat wechselt über den Klick vom vorhergehenden Zustand in den Zustand "Will Gebäude errichten". Mögliche Ausgänge: Per Escape zurück zum Grundzustand, per Klick auf das Spielfeld in den Zustand "Gebäude wird errichtet". Wobei der Spieler ja sicher weitermachen kann mit anderen Aktionen, solange ein Gebäude errichtet wird, nicht? Dinge, die eine gewisse Zeit laufen ohne daß der Spieler blockiert wird bzw. ständig eine weitere Aktion unternehmen muß, würde ich nicht fest mit dem Spielerobjekt koppeln. Falls das Spielerobjekt Informationen über laufende Hintergrundvorgänge braucht würde ich die in eine Liste stecken, weil es eine unbestimmte Anzahl sein kann. Außer, dein Spiel sieht nicht vor, daß man zwei, drei Gebäude gleichzeitig errichten kann. -- Signaturen mit mehr als zwei Zeilen gehen mir auf den Wecker [ - Antworten - Zitieren - Direktlink - ] |
17.06.2010, 12:38 Uhr Thore Posts: 2266 Nutzer |
Ich habe kein Zustands-Übergangs-Automat beschrieben (oder bewusst beschreiben wollen), und das Wort Automat extra in Anführungszeichen gesetzt. Das kann man aber dennoch als DFA realisieren, dann springt man bei der nächsten Aktions-Wahl wieder auf den Start zurück und setzt dann das neue Flag, so ist immer nur ein Flag aktiv. Und man kann bei meinem beschriebenen auch mehrere Aktionen verwenden, richtig. Was auch je nach Spiel Sinn machen kann, ob in diesem das weiß nur der Autor Berücksichtigt werden muss, ob die Reihenfolge mehrere gewählten Aktionen eingehalten werden muss, dann ist diese Art wie ich es beschrieben hab nicht machbar. Ansonsten in vielen Programmen gängige Praxis... Du kannst es ähnlich wie ein Betriebssystem als Überbau machen, das die laufenden "Prozesse" überwacht. Die Aktionen können Timer/Event-gesteuert (trigger) ablaufen, oder in einer Master-Schleife schrittweise abgearbeitet werden. Wie Du es realisierst hängt davon ab was Du machen willst. [ Dieser Beitrag wurde von Thore am 17.06.2010 um 12:38 Uhr geändert. ] [ - Antworten - Zitieren - Direktlink - ] |
17.06.2010, 13:32 Uhr Reth Posts: 1858 Nutzer |
Zitat:Das weiss ich. Allerdings kann man das von Thore beschriebene Prinzip auf das Spielerobjekt gemünzt sehr wohl als Zustandsautomat umsetzen (@Thore: Ich weiss, dass es nicht so gemeint ist - Deine Erläuterung habe ich gelesen), da sich ein Spielerobjekt immer in irgend einem Zustand befindet. Eine Spieleraktion triggert dann einen Zustandsübergang, die Rücknahme einer Aktion ebenfalls. Somit ist immer genau ein Zustand aktiv. Allerdings reicht das nicht, daher die Idee mit dieser Art "Stack". Das ich damit keinen Zustandsautomaten gemeint habe, hatte ich eigentlich vorausgesetzt. Dieser "Stack" soll dazu dienen, das man irgendeine Aktion, die als nächstes kommen soll vorbereiten kann, so dass sie ggf. durch etwas Anderes ausgeführt werden kann. Als "global im Programm" verfügbarer Stack deshalb, weil dieses ja dann nicht mehr nur für Aktionen zur Verfügung steht, die den Spieler betreffen (wie hier: "Will Gebäude bauen" und "Baut Gebäude"). Zitat:Genau diese Zustände wären dann z. B. im Spielerobjekt vorhanden. Allerdings an dieser Stelle wohl nicht so glücklich, da das Errichten eines Gebäudes nicht nur den Spieler betrifft, sondern z.B. auch das Spielfeld und den Computergegner, der dieses Gebäude ja nun "sehen" kann. Zitat:Der Spieler kann immer nur eine Aktion auf einmal ausführen, aber dennoch z.B. 2 Gebäude "gleichzeitig" errichten, in dem er dies so schnell ihm möglich ist ausführt. Die Aktion hinterlegt beim Spieler lediglich die nötigen Informationen über das neue Gebäude. Der "Prozess" des Errichtens (z.B. die Animation) erfolgt vollständig unabhängig davon. [ - Antworten - Zitieren - Direktlink - ] |
17.06.2010, 13:50 Uhr Holger Posts: 8116 Nutzer |
Zitat:Hat irgendwer etwas anderes behauptet? Zitat:Genau, und implementiert wird diese Aktion als "setze die LMB-Aktion des Spielfeldes auf BuildAtXY". Zitat:Genau. Das wäre dann BuildAtXY. Zitat:Wo ist das Problem? Zitat:Zu einem bestimmten Zeitpunkt bedeutet eine Linksklick immer genau eine Aktion. Normalerweise gibt es ja auch ein Feedback, z.B. durch einen anderen Mauszeiger oder eine Vorschau an der aktuellen Position. Die zu einem bestimmten Zeitpunkt mit dem Linksklick assoziierte Aktion ist somit Teil des Zustands des Spielfelds. Zitat:Klingt nach einer kompliziert zu kontrollierenden Struktur. Ein Konzept, bei dem jede ausgewählte Aktion die vorhergehende ersetzt, ist nicht nur für den Spieler verständlicher, sondern stellt auch automatisch sicher, dass Dir kein Stack überlaufen kann. Zitat:Warum stellt sich diese Frage? -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
17.06.2010, 13:56 Uhr Holger Posts: 8116 Nutzer |
Zitat:Irgendwie scheinst Du ziemlich große Gedankensprünge zu machen. Dass ein Spieler ein Gebäude errichten will, geht niemanden außer dem Spieler selbst an. Und wenn es mehr als einen menschlichen Spieler gibt, kann auch jeder dieser Spieler für sich beschließen, ein Gebäude zu errichten. Da ist ein globaler Stack vollkommen fehl am Platze. Für andere Spieler, bzw. den globalen Zustand relevant sind lediglich Gebäude, deren Errichtung bereits im Gange oder beendet ist. Das hat aber mit dem Konzept der Aktionen überhaupt nichts mehr zu tun. -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
17.06.2010, 14:22 Uhr Thore Posts: 2266 Nutzer |
Du hast doch interagierende Objekte: Spielfeld, SpielerA, SpielerB, ... Die Spieler sehen alle Felder (Gebäude etc) des Spielfelds. Wird eine Aktion betätigt (z.B. will Gebäude bauen) dann hat nur der Spieler diesen Status. Die anderen Spieler und das Spielfeld wissen davon noch nichts. Klickst Du nun aufs Spielfeld, gibt der Spieler dem Spielfeld über den Status mit was er machen will (Mit meiner Idee über ein Flag, oder Holgers Idee als Hook-Funktion, beides geht). Das Spielfeld weiß nun, an Stelle x,y wird ein Häusle gebaut. Die anderen Spieler sehen ja die Attribute des Spielfelds, und somit auch den Bau des neuen Gebäudes. Ob jemand eine Aktion plant, ist jedoch verborgen. Kannst Dir wie ein Stern (oder Baum) vorstellen, in der Mitte das Spielfeld und außenrum die Spieler (und ggf andere Objekte) [ - Antworten - Zitieren - Direktlink - ] |
17.06.2010, 15:21 Uhr Der_Wanderer Posts: 1229 Nutzer |
Das Problem ist, dass bei OOP ein stärkeres Gewicht auf der Planungsphase liegt. Das ist gut für erfahrene Programmierer, weil es danach leichter geht. Das ist schlecht für unerfahrene, weil sie die Strukturen erst während der Implemeentation ausbauen, und sich somit von Anfang an Dinge verbauen können die später in einem hässlichen Gewurstel enden. Wenn du also OOP machen willst, dann überlege dir genau, wann wer welche Information braucht. Ich habe es nicht so wirklich ganz verstanden was du machen willst, aber einen "Stack" sicher nicht. Du willst ja, wenn der Spieler eine andere Aktion anwählt, dir nicht die vorherige merken sondern überschreiben. Und Global machen weil man keine geeignete OO Struktur findet ist quasi Tabu, damit würdest du die OO Idee untergraben. Dann kannst du auch gleich "ganz normal" procedural programmieren, weil du den Vorteil der Kapselung verlierst (z.b. beliebig viele Spieler machen, du parallel und unabhängig voneinander agieren können). Ich denke du brauchst lediglich ein Feld "action" in deinem Spieler Objekt, das sich merkt welche Aktion der Spieler ausgewählt hat, damit man beim klick in das Spielfeld entsprechend reagieren kann. Das Feld kann dann verschiedene Werte annehmen z.b. "ACTION_NONE", "ACTION_BUILD", "ACTION_...". -- -- Author of HD-Rec, Sweeper, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, AudioConverter, ScreenCam, PerlinFX, MapEdit, AB3 Includes und viele mehr... Homepage: http://www.hd-rec.de [ - Antworten - Zitieren - Direktlink - ] |
17.06.2010, 20:51 Uhr Reth Posts: 1858 Nutzer |
Zitat: Hab ich auch nicht behauptet. Dass ein Spieler eine Gebäude errichten will, weiss sicher nur er. Dass aber eins errichtet wird, muss er mit bekommen und genau so das Spielfeld. Daher die Idee, eine zentrale Stelle zu haben (global ist hier der falsche Ausdruck gewesen), an der solche Aktionen vermerkt werden, die nicht nur eine Klasse betreffen. Ein Vermerk einer neuen Aktion als nächste auszuführende beim Linksklick finde ich eher nicht so zielführend, da ein Linksklick auf einen Button z.B. eine andere Aktion vorbereiten kann oder die gewählte Aktion für den Spieler wieder zurücknimmt. @All: Ich möchte vermeiden, dass jede Klasse jede andere kennen muss, damit Aktionen entsprechend durchgeführt werden. Mein Punkt ist hier: Wie wird die Information "Linker Mausklick" in "Spieler errichtet Gebäude" übersetzt? Für Maus-bezogene Intuition-Messages habe ich eine Art allgemeiner Listener, der auf Mausklicks und Mausbewegungen reagiert. D.h. die Informationen "Linker Mausklick" + "Klick aufs Spielfeld" + "Spieler will Gebäude errichten" müssen irgendwie zusammen finden. Und hier habe ich noch kein gutes allgemeines Konzept, was solche Zusammenhänge angeht (das hier ist ja nur ein konkretes Bsp.). Zudem gibt es ja auch Aktionen, die nicht durch den Spieler, sondern z.B. zeitlich ausgelöst werden! Kompliziert zu erklären! Generell versuche ich mit möglichst einheitlichen Strukturen die Aktions- und Interaktionsmöglichkeiten zu gestalten. Bisher gehören zu diesen Strukturen z.B. Aktionsklassen, die man an bestimmte Auslöser (z.B. Buttons, zeitliche Trigger) usw. hängen kann. Die Aktionsklasse an dem Button für den Gebäudebau schaltet z.B. den Cursor entsprechend um. Die noch zu gestaltende Aktion "Gebäude errichten" müsste dann z.B. dem Spieler, dem Gebäude und dem Spielfeld Bescheid geben! Nur wie bekommt diese Aktion mit, dass sie ausgelöst wurde? Als Nächste Aktion an den linken Mausbutton zu hängen finde ich wie oben gesagt nicht so gut. Weiss nicht, ob das nun verständlicher war? [ - Antworten - Zitieren - Direktlink - ] |
17.06.2010, 20:56 Uhr Thore Posts: 2266 Nutzer |
Beispiel: Die Spieler kennen das Spielfeld. Klickt ein Spieler eine Aktion an, weiß das nur dieser Spieler. Erst wenn der Spieler aufs Spielfeld klickt, übergibt er dem Spielfeld in diesem Slot seine Aktion. Vorher weiß das Spielfeld nichts. Du hast damit also keine verwobene Struktur sondern nur Spieler->Spielfeld und ggf Spielfeld->Spieler. Oder Du machst ein Context der alle Spieler und das Spielfeld kennt, und arbeitest über den. [ - Antworten - Zitieren - Direktlink - ] |
17.06.2010, 21:10 Uhr Reth Posts: 1858 Nutzer |
Zitat: Genau! Das war auch eine Idee in Abwandlung des Stack-Gedanken, die ich im letzten Beitrag mit der "zentralen Stelle" beschrieben hatte. Dort sind alle Objekte bekannt und dort können auch Zustände hinterlegt werden, die nicht nur ein konkretes Objekt betreffen. Z.B. die Aktion "Spieler will Gebäude errichten" kann natürlich allein im Spieler vermerkt werden. Die Aktion "Gebäude errichten" ist dann eher was für die zentrale Instanz und ergibt sich aus dem Linksklick ins Spielfeld, sowie dem Zustand im Spieler "Will Gebäude errichten" (geht dann nur bei einem menschlichen Spieler - anderen Falles kann in der zentralen Instanz vermerkt werden: Spieler XY will Gebäude errichten). Die zentrale Instanz löst daraufhin beim Spieler das Hinzufügen eines neuen Gebäudes aus, sagt dem Spielfeld wo sich das Gebäude befindet und lässt beim Gebäude die Aufbauanimation ablaufen usw. Dadurch muss nur die zentrale Instanz alle diese Objekte kennen. [ - Antworten - Zitieren - Direktlink - ] |
17.06.2010, 21:25 Uhr Der_Wanderer Posts: 1229 Nutzer |
So eine Zentrale Instanz ist meistens eine Verzweifelungstat, um altbekannte Herangehensweisen in OOP reinzupressen. Was ein Spieler vorhat, ist alleine Sache des Spielers. Wenn du anfängst, eine Liste zu speichern in einem Globalen Kontext der Dinge enthält die spielerspezifisch sind dann ist das falsch. Deshalb hast du ja verschiedene Spieler Instanzen. Wenn das Gebäude gebaut wird, ist das alleine Sache des Spielfeldes. Also der Spieler bekommt ein Feld "action". Das Spielfeld bekommt eine Liste mit gerade bauenden Objekten. Wenn ein Mausklick passiert sollte das als Event an den aktuellen Spieler gehen (diese Information ist am Besten in dem Event Listener untergebracht). Der Spieler weis ja was er "vorhat" und kann dann im Spielfeld die entsprechende Aktion anhängen. Das sollte aber nicht direkt an den Mausklick gekoppelt sein. Der Mausklick sollte von einem Event Listener abstrahiert werden, sodass du nicht nur gezwungenermaßen von der GUI Befehle entgegen nehmen kannst, sondern z.B. via Internet oder KI, und das muss aus Spielersicht durch die gleichen Methoden realisiert werden. Also Spieler.baue(), Spieler.bekommePunkte() etc. Niemals eine Codezeile zweimal schreiben, dann simmt was nicht mit dem Design. -- -- Author of HD-Rec, Sweeper, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, AudioConverter, ScreenCam, PerlinFX, MapEdit, AB3 Includes und viele mehr... Homepage: http://www.hd-rec.de [ - Antworten - Zitieren - Direktlink - ] |
17.06.2010, 21:52 Uhr Reth Posts: 1858 Nutzer |
Zitat:Jain. Der Bau des Gebäudes ist mehrteilig:
Zitat:Hier bin ich mir unschlüssig, ob ich dem Listener wirklich das Spielerobjekt als Parameter bzw. als Member mit geben will. Eigentlich eher nicht. Zitat:Hier kommen wir schon eher in die Region, die ich gerade anstrebe: Es gibt allgemeine Actions, die bei bestimmten Ereignissen ausgeführt werden sollen. Z.B. gibt es eine Action, die ausgeführt wird, wenn man den Button für das Errichten eines Gebäudes drückt. Dieselbe Aktion kann ich aber auch wie gesagt einem Menüpunkt oder einem Hotkey mitgeben. Die Aktion bekommt alle benötigten Objekte, die mit ihr zusammen hängen. Das Gleiche möchte ich natürlich auch für alle anderen Aktionen durchführen, wobei hier Aktionen, die durch verschiedene Spieler identisch ablaufen können entweder als spezifische Subklassen designed würden oder parametrierbar sein müssten. Zitat:Völlig d’accord. Das sollte jedem einleuchten! [ - Antworten - Zitieren - Direktlink - ] |
18.06.2010, 17:36 Uhr Holger Posts: 8116 Nutzer |
Zitat:Die Errichtung eines Gebäudes ist ein Vorgang, der mit der Aktion, die zur Errichtung führte, überhaupt nichts mehr zu tun hat. Ich nehme doch mal an, dass es bereits einen Speicherplatz für existierende Gebäude gibt, vorzugsweise mit der Karte/dem Spielfeld assoziiert. Und genau da werden normalerweise auch Gebäude gespeichert, die sich gerade im Bau befinden. Schließlich können sich (nahezu) beliebig viele Gebäude im Bau befinden, aber pro Spielfeld/Position nur genau eines. Im Bau befindliche Gebäude unterliegen denselben Regeln wie fertige, deshalb muss man da auch kaum einen Unterschied machen. Zitat:Dann hast Du ein Problem. Schließlich kannst Du "A führt zu B" nur über eine Verknüpfung von A nach B implementieren. Du kannst allenfalls noch ein paar Indirektionen oder Schnörkel einbauen, die den Code nicht wirklich besser machen. Zitat:Vielleicht solltest Du Dir den Workflow nochmal ganz genau aufschreiben, und dabei penibel auf den Punkt achten, wann aus dem Vorhaben, das nur den Spieler etwas angeht, ein Zustand wird, der auch die anderen Spieler, bzw. die Spielwelt beeinflusst. Zitat:Du solltest Dich nicht so an dem Linken Mausknopf hochziehen, von dem wir hier immer sprechen. Es gibt einen ganz klaren Grund, warum der erste Klick auf den Button (oder die Menüauswahl oder der HotKey) nicht zum sofortigen Baubeginn führt: wir brauchen noch die Koordinaten für das Gebäude. Wenn wir "Klick mit linkem Mausbutton" sagen, meinen wir also eine Methode zur aktiven Koordinatenauswahl, die Du natürlich beliebig abstrahieren kannst. Deshalb gibt es grundsätzlich zwei Aktionen, eine zur Auswahl des Vorhabens und eine zur Auswahl der Koordinaten. Egal, wie Du es machst, die zuerst ausgewählte Aktion bestimmt die zweite. Und erst wenn beide ausgewählt wurden, beginnt der Vorgang, der auch für die restliche Spielwelt sichtbar ist. -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
19.02.2012, 17:37 Uhr Reth Posts: 1858 Nutzer |
Hallo zusammen, ich greife das Thema wieder auf, da ich an dieser Stelle immer wieder vorbei komme und mit meinem bisherigen Design alles andere als zufrieden bin. Das merke ich auch daran, dass ich mehr refactoring betreibe als progressive Entwicklung. Der Punkt den Der_Wanderer ansprach trifft hier vollkommen zu: Die Gedanken, die ich mir ursprünglich dazu gemacht hatte waren wohl unzureichend/die falschen/was auch immer. Den Punkt, den Holger hier angesprochen hatte finde ich schon ganz gut: Objekten, die es benötigen Infos über UI-Ereignisse mitzuteilen (im Bsp. oben dem Spielfeld eine LMB-Aktion zu verpassen, die bei LMB-Ereignissen, welche das Spielfeld betreffen aktiviert wird). Eine Idee, die mir hierzu kam wäre es, solchen Objekten eine Schnittstelle zu verpassen und ihnen immer alle LMB-Ereignisse (um beim Bsp. zu bleiben) mitzugeben. Die Objekte müssten dann selbst wissen, ob sie was zu tun haben oder nicht. Was haltet ihr davon? Ein anderes "Problem", das ich noch habe ist Folgendes: Für die Darstellung der aktuell ausgewählten Aktion des Spielers nutze ich einen "Cursor" dieser ändert sein Aussehen in Abhängigkeit der gewählten Aktion. Das hatte ich bisher mit reinen Animationsobjekten gelöst, die ich auch an anderer Stelle nutze (z.B. für Gebäude, Landschaften etc.). Jedes Animationsobjekt kann dabei un-/sichtbar geschalten werden. Animationsobjekte selbst haben aber keine Logik zur Ermittlung ihrer darstellenden Koordinaten und bekommen diese "von außen" gesetzt. Nun gibt das beim Cursor das Problem, dass dieser je nach Aktion entweder am Mauszeiger klebt (also quasi jede x-/y-Koordinate bekommen kann), oder aber nur an bestimmten Stellen des Spielfeldes auftauchen darf (hier bestimmt eine "externe" Logik, welche das sind). Mein Ansatz derzeit ist, dass ich eine Cursorklasse geschrieben habe, welche das Animationsobjekt enthält und zusätzlich besagte Logik bereitstellt (und auch alle weiteren Logiken, die in dieser Richtung noch kommen mögen). Diese Cursorklasse registriert sich bei einem sog. Receiver, der alle Mausereignisse aus dem Userport des Spielfensters erhält und entsprechende Methoden bereitstellt (ähnlich Listener/Adapter bei Java, hat z.B. ne mouseMoved()-Methode, diese setzt beim Cursor die neue Mauszeigerposition). So weit so gut. Großer Nachteil: Die Cursorklasse muss nun alle notwendigen Methoden der Animationsklasse ebenfalls nach außen legen, damit z.B. das Un-/Sichtbarschalten und das Umschalten der verschiedenen Animationen erfolgen kann. Ein Alternative wäre höchstens noch, die Cursorklasse von der Animationsobjektklasse erben zu lassen (nutze C++), was ich aber nicht wirklich sehe, da hier keine reine IS-A-Beziehung vorliegt (der Cursor ist nun mal kein reines Animationsobjekt, sondern mehr). Habt ihr hier noch ne andere/bessere Idee? Danke schon mal! [ Dieser Beitrag wurde von Reth am 19.02.2012 um 18:29 Uhr geändert. ] [ - Antworten - Zitieren - Direktlink - ] |
23.02.2012, 13:48 Uhr Holger Posts: 8116 Nutzer |
Zitat:LMB klingt für mich nach viel zu „low-level“. Worum es doch eher geht, sind Events wie „Spielfeld selektiert“ (die Konvertierung von Mauskoordinaten in Spielfeld hat das Karten-Objekt bereits durchgeführt) oder „Gebäude/Einheit selektiert“… Zitat:Durchreichen von x Methoden, die man auch immer noch an jede Erweiterung anpassen muss, ist kontraproduktiv. Warum musst Du sie denn überhaupt durchreichen, statt einfach einen Direktzugriff auf das Animationsobjekt zuzulassen? Ich vermute mal, es fehlt Dir ein Mechanismus, mit dem das Cursor-Objekt erfahren kann, dass sich das Animationsobjekt verändert hat. Konzentriere Dich auf dieses eigentliche Problem, und Du sparst Dir die Arbeit mit den Cursor-Methoden. Weiterer Vorteil: anderen Klassen kann es egal sein, ob die Animation, mit der sie interagieren, am Cursor klebt, auf dem Spielfeld abläuft oder in einem Gadget stattfindet. -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
27.02.2012, 20:41 Uhr Reth Posts: 1858 Nutzer |
Zitat:Bei solchen Events bleibt mir aber der Zshg. zur Folgeaktion unklar. Wenn ich z.B. einen Button anklicke möchte ich, dass am Mauszeiger über dem Spielfeld eine Animation angezeigt wird (je nach Art des gedrückten Buttons), welche die ausgewählte Aktion des Spielers anzeigt, die er nun durchführen kann. Bei einem Klick auf das Spielfeld/ein Gebäude/... soll dann diese Aktion durchgeführt werden. Dabei reicht es ja nicht zu sagen: Gebäude selektiert, sondern es muss ja auch eine bestimmte Aktion auf dem Gebäudeobjekt ausgeführt werden. Zitat:Durchreichen finde ich auch furchtbar. Wozu ich sie brauche ist der Grund: S.o. nach Anwahl eines Buttons eine Animation am Mauszeiger. Diese wurde bisher nur durch ein Animationsobjekt gestellt. Das Animationsobjekt ist nur für Darstellungsaufgaben da und kann untersch. Animationen beherbergen und unabhängig voneinander abspielen (aber immer nur eine auf einmal). Damit konnte ich alles Abdecken. Nun sollen aber manche dieser Animationen nur an bestimmten Koordinaten ablaufen dürfen, an anderen wieder nicht. So eine Logik besitzt das AnimationsObjekt nicht, es empfängt nur Koordination. Also habe ich die Cursorklasse geschrieben. Diese kann unterschiedliche Cursortypen annehmen (genauso wie das Animationsobjekt untersch. Animationstypen annehmen kann, um untersch. Animationen darzustellen). Dazu kann die Cursorklasse an- und ausgeschaltet werden (da die Animation nicht immer sichtbar sein soll, z.B. wenn wieder abgewählt oder Aktion durchgeführt wurde). Das sind alles Methoden, die auf das Animationsobjekt durchgereicht werden! Daher der üble Zusammenhang. Die Cursorklasse erledigt nun mit der Spielfeldklasse das bestimmen der notwendigen Koordinaten wenn bestimmte Aktionen ausgewählt wurden. Bei anderen Aktionen reicht es nur die aktuellen Mauskoordinaten durch. Zitat:Ich probier mich darauf zu konzentieren. Den anderen Klassen ist es auch egal, die dasselbe Animationsobjekt (wenn es denn woanders genutzt werden würde) völlig normal ohne Cursorklasse verwendet werden kann. Momentan sieht mein Konstrkukt so aus (allgemein und ein konkretes Bsp. für Mauseregnisse):
Das gefällt mir überhaupt noch nicht, da ich noch nicht genau weiss, wie ich die Spielabläufe wie: Button gedrückt => Animation anzeigen => Spielfeld/Gebäude geklickt => Aktion beim Spieler ausführen und dabei andere Animation abspielen! Es klappt immer nur ein Teil gut, der Rest umständlich bis gar nicht! Ich steh immer wieder auf dem Schlauch, wenn auch an unterschiedlichen Stellen! [ - Antworten - Zitieren - Direktlink - ] |
27.02.2012, 23:00 Uhr Holger Posts: 8116 Nutzer |
Zitat:Was kann ein „linker Mausknopf gedrückt“-Event an dieser Stelle mehr leisten als ein „Feld(20, 15, Gras) selektiert“? Zitat:Wir drehen uns im Kreis. Es gibt genau eine aktuell gewählte Gebäude-Aktion und diese sollte der Empfänger des nächsten „Gebäude selektiert“ Events sein. Nach dem Empfang des Events trägt sie sich aus. Zitat:Was heißt „durchreichen“ in diesem Zusammenhang? Besitzt die Animationsklasse bereits die Fähigkeit zum Ein- und Ausschalten? Wenn nicht, ist es kein Durchreichen, wenn doch, wozu dann überhaupt die Cursor-Klasse? Zitat:Warum muss es das tun? Animationen existieren doch nicht im luftleeren Raum. Sie besitzen doch immer einen Kontext oder Parent o.ä., egal, ob das nun ein Fenster, eine Zielbitmap oder ein Cursor ist. Der Knackpunkt liegt doch nur darin, diesen Teil des Animationsmechanismus so allgemein zu halten, dass der Cursor als möglicher Kontext der Animation kein Spezialfall mehr ist. Zitat:Du musst erst mal gedanklich die Ablauf-Logik in eine Zustandslogik überführen. Ganz allgemein gesprochen sind Abläufe Zustandswechel und somit gibt es vor und nach jedem der Schritte Deines Ablaufs einen Zustand, den Du komplett beschreiben kannst. Bzw. können musst. Dann kannst Du hingehen und die Objekte schaffen, die die möglichen Zustände repräsentieren. Wenn die klar sind, ergibt sich der Rest von selbst. Andererseits sind wir damit so weit wie zu Beginn des Threads. Verlierst Du Dich vielleicht zu sehr in Details oder liegt da irgendwo noch eine andere Schwierigkeit, die Du nur nicht ausreichend erklären kannst? -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
28.02.2012, 14:23 Uhr Reth Posts: 1858 Nutzer |
@Holger: Immer wieder danke für Deinen Input muss ich hier schon mal sagen! Zitat:Je nachdem, ob ich Dich falsch verstanden habe nichts oder alles (siehe in den folgenden Antworten). Zitat:Und wie würdest Du hier die Konstellation sowie das Ein- und Austragen aller Beteiligten sehen? So wie ich Deinen Text verstehe erhält das Gebäude verschiedene Aktionen, die ausgewählt werden können (meine Design-Frage dazu wäre: Wie und von wem?). Diese Aktionen warten dann u.U. auf das nötige Ereignis (z.b. Gebäude selektiert; meine Design-Frage hierzu: Wie und durch wen kommt diese Ereignisinformation?). Oder hab ich Dich hier falsch verstanden? Meine derzeitigen Bestrebungen sind eher noch sehr Low-Level orientiert, in dem ich versuche, mir Klassen und Methoden für z.B. Menü-, Maus und Gadgethandling zu bauen, die ich auch in anderen Programmen wieder verwenden kann (ohne ein neues Framework zu erstellen - nur für mich, damit ich die Amiga- und die C++-Programmierung besser kennen lerne). Mit diesem Gerüst versuche ich nun die für das Spiel anfallenden Dinge umzusetzen. Aber vielleicht ist Dein Ansatz hier besser und ich statte meine "Haupt-"Objekte (Gebäude, Spieler, Spielfeld, ...) mit Aktionen aus und muss dann noch austüfteln, wie ich es anstelle, dass diese dann entweder sofort nach Anwahl, oder nach Eintreten von notwendigen Ereignissen loslaufen. Zitat:Ja, die Animationsklasse besitzt die Fähigkeit an- und wieder ausgeschaltet zu werden (bzw. sichtbar/unsichtbar). Ursprünglich war die Cursorklasse auch nicht nötig, da die Mauskoordinaten immer 1:1 an das Cursoranimationsobjekt durchgereicht werden konnten. Dies soll aber im Spiel nicht für alle Varianten der Cursoranimationen der Fall sein. Einige sollen nur an bestimmten Orten auf dem Spielfeld dargestellt werden (z.B. freien Bauflächen). So eine Logik möchte ich nicht in der Animationsklasse abbilden, sondern außerhalb. Daher nun die Cursorklasse. Zitat:Das wäre ein Ansatz. Bei mir sieht es etwa so aus: Die Animationen existieren alle in einem Rastport, den sie bei ihrer Erstellung mitbekommen. Darüber hinaus werden sie nur dargestellt, bekommen (neue) Koordinaten und wissen, ob sie sichtbar sind oder nicht. Animationsobjekte fassen mehrere solcher Animationen zusammen (z.B., um alle für ein Gebäude notwendigen Animationen in einem Objekt zu haben). Sie wissen daher, welche ihrer Animatione gerade die ausgewählte ist, ob sie sichtbar ist oder nicht etc. Auch das Thema Koordinaten geben sie durch (bin mir gerade nicht in allen Punkten 100% sicher, da ich gerade nicht vorm Source sitze - kommt aber so ziemlich hin). Daher passiert hier schon einiges "Durchreichen", von dem ich aber sicher noch den einen oder anderen Teil optimieren könnte (allerdings nicht, wenn Animaitonen auch mal ohne Animationsobjekte genutzt werden können sollen, was ich schon so sehe). Die Cursorklasse nutze ich aktuell nur, um die Koordinatenberechnung zu machen, die in Abhängigkeit von unterschiedlichen Cursoranimationen unterschiedlich ausfällt. Die dafür benötigten weiteren Klassen möchte ich nicht in der Schnittstelle von Animationsobjekten sehen, da sie diese für ihre Aufgaben nicht benötigen. Sie wollen nur die Koordinaten wissen, an denen sie angezeigt werden sollen. Daher kommt mir die Nutzung des Cursors als Context für Animationen an dieser Stelle merkwürdig vor (vor dem Hintergrund meiner bisherigen Source-Konstellation). Da versteh ich gerad nicht, wie das tun sollte. Zitat:Das mit den Details stimmt bei mir bestimmt. Vielleicht spielt der von mir oben beschriebene Punkt hier mit eine Rolle (Low-Level-Objekte für Menü-, Maus- und Gadgethandling), zu dem es ja schon ein Konzept und Klassen gibt. Das Verheiraten dieser Low-Level-komponenten mit dem hier von Dir beschriebenen macht mir gerade noch die Probleme. [ - Antworten - Zitieren - Direktlink - ] |
29.02.2012, 18:56 Uhr Holger Posts: 8116 Nutzer |
Zitat:Moment, das war Deine Vorgabe: zuerst wählt der Benutzer die Aktion, z.B. via Button, dann wählt er den Ort oder das Zielobjekt. Ich würde eher ein Menü bevorzugen, das sich bei der Auswahl eines Objektes öffnet, weil man dann mehr Platz für das Spielfeld hat. Zitat:Das Low-Level-Event geht an das Objekt, das in diesen Einheiten arbeitet, das Mausklick-Event also beispielsweise an das Spielfeld, welches die Pixelkoordinaten verarbeiten kann und daraus ein High-Level-Event wie „(leeres) Feld selektiert“, „Einheit selektiert“ oder „Gebäude selektiert“ generieren und versenden kann. Wenn man die Komponenten besser trennen will, bietet sich eine Event-Bus Architektur an. Das heißt, es gibt genau ein zentrales Objekt, das für die Vermittlung von Events zuständig ist. Empfänger melden sich bei diesem an und Versender laden bei ihm ihre Events ab. Der Event-Bus sorgt dann dafür, dass alle für diesen Event-Typ (ID, Name, whatever) registrierten Empfänger das Event erhalten. Vorteil: die Empfänger müssen die Quelle nicht kennen, um sich zu registrieren und die Zuständigkeiten können auch viel leichter geändert werden. Zitat:Das ist ok, aber diese Low-Level-Dinge sollten letztendlich auch bei den Low-Level-Objekten bleiben. Die Anwendungslogik sollte davon nicht beeinflusst werden. Wiederverwendung ist ja an sich ein gutes Ziel, nützt nur gar nichts, wenn man es nicht schafft, überhaupt einen Anwendungsfall zu implementieren. Dann sollte man aufhören, auf hypothetische Wiederverwendung Rücksicht zu nehmen und anfangen, ganz pragmatisch nur für die eine aktuelle Anwendung zu entwickeln. Hinterher kann man immer noch gucken, was man für spätere Anwendungen ausschlachten kann. Zitat:Denke abstrakt. Die Animationen kennen einfach ein Objekt, das ihnen ihre Koordinaten liefert. Mehr nicht. Dieser Koordinaten-Lieferant kann ein ganz triviales Objekt mit fixen Koordinaten sein, aber auch ein Gadget, das immer Koordinaten relativ zur eigenen Position liefert, oder auch ein Cursor. -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
-1- | [ - Beitrag schreiben - ] |
amiga-news.de Forum > Programmierung > Steuerung zwischen GUI und "Ausführern"? | [ - Suche - Neue Beiträge - Registrieren - Login - ] |
Impressum |
Datenschutzerklärung |
Netiquette |
Werbung |
Kontakt
Copyright © 1998-2024 by amiga-news.de - alle Rechte vorbehalten. |