EINFÜHRUNG |
Im täglichen Leben bist du von einer Vielzahl von verschiedenen Objekten umgeben. Da Software oft die Wirklichkeit modellmässig abbildet, ist es naheliegend, auch in der Informatik Objekte einzuführen. Man spricht dann von Objektorientierter Programmierung (OOP). Das Konzept der OOP hat sich seit zwei Jahrzehnten in der Informatik als derart wegweisend erwiesen, dass es praktisch in allen heute entwickelten Softwaresystemen angewendet wird [mehr...
Man unterscheidet dabei zwischen Programmiersprachen wie Java, mit denen man nur objektorientiert Du hast bereits die Turtle als Objekt kennen gelernt. Eine Turtle besitzt Eigenschaften (sie hat eine bestimmte Farbe, befindet sich an einer gewissen Position und hat eine bestimmte Blickrichtung) und Fähigkeiten (sie kann sich vorwärts bewegen, sich drehen, usw.). In der OOP werden Objekte mit ähnlichen Eigenschaften und Fähigkeiten in Klassen eingeteilt. Die Turtleobjekte gehören zur Klasse Turtle, man sagt auch, sind Instanzen der Klasse Turtle. Um ein Objekt zu erzeugen, muss man zuerst eine Klasse definieren oder wie bei Turtles eine bereits vordefinierte Klasse verwenden. Beim Programmieren nennt man die Eigenschaften auch Attribute oder Instanzvariablen, die Fähigkeiten auch Operationen oder Methoden. Es handelt sich um Variablen und Funktionen, ausser dass sie einer bestimmten Klasse angehören und damit in der Klasse "gekapselt" sind. Um sie ausserhalb der Klasse zu verwenden, muss man eine Klasseninstanz und den Punktoperator voranstellen.
|
EIN ANPASSUNGSFÄHIGES SPIELFENSTER |
Ohne OOP ist es nicht möglich, mit vernünftigem Aufwand ein Computergame zu erstellen, denn die Spielfiguren und andere Gegenstände des Gameboards sind offensichtlich Objekte. Das Gameboard ist ein rechteckiges Bildschirmfenster und wird durch die Klasse GameGrid aus der Gamelibrary JGameGrid modelliert. TigerJython stellt dir eine Instanz beim Aufruf von makeGameGrid() zur Verfügung und mit show() wird das Fenster angezeigt. Dabei kannst du das Aussehen des Spielfensters über Parameterwerte deinen Wünschen anpassen. Mit makeGameGrid(10, 10, 60, Color.red, "sprites/town.jpg", False)
from gamegrid import * makeGameGrid(10, 10, 60, Color.red, "sprites/town.jpg", False) show()
|
MEMO |
Die Methoden der Klasse GameGrid stehen dir mit makeGameGrid() als Funktionen zur Verfügung. Du kannst aber auch selbst eine Instanz erzeugen und die Methoden mit dem Punktoperator aufrufen. from gamegrid import * gg = GameGrid(10, 10, 60, Color.red, "sprites/town.jpg", False) gg.show() Das Spielfenster ist aus quadratischen Zellen aufgebaut, wobei die Zellengrösse (60 pixel) und die Anzahl 10 horizontaler und vertikaler Zellen angegebenen werden. Damit auch die rechte und untere Gitterlinie angezeigt werden, besitzt das Fenster eine Grösse von 601 x 601 pixel. Dies entspricht der (minimalen) Grösse des Hintergrundbildes Der letzte boolesche Parameter bestimmt, ob eine Navigationsleiste erscheint. |
KLASSENDEFINITION MIT ABLEITUNG |
Bei der Definition einer Klasse kannst du entscheiden, ob deine neue Klasse ganz eigenständig ist oder aus einer bereits vorhandenen Klasse abgleitet wird. In der abgeleiteten Klasse stehen dir alle Eigenschaften und Fähigkeiten der Oberklasse (auch Basisklasse oder Superklasse genannt) zur Verfügung. Anschaulich sagt man, dass die abgeleitete Klasse Eigenschaften und Fähigkeiten erbt. In der Gamelibrary JGameGrid werden Spielfiguren Actors genannt und sind Instanzen der vordefinierten Klasse Actor. Willst du also eine eigene Spielfigur verwenden, so definierst du eine Klasse, die aus Actor abgeleitet ist. Deine Klassendefinition beginnt mit dem Schlüsselwort class. Es folgt der beliebig wählbare Klassennamen und ein rundes Klammerpaar. Dort schreibst du den Namen einer oder mehrerer Klassen hin, von denen du deine Klasse ableitest. Da du die Spielfigur von Actor ableiten willst, gibst du diesen Klassennamen an. Die Klassendefinition enthält die Definition der Methoden, die wie normale Funktionen definiert werden, mit dem Unterschied, dass sie obligatorisch den Parameter self als ersten Parameter aufweisen müssen. Mit diesem Parameter kannst du auf andere Methoden und Instanzvariablen der eigenen Klasse und ihrer Basisklasse zugreifen. Die Liste der Methodendefinitionen beginnt üblicherweise mit der Definition einer speziellen Methode mit dem Namen __init__ (zwei vor- und nachgestellte Underlines). Diese nennt man Konstruktor (in Python auch Initializer genannt) und sie wird automatisch dann aufgerufen, wenn ein Objekt der Klasse erzeugt wird. In unserem Fall rufst du im Konstruktor von Alien den Konstruktor der Basisklasse Actor auf, welchem du den Pfad zum Spritebild übergibst. Als nächstes definierst du die Methode act(). Diese spielt für die Gameanimation eine zentrale Rolle, denn sie wird vom Gamemanager in jedem Simulationszyklus automatisch aufgerufen. Dies ist ein besonders intelligenter Trick, damit du dich nicht mit einer Wiederholstruktur selbst um die Animation kümmern musst. In act() legst du fest, was die Spielfigur in jedem Simulationszyklus machen soll. Als Demonstration bewegst du sie hier lediglich mit move() in die nächste Zelle. Da move() eine Methode der Basisklasse Actor ist, musst du sie mit vorgestelltem self aufrufen.
from gamegrid import * # ---------------- class Alien ---------------- class Alien(Actor): def __init__(self): Actor.__init__(self, "sprites/alien.png") def act(self): self.move() makeGameGrid(10, 10, 60, Color.red, "sprites/town.jpg", False) spin = Alien() # object creation, many instances can be created urix = Alien() addActor(spin, Location(2, 0), 90) addActor(urix, Location(5, 0), 90) show() doRun() |
MEMO |
Eine Klassendefinition beginnt mit dem Schlüsselwort class und kapselt die Methoden und Instanzvariablen der Klasse. Der Konstruktor mit dem Namen __init__ wird bei der Erzeugung eines Objekts automatisch aufgerufen. Um ein Objekt (eine Instanz) zu erzeugen, verwendest du den Klassennamen und übergibst ihm die Parameterwerte, welche __init__ erhalten soll. Alle Spielfiguren werden aus der Klasse Actor abgeleitet. In der Methode act() definierst du, was die Spielfigur in jedem Simulationszyklus machen soll. Mit addActor() fügst du eine Spielfigur in das Gameboard, wobei du seine Startposition (Location) und seine Startrichtung (in Grad) angibst (0 gegen Osten, positiv in Uhrzeigersinn). |
ANGRIFF DER ALIENS |
from gamegrid import * from random import randint # ---------------- class Alien ---------------- class Alien(Actor): def __init__(self): Actor.__init__(self, "sprites/alien.png") def act(self): self.move() makeGameGrid(10, 10, 60, Color.red, "sprites/town.jpg", False) show() doRun() while not isDisposed(): alien = Alien() addActor(alien, Location(randint(0, 9), 0), 90) delay(200) |
MEMO |
Eine Endlosschleife im Hauptteil des Programms sollte mit isDisposed() darauf testen, ob das Gamefenster geschlossen wurde, damit das Programm korrekt beendet wird. Achtung: Es ist manchmal nötig, TigerJython zu schliessen und wieder zu öffnen, damit gleichnamige, aber veränderte Sprite- oder Hintergrundbilder geladen werden. |
SPACEINVADER LIGHT |
In deinem ersten selbst geschriebenen Computergame soll der Spieler versuchen, eine Alien-Invasion zu bekämpfen, indem er die angreifenden Aliens mit Mausklicks entfernt. Jeder in der Stadt gelandete Alien führt zu einem Minuspunkt. Für die Mausunterstützung fügst du einen Maus-Callback mit dem Namen pressCallback ein und registrierst ihn als benannten Parameter mousePressed. Im Callback holst du dir zuerst aus dem Event-Parameter e die Zellenposition des Mausklicks. Befindet sich in dieser Zelle ein Actor, so kriegst du ihn mit getOneActorAt(), ist die Zelle leer, so liefert der Aufruf None. removeActor() entfernt den Actor aus dem Gameboard. from gamegrid import * from random import randint # ---------------- class Alien ---------------- class Alien(Actor): def __init__(self): Actor.__init__(self, "sprites/alien.png") def act(self): self.move() def pressCallback(e): location = toLocationInGrid(e.getX(), e.getY()) actor = getOneActorAt(location) if actor != None: removeActor(actor) refresh() makeGameGrid(10, 10, 60, Color.red, "sprites/town.jpg", False, mousePressed = pressCallback) setSimulationPeriod(800) show() doRun() while not isDisposed(): alien = Alien() addActor(alien, Location(randint(0, 9), 0), 90) delay(1000) |
MEMO |
Da act() in jeder Simulationsperiode einmal aufgerufen wird, ist die Periodendauer für die Ablaufgeschwindigkeit des Games verantwortlich. Der Standardwert der Simulationsperiode ist 200 ms. Sie kann mit setSimulationPeriod() auf einen anderen Wert eingestellt werden. Das Gameboard wird in jedem Simulationszyklus einmal neu aufgebaut (gerendert), eine Änderung der Spielsituation wird daher erst zu diesem Zeitpunkt sichtbar. Willst du bei einem Mausklick die neue Situation sofort anzeigen, so kannst du das Rendern mit refresh() manuell ausführen. |
AUFGABEN |
|
EIGENE BILDER VERWENDEN |
Sie können auch eigene Bilder für Actors und Spielfensterhintergrund verwenden. Sie können im beliebigen Ordner auf Ihrem Computer gespeichert sein. Im Programm geben Sie den Pfad der Bilddatei an: Unter MacOS z.B. Unter Windows können Sie die eigenen Bilder auch im Unterverzeichnis sprites des Unterverzeichnises /bin des Installationsverzeichnisses speichern. |