![]() |
Anregung für Klassendesign
Hallo,
ich brauche (nicht direkt für ein Spiel auch wenn's so aussieht) ein paar Anregungen, wie ich die Klassen meiner Geschäftslogik aufbaue, bzw. welche Klassen ich eigentlich brauche und wer da wen kennen sollte. - Ich habe ein "Spielfeld" bestehend aus einzelnen Feldern (entweder Schachbrett-Muster oder Hex-Felder). - Jedes dieser Felder kann Eigenschaften haben (und natürlich Koordinaten). - Auf jedem dieser Felder können Objekte liegen, die Eigenschaften haben, wobei die Eigenschaften der Felder beeinflussen können, was für Objekte auf dem Feld liegen können. - Auf jedem dieser Felder können "Figuren" stehen, die sich über das Spielfeld bewegen können, wobei Art und Reichweite der Bewegung von den Objekten auf den Feldern, von den Feldern selber und von den Eigenschaften der Figur beinflusst werden können. u.a. Aufgaben, die die Logik können muss: Wenn ich ein Objekt auf dem Plan platzieren will, muss ich wissen, wo ich das ablegen darf und wo nicht. Wenn ich eine Figur bewegen will, muss ich sehen können wie weit sie maximal kommt, und auf welche Felder ich sie stellen kann. Die Aufgaben hören sich so beschrieben natürlich nach Dingen an, die eher die View betreffen ("Muss ich sehen können"), aber irgendwie muss die View ja später auch wissen, welche Felder sie mir irgendwie markiert, damit ich sehen kann, wohin eine Figur gesetzt werden darf. Daher die Zusatzfrage, wie würde man die Kommunikation mit einer View und der Logik umsetzen? Würden da einfach Listen mit Feldkoordinaten bereitgestellt, oder wie macht man sowas? |
AW: Anregung für Klassendesign
Da müßte man erst mal wissen welche Form die Felder haben (Rechteck, Kreis, Polygon)?
|
AW: Anregung für Klassendesign
Echt? Muss nicht. Ein Feld ist ein Feld und hat Nachbarn. Ein quadratisches Feld hat 4, ein hexagonales Feld eben 6. Aber es ist ein Feld. Dieses Model kann man später auf 5-dimensionale Hyperräume erweitern. Es bleibt dabei. Ein Feld ist ein Feld und ich kann von einem Feld auf bestimmte andere hüpfen.
Zur Frage: Ich würde deine Klassen, Eigenschaften und Methoden erst einmal in Objectpascal aufschreiben, denn deine Beschreibung kannst Du 1:1 auf deine Klassen anwenden. Die genauen Eigenschaften sind zwar nicht bekannt, aber die Methoden ('Darf ich? Wo könnte ich hin?' etc) schon. Und damit sind auch die Abhängigkeiten grob skizziert, denn für eine bestimmte Entscheidung oder Aufgabe benötigt eine Figur das Wissen um 'Felder' und vielleicht sogar auch 'Objekte'. Durch die Abhängigkeiten muss z.B. ein Objekt auch 'Felder' kennen, denn es muss ja wissen, ob es da rauf darf. Wenn Du die groben Abhängigkeiten umgesetzt hast, schaust Du dir jede Klasse an. Wenn z.B. eine Figur -neben der schönen Aufgabe, eine Figur zu sein- noch andere Aufgaben hat (z.B. 'Darf ich auf dieses Feld?') dann schreibst Du dir eine Klasse, die diese Entscheidung fällt, also einen 'TFigurLocator' oder so. Damit hat die Figur diese Aufgabe delegiert. Da sich Objekte und Figuren bezüglich diverser Entscheidungen nicht unterscheiden, können sie eine gemeinsame Basisklasse haben, müssen aber nicht: Bloß weil ein Tisch und ein Pferd jeweils 4 Beine haben, sollte man keine Basisklasse hierfür erstellen. Die Gemeinsamkeit könnte sich auch über ein Interface und eben die 'TXXXXLocator'-Entscheiderklassen abbilden lassen. Ich würde 'einfach mal anfangen' und hier den Ansatz posten. Wirst schon sehen, wie gut die Ratschläge sind... :thumb: Crossreferences solltest Du vermeiden, z.B. durch oben skizzierte Delegierung an eine separate Klasse: a <-> b => a -> c <- b Anstatt : 'a kennt b und umgekehrt' (was eine zirkuläre Referenz ist) macht man: 'a kennt c und b kennt c, c kennt a und b. Aber a und b kennen sich nicht mehr'. Mit Sicherheit gibt es noch andere Wege zum Ziel, aber ich würde es so machen bzw. so erst einmal anfangen. |
AW: Anregung für Klassendesign
Zitat:
|
AW: Anregung für Klassendesign
Das ermittelt der Controller, dafür ist er da.
|
AW: Anregung für Klassendesign
Das Spielfeld unterscheidet sich nicht wesentlich, egal ob rechteckige oder Hexfelder:
Code:
Die einzelnen Felder haben abhängig von der Geometrie andere Nachbarfelder.
Geometrie recheckige Felder
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X Geometrie Hexfelder horizontal versetzt X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X (für vertikal einfach 90Grad drehen) Will man diese bestimmen, braucht man dafür jeweils eine eigene Enumeratorklasse, die die einzelnen Nachbarfelder und Richtung zurückgibt. Damit die Figuren bestimmen können, wo man diese setzen kann und welche Felder erreichbar sind, muss Ihnen das Spielfeld und dessen Geometrie bekannt sein. Die Ergebnisfelder würde ich mit einem Enumerator zurückgeben. |
AW: Anregung für Klassendesign
Zitat:
Type
Delphi-Quellcode:
Fertig. Im Schachbrett hat Feld 'A1' drei Nachbarn, H5 dagegen 8, wenn man die Diagonal erreichbaren hinzuzählt. Ansonsten 2 bzw. 4. Oder eben 6 oder 26 (3-D Schach). Alles ein und dieselbe Struktur.
TFeld = class ...
property Nachbarn : TFeldListe read fFeldListe; end; Ich kann das komplett entkoppeln. Mit dem Modell kann ich auch komplette Labyrinthe bauen, oder beliebige topologische Netze aufspannen. Ob das das schnellste ist und am wenigsten Speicherplatz verbrät, sei mal dahingestellt. Aber am flexibelsten ist es allemal, weil ich -entgegen allen Behauptungen- in der Logik komplett unabhängig vom Layout bin. |
AW: Anregung für Klassendesign
Zitat:
|
AW: Anregung für Klassendesign
Ich fang mal klein an, um zu erläutern, wie sehr ich mit der ganzen Geschickte noch am Anfang stehe. Ich würd halt gerne meine Klassen direkt von Anfang an sinnvoll planen als das immer wieder umzustricken.
Delphi-Quellcode:
Hier fängt meine unsicherheit dann direkt schon an. Muss die Figur ihre Koordinaten wissen, oder weiß eine übergeordnete Kontroller-Klasse oder das Spielbrett wo sich die Figur befindet. Oder weiß das Spielfeld um seine Felder und die Felder wissen welche Figur auf ihnen drauf steht?
TFigur = class
private Bewegungsweite:integer; //X:integer; //Y:integer; public //procedure MoveTo(X,Y:Integer); end; Ist die MoveTo Klasse überhaupt Sinnig bei der Figur oder gehört die auch in einen Kontroller? Ich werde mich mal am WE hinsetzen und versuchen das UML-mässig entwerfen. Anregungen sind bis dahin gerne weiter willkommen :) Edit: Es geht mir jetzt wirklich eher darum wie die Klassen zueinander stehen und welche ich alles brauche (und in Folge ein bißchen darum wie die Klasse designed werden musss). Nicht jetzt schon um konkrete Berechnungen oder sowas. Dazu habe ich mich (z.B. für Hexfelder ![]() |
AW: Anregung für Klassendesign
Ich würde der Figur selbst definitiv keine Koordinaten als Zahlen geben. Zumindest dann nicht, wenn man seine Felder ohnehin schon als Klassen abbildet. In die Figur gehört dann allenfalls eine Referenz auf ihr aktuelles Feld - aber das auch nur, wenn unbedingt nötig. Je nach dem kann es schon reichen, wenn ein Feld seine auf ihm befindlichen Teile (inkl. Figuren) kennt.
Gerade bei solchen Doppelbeziehungen, wo sich zwei Instanzen gegenseitig kennen können, sind Controller-Klassen unbedingt sinnvoll. Sonst hat man schneller als man meint auf ein Mal ein Feld, dass meint Figur X stünde auf ihm, Figur X meint aber felsenfest ganz wo anders zu stehen. Ein Koordinatensystem ist bei einem Spielfeld als Netz von Klassen sogar nichtmals mehr nötig, es sei denn man benötigt es aus irgendwelchen anderen Gründen. Lauf-Distanzen sind sogar noch über die Anzahl der genommenen Feld-Referenzen hin zum Ziel abzählbar. |
AW: Anregung für Klassendesign
Zitat:
(ich nehme mal an, es geht nicht um die Koordinaten für das selbstzeichnen) Gruß K-H |
AW: Anregung für Klassendesign
Ich hatte meinen Beitrag vorhin verworfen, aber da Du von vorn anfangen willst:
Das wichtigste ist m.E. erst mal, dass Du GUI und BL trennst. Also alles, was Du überlegst und in Klassen abbildest sollte sich auf reine Daten/Objekte beziehen. Die Darstellung in einem Formular solte da erst mal noch keine Rolle spielen. Wenn Du das sauber einhältst wird Dein Projekt besser wartbar und scalierbar bleiben. So kannst Du ein komplettes (virtuelles) Projekt in BL-Klassen definieren. Die Darstellung und Bearbeitung im Formular wäre ein davon völlig losgelöstes (bzw. parallel zu entwickelndes) Thema. Natürlich brauchst Du eine Schicht dazwischen, die beide Seiten verbindet. Der Aufbau der BL-Klassen ist dann eher Geschmacksache und von der Zielstellung des Projektes abhängig. Grundsätzlich würde ich die Position einer Figur in Figur.x und Figur.y speichern. Das irgendwo in einem Array abzulegen würde vielleicht Sinn machen, wenn man extrem schnell Berechnungen mit den Berechnungen durchführen will und der Weg über die Figuren zu langsam wäre - aber normalerweise wäre das sicher nicht sinnvoll. Auch ob man eine Figur in ein Feld einfügt (Owner) oder in das Spielfeld (und die Beziehung zu den Feldern explizit verwaltet) oder ob man jeder Figur ein Spielfeld und ein Feld zuweisen will hängt wohl von der Zielstellung ab. Ich habe in meinem letzten Projekt jedenfalls nicht Owner benutzt um die Beziehungen abzubilden da dadurch in der Summe ziemlich viel Zeit verbraucht wurde (Observer), die ich lieber anders nutzen wollte. Auch wo Du MoveTo implementierst musst Du vom Einzelfall entscheiden. Wichtig ist jedenfalls, alles möglicht gut vonenander zu entkoppeln - sowohl die GUI von der BL als auch die Klassen untereinander. Wenn Du irgendwann denkst, FigurA bräuchte jetzt mal schnell die dritte Figur auf Feld123 ... hmmm... ok, dafür muss die Figur mal schnell wissen, wie ein Feld aufgebaut ist und dessen Figursammlung durchsuchen ... dann solltest Du stutzig werden. Und wenn Du in der Richtung weiter denkst wirst Du irgendwann auf Interfaces kommen. Das ist aber ein weiteres Thema (für mich auch ein recht neues)... Weiterhin wichtig ist die Persistenz der BL-Objekte. Wenn Du ein Spielfeld hast und darauf Felder und darauf Figuren, dann sind das Objekte mit (Speicher-)Adressen. Wenn Du den Zustand speicherst (z.B. in einer XML-Datei) und später wieder lädst, dann liegen die Objekte natürlich an ganz anderen Adressen im Speicher. Somit brauchst Du eine Möglichkeit, die früheren Beziehungen ("Figur134 hat Figur345 als Freund") wieder herzustellen. Daher müssten die Objekte eine ID erhalten, über die sie identifizierbar sind und über die auch Verweise wieder hergestellt werden können. Gleiches gilt natürlich, wenn Du nicht alle Objekte gleichzeitig im Speicher halten willst oder kannst bzw. vielleicht über mehrere Clients auf den gleichen Datenbestand zugreifen möchtest (ich weiß, wovon ich rede ;-)). Fazit: Möglichst klare Klassen bauen, die möglichst wenig voneinander abhängen und die Objekte mit Id´s ausstatten. So wirst Du am weitesten kommen. |
AW: Anregung für Klassendesign
Zitat:
Figur können aber nur bestimmte Bewegungen oder Richtungen zulassen und mehrere Felder zurücklegen oder überspringen (Läufer oder Springer). Da braucht dann jede Figurtyp noch mal einen eigenen Enumerator (der auf das Spielfeld und dessen Enumerator(en) zugreifen kann) und der ist abhängig von der Feldgeometrie. Aber das geht schon viel zu sehr ins Detail. |
AW: Anregung für Klassendesign
Mir ging es hier nicht um das 'sinnvoll', sondern ob es notwendig ist. Lies Dir mal bitte den ganzen Thread durch. Da wurde behauptet, ohne Spielfeldlayout ginge es nicht, was nicht stimmt. Es *geht* ohne.
Im Übrigen kann ich bei so einer Datenstruktur natürlich auch Springerzüge ermitteln. Und zwar schneller, als mit einer 8x8 Matrix auf herkömmliche Art und Weise. Man muss nur wissen, wie :mrgreen: Aber das gehört hier ja nicht hin. Hier geht es um ein Spielfeld mit Feldern, Figuren und Objekten. Bis es es nicht klar ist, wie die Felder angeordnet sind. Also würde ich mal behaupten, also ich behaupte sogar, das mein Ansatz der bisher einzig brauchbare. Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:05 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz