# Aufbau von Klassen für Spiel



## Sphinx2k (26. Jan 2012)

Hallo,
Ich möchte ein Spiel in der Art von Master of Orion (Erklärung weiter unten) erstellen, ziel soll ehr sein mehr über das Programmieren zu lernen als ein Blockbuster zu erschaffen. 
Version 1 soll so aussehen. 
Man startet auf einem Planet und Raumschiff und kann dieses dann zu einem anderen Planeten schicken um ihn zu Kolonisieren. 
Jetzt kommt mir die Überlegung: hmm gebe ich dem Raumschiff Funktionen um von A nach B zu fliegen, eine Funktion um den Planeten zu Kolonisieren. Was in etwa den Simpel Programmierbeispielen nach Schema Programmiere eine Klasse Auto welche Funktionen zum Starten und Losfahren hat.
Selbst mit Vererbung von einer Superklasse kommt mir das recht Statisch vor bei dem was ich evtl. noch alles einbauen möchte.
Meine Idee ist jetzt in etwa für jede mögliche Handlung eines Raumschiffs eine eigene Klasse zu erstellen. Eine Klasse FliegeNach, eine Klasse Kolonisieren. Meine Raumschiffsklasse hat dann einmal ein Array mit allen Handlungen die es tun kann um diese Nachzuschlagen/Anzuzeigen. Wird jetzt eine verwendet wird diese an ein neues Array "Warteschlange" angehängt, welche dann Stück für Stück abgearbeitet wird. 
Pseudoablauf für das Kolonisieren. 
Klick auf Raumschiff.
Im Array schauen was es kann und die Optionen in einem Menü anzeigen.
Bei klick auf Kolonisieren ein Ziel erwarten.
Nach dessen auswahl eine neue Instanz von FliegeNach in der Warteschlange erstellen, gefolgt von einer Kolonisiere Instanz.

Kommt mir im ersten Moment erst mal wie eine gute Idee vor das so zu machen. Aber ist es das wirklich?
Ich möchte eine Struktur haben die ich eben erweitern kann wenn ich möchte ohne jedes mal den Kompletten Quellcode umzugraben wenn ich eine neue Idee hab was für ein Feature ich einfügen möchte.


----------



## Tomate_Salat (26. Jan 2012)

Du solltest dir OOP nochmal genau ansehen. Man erstellt nicht für jede "Handlung" eine eigene Klasse. Wenn dann hast du eine Klasse Raumschiff mit den Methoden: 
- fly
- land
- doHitTheEvilRedButtonWhichForcesASupernovaSelfDestruction

Wenn du Eigenschaften ausdrücken willst, dann arbeite mit Interfaces:

class Raumschiff implements FlyAble, SelfDestructAble

Vllt nochmal die Basics anschauen, erstmal mit Konsolenanwendungen zufrieden geben. Danach empfehle ich dir mal Quaxlis tutorial durchzuarbeiten.


----------



## HimBromBeere (26. Jan 2012)

Du solltest auf jeden Fall einige Interfaces erstellen, wie bereits erwähnt ein FlyAble-Interface (das sind z.B. Raumschiffe, aber können auch Kometen oder Katzen sein (man staunt nicht schlecht, was man da sol alles finden kann...)). Dieses Interface schreibt Methoden wie fly, land, unload (Passagiere entladen) und die bereits erwähnte superNovaSelfDestructOnRedEvilButtonHit. 

Methoden speichert man nicht in einem Array ab, das ist Blödsinn (zumahl das auch gar nicht mal soooo einfach ist für den Anfang...). 
Alle deine Himmelsobjekte (Planeten, Raumschiffe, Katzen, ...) erben irgendwann auch von einer Superklasse SoaceObject, die z.B. eine Methode checkOnCollision(anderesSpaceObject) kennt (diese Methode hast du dann in allen Objekten am Himmel: Raumschiffe, Planeten, Katzen, Raketen...). 
Ein Planet könnte eine Art statischer Himmelskörrper sein, der zusätzlich auch noch eine Methode zur Bevölkerung besitzt sowie eine doNotMoveToBeAsMeaninglessAsPossible().


----------



## Gast2 (26. Jan 2012)

Also soo abwegig finde ich es nicht die Aktionen als eigene Klassen zu definieren, siehe strategy pattern. Dann könnte man auch 



> Methoden speichert man nicht in einem Array ab, das ist Blödsinn (zumahl das auch gar nicht mal soooo einfach ist für den Anfang...).


Blödsinn finde ich das nicht. Ich weiß zwar nicht wie genau das Spiel ablaufen soll, aber ich kenns so dass man Einheiten mehrere Befehle geben kann, wie bspw. "Fliege nach x", "Kolonisiere y", "Fliege nach z". Wenn man die Aktionen als eigene Klasse modelliert hat besitzt das Raumschiff einfach ne 
	
	
	
	





```
List<Action>
```
.


----------



## Tomate_Salat (26. Jan 2012)

Sagt ja niemand was dagegen, dass eine Klasse/Interface nur eine Methode implementiert. Aber wenn der TO für jede Aktion eine eigene Klasse erstellt und diese noch "FliegeNach" nennt, dann verfehlt das wieder sein Ziel. FliegeNach, Koloniesiere,... sind geeignete Namen für Methoden, aber nicht für Objekte. 

Es sollte nicht das Ziel sein, für jede Aktion eine eigene Klasse zu schreiben, sondern diese sinnig auszulagern.


----------



## Sphinx2k (26. Jan 2012)

Jetzt bin ich vollends verwirrt, und ich versuche noch mal etwas aufzuklären was ich meinte.
Aktuell hab ich eine Abstrakte Oberklasse Weltraumobjekt davon erbt die abstrakte Klasse BeweglichesWeltraumobjekt und davon ist ein Raumschiff abgeleitet. 
Die Weltraumobjekt Klasse hat natürlich Sachen wie x,y Koordinaten, Methoden wie Draw() und co. BeweglichesWeltraumobjekt aktuell so etwas wie flugrichtung und geschwindigkeit.
Klar kann ich jetzt in der BeweglichesWeltraumobjekt Klasse eine MoveTo(WeltraumObjekt X) erstellen, oder ein Interface welches Methoden einbringt, die ich dann ausformuliere. 
Dann brauche ich aber z.B. noch eine Liste welche mir die Aktionen speichert die geplant sind, eine Funktion Arbeitet diese liste dann ab und ruft die Passende Funktion auf. 
Würde funktionieren möchte ich gar nicht absprechen.

Hätte ich ein Objekt "Flug" könnte ich dem Sachen wie.
Weltraumobjekt ziel;
double geschwindigkeit
. . . . .
und deine doIt() Methode mitgeben die das ganze ausführt. 

Jetzt brauche ich nur eine Liste zu haben an der bei jedem neuen Befehl so ein neues Objekt angehängt wird welche dann abgearbeitet wird. 
Mir kommt diese Variante immer noch "schlauer" vor, aber ich möchte in erster Linie ja was daraus lernen und mir dann doch lieber einen ordentlichen Stiel angewöhnen. 
Ich bin auch über Tipps dankbar welche Literatur was Klassen Design angeht sinnvoll ist. Die meisten gehen aber auf das Prinzip ein, machen ein Mini bespiele und das war es, das Große Gesamtbild hat sich daraus noch nie für mich ergeben (Einer der Hauptgründe warum dieses Lernprojekt).


----------



## Tomate_Salat (26. Jan 2012)

Such mal nach dem Forum-user [c]Quaxli[/c] und lade dir das Tutorial aus seiner Signatur herunter. Da beschreibt er ganz gut, wie man 2D-Spiele entwickelt. 

Wenn du das Beispiel mal durchgearbeitet und verstanden hast, wird denke ich dein Vorhaben um einiges klarer.


----------



## Firephoenix (26. Jan 2012)

Bzw Literatur:
Galileo Computing :: Objektorientierte Programmierung - Das umfassende Handbuch
und Design Patterns von Gamma et al für passende Entwurfsmuster.

/Befehle als objekte geht übrigens eher in die Richtung Command Pattern, Strategie kapselt keine Befehle sondern die Art wie mit Befehlen umgegangen wird.

Gruß


----------



## HimBromBeere (27. Jan 2012)

> und deine doIt() Methode mitgeben die das ganze ausführt.


OK, ich hab kapiert, was du willst, aber als wirklich sinnvoll erachte ich es immer noch nicht. Um die Aktionen - wie du sie nennst - in eine Liste zu speichern - musst du diese doch auch wenigstens vom Namen her kennen, formulieren musst du sie auch hin wie her, also was spricht gegen

```
BeweglichesObjekt Raumschiff = new Raumschiff();
Raumschiff.bewege();
Raumschiff.prüfeKollision(...);
Raumschiff.drueckDenBosenRotenKnopfundZerstoreDamitAllesLebenUndDasUniversum()
```
und für

```
List<Action> actions = new ArrayList<Action>;
actions.add(bewege);
actions.add(prüfeKollision (über Parameterübergaben musst du dir auch noch Gedanken machen...));
actions.add(drueckDenBosenRotenKnopfundZerstoreDamitAllesLebenUndDasUniversum);

raumschiff.arbeiteAb(actions);
```
Versteh ich ehrlich gesagt nicht...


----------



## Sphinx2k (27. Jan 2012)

Firephoenix seine Nachlese Tipps werde ich mir jetzt erst einmal durchlesen und erst danach weitermachen. Interessieren würde mich aber schon ob ich hier so auf dem Holzweg bin oder ich nur nicht richtig dargelegt hab wo ich das Problem sehe. 
Das Tutorial von Quaxli kenn ich und das ist für sich gut aber kratzt leider nicht mal an was meine Überlegung/Problem ist.



			
				HimBromBeere hat gesagt.:
			
		

> Versteh ich ehrlich gesagt nicht...



Erst einmal spricht da natürlich gar nichts gegen das so zu machen. Wenn ich jetzt aber Aufträge in einer Warteschlange möchte muss ich mir ohnehin ein Array "warteschlange" bei meinem Raumschiff anlegen. Und für alle Sachen die das Raumschiff mal können soll eine Struktur erstellen. Einmal ist fliegeZu(WeltraumObjekt), einmal Lade 50t Rohstoff X ein, einmal LegeMinenfeld...
Also brauche ich ohnehin ein Array was all diese Werte/Objekte aufnimmt. Dann muss ich bei jedem Eintrag mit Switch/If die nötige Methode meiner Raumschiffklasse herausfinden und mit passenden Werten aufrufen. 
Das ist entweder von mir zu Kompliziert gedacht oder es ist so kompliziert dann frage ich mich wo der vor teil liegen soll.


----------



## freqry (2. Feb 2012)

dafür wäre meiner Meinung das Builder-pattern sehr gut geeignet:

javablog.ch  Blog Archive  Effective Java: Builder-Pattern


----------



## Marco13 (2. Feb 2012)

HimBromBeere hat gesagt.:


> OK, ich hab kapiert, was du willst, aber als wirklich sinnvoll erachte ich es immer noch nicht. Um die Aktionen - wie du sie nennst - in eine Liste zu speichern - musst du diese doch auch wenigstens vom Namen her kennen, formulieren musst du sie auch hin wie her, also was spricht gegen
> 
> ```
> BeweglichesObjekt Raumschiff = new Raumschiff();
> ...



Hm... Das eine ist hart verdrahtet und das andere nicht. Allgemein finde ich, so eine "Action"-Klasse (die vielleicht wegen Swing Actions anders heißen sollte) nicht nur sinnvoll, sondern u.U. geradezu _notwendig_. Abgesehen davon, dass man solche Aktionen ggf. in einer Liste im GUI darstellen will, und es praktisch sein könnte, wenn in der Liste das stehen würde, was bei [c]action.getDescription();[/c] (und ähnlichen Methoden, wie z.B. zur Abfrage der Zeit, wann die Aktion gestartet wurde, wie weit sie schon fortgeschritten ist usw) zurückgeliefert werden könnte, stellt sich beim Hartverdrahteten Ansatz die Fragen: Wie entfernt man die letzte Aktion, wenn man das Universum (warum auch immer :bahnhof: ) nun DOCH nicht zerstören will!?


----------



## Landei (2. Feb 2012)

Tomate_Salat hat gesagt.:


> Sagt ja niemand was dagegen, dass eine Klasse/Interface nur eine Methode implementiert. Aber wenn der TO für jede Aktion eine eigene Klasse erstellt und diese noch "FliegeNach" nennt, dann verfehlt das wieder sein Ziel. FliegeNach, Koloniesiere,... sind geeignete Namen für Methoden, aber nicht für Objekte.
> 
> Es sollte nicht das Ziel sein, für jede Aktion eine eigene Klasse zu schreiben, sondern diese sinnig auszulagern.



Hier möchte ich widersprechen: Bei einem solchen Spiel kann es viele verschiedene Aktionsarten geben, die nicht bei jedem Schiff und auch nicht unter allen Bedingungen möglich sind (Kolonisieren können nur Kolonieschiffe, und auch nur dann, wenn sie vorher Leute an Bord genommen haben, schwer beschädigte Schiffe können nicht kämpfen u.s.w.). In einer Hierarchie lässt sich das schlecht abbilden, insbesondere wenn man erlauben will, dass der Spieler Schiffstypen relativ frei weiterentwickeln kann. Insofern erfordert die Klasse Schiff viel mehr Flexibilität als etwa ein normales Business-Objekt, und der TO tut sehr gut daran, das von Anfang an einzuplanen.


----------



## Sphinx2k (3. Feb 2012)

Kleiner zwischenstand bei meinem Testprojekt. 
Nach viel grübeln und testen hab ich das ganze jetzt mit einer AbilityMoveTo Klasse gelöst welche wie alle Fähigkeiten dann von einer AbstractAbility abgeleitet werden. Dieser Ansatz bringt mir einfach die nötige Flexibilität.
Die Fähigkeit wird erstellt mit den nötigen Informationen und in einer Warteschlangen Liste gespeichert. Es wird immer die erste genommen und die darf arbeiten. Wenn die Fähigkeit erledigt ist setzt sie einen boolean done = true. und die Raumschiff klasse kickt sie aus der Warteschlange und nimmt sich die neue oberste Fähigkeit vor. 

Und damit geht das ganze sehr locker und _für mich_ schön strukturiert über die Bühne. Aktuell kann sich das Raumschiff nur bewegen, aber an sich sollte es auch mit anderen Aktionen wunderbar funktionieren.


----------

