TigerJython | xx für Gymnasien |
Die Callbacks werden bei der Erzeugung des Spielfensters mit benannten Parametern registriert (Beispiele 1, 2 und 3) |
|
Man verwendet einen GGMouseListener und registriert ihn mit den notwendigen Callbacks (Beispiel 4) |
Im Abschnitt Maus-Events II wird zusätzlich der GGMouseTouchListener verwendet, der nicht nur die Koordinaten des Mausklicks, sondern auch das Spritebild des Actor, der sich an der Position des Mausklicks befindet, erfassen kann.
Beispiel 1: Beim Drücken der Maustaste wird ein neuer Fisch erzeugt. Dies ist ein schönes Beispiel für die objektorientierte Programmierung, denn jeder neue Fisch ist eine Instanz der Klasse Fish und "weiss" darum aus der Klassendefinition, wie er sich bewegen soll. Die Callbackfunktion pressCallback() wird als globale Funktion definiert. Beim Drücken der Maustaste werden mit e.getX() und e.getY() die Koordinaten des Mausklicks erfasst und an dieser Position ein Objekt der Klasse Fish erzeugt. Die Registrierung des Callbacks erfolgt als Parameter bei der Erzeugung des Spielfensters (wie bei der Turtlegrafik). |
# Gg8.py from gamegrid import * # ---------------- class Fish ---------------- class Fish(Actor): def __init__(self): Actor.__init__(self, "sprites/nemo.gif"); def act(self): self.move() if not self.isMoveValid(): self.turn(180) self.setHorzMirror(not self.isHorzMirror()) # ---------------- main ---------------------- def pressCallback(e): location = toLocationInGrid(e.getX(), e.getY()) addActor(Fish(), location) makeGameGrid(10, 10, 60, Color.red, "sprites/reef.gif", False, mousePressed = pressCallback) show() doRun() |
Erklärungen zum Programmcode:
def pressCallback(e): definiert die Callbackfunktion, die aufgerufen wird, wenn die Maustaste gedrückt wird. e steht für Event | |
toLocationInGrid(e.getX(), e.getY()) erfasst und wandelt sie in Zellenkoordinaten (Locations) um | |
makeGameGrid( ..., mousePressed = pressCallback) registriert den Callback |
Beispiel 2: Eine Spielfigur kann mit der gedrückten Maustaste an eine beliebige Position im Gitter verschoben werden. Wir verwenden zwei Callbacks pressCallback() und dragCallback(). Da die Variable actor in beiden Funktionen verwendet wird, muss sie als global deklariert werden. Die beiden Funktionen werden mit benannten Parametern beim Erzeugen des Spielfensters registriert.
|
# Gg8a.py from gamegrid import * # ---------------- class Ghost ---------------- class Ghost(Actor): def __init__(self): Actor.__init__(self, "sprites/ghost.png") # ---------------- main ---------------------- def pressCallback(e): location = toLocationInGrid(e.getX(), e.getY()) global actor actor = getOneActorAt(location) def dragCallback(e): if actor == None: return location = toLocationInGrid(e.getX(), e.getY()) actor.setLocation(location) makeGameGrid(10, 10, 60, Color.red, False, mousePressed = pressCallback, mouseDragged = dragCallback) ghost1 = Ghost() ghost2 = Ghost() addActor(ghost1, Location(5, 5)) addActor(ghost2, Location(2, 3)) show() doRun() |
Erklärungen zum Programmcode:
mousePressed = pressCallback, mouseDragged = dragCallback : Bei der Erzeugung des Spielfensters können mehrere Callbackfunktionen registriert werden | |
global actor: Damit die Variable actor in der Methode pressCallback() zugewiesen werden kann, muss sie als global deklariert werden | |
if actor == None: Wird in eine leere Zelle geklickt, so liefert getOneActorAt() den Wert None. Beim nachfolgenden Ziehen wird der dragCallback mit return verlassen |
Beispiel 3: Im Beispiel 2 bewegt sich die Spielfigur beim Ziehen mit gedrückter Maustaste sprungartig von Zelle zur Zelle. Manchmal ist es eleganter, die Objekte kontinuierlich zu ziehen und beim Loslassen der Maustaste exakt in einer Gitterzelle zu positionieren. Vier Kugeln werden zu Beginn zufällig im Spielfenster. Mit der Maus sollen sie in die mittleren 4 Felder verschoben werden. Wir verwenden drei Callbacks pressCallback() , dragCallback() und releaseCallback(). Im presCallback() wird die Position des Mausklicks und die Kugel, die sich auf dieser Position befindet, erfasst. Die Methode setLocationOffset() im dragCallback() bewirkt die kontinuierliche Bewegung während des Ziehens mit gedrückter Maustaste. Im releaseCallback() wird die Kugel beim Loslassen der Maustaste wieder genau im Gitter positioniert.
|
# Gg8b.py from gamegrid import * def pressCallback(e): global actor, startLoc startLoc = toLocationInGrid(e.getX(), e.getY()) actor = getOneActorAt(startLoc) def dragCallback(e): if actor == None: return startPoint = toPoint(startLoc) actor.setLocationOffset(e.getX() - startPoint.x, e.getY() - startPoint.y) def releaseCallback(e): if actor == None: return destLoc = toLocationInGrid(e.getX(), e.getY()) actor.setLocationOffset(0, 0) actor.setLocation(destLoc) actor = None startLoc = None makeGameGrid(8, 8, 70, Color.red, False, mousePressed = pressCallback, mouseDragged = dragCallback, mouseReleased = releaseCallback) setTitle("Sort Balls") for i in range(4): ball = Actor("sprites/marble.png") addActor(ball, getRandomEmptyLocation()) show() setSimulationPeriod(20) doRun() |
Erklärungen zum Programmcode:
global actor, startLoc: Damit die Variablen in mehreren Callbacks verwendbar sind, müssen sie als global deklariert sein | |
setLocationOffset(e.getX() - startPoint.x, e.getY() - startPoint.y): bewirkt Bewegung ausserhalb der Gittezellen | |
setLocationOffset(0, 0): beim Loslassen der Maustaste wird die Kugel in der Mitte der Zelle positioniert |
Beispiel 4: Ein Auto kann mit der gedrückten Maustaste bewegt werden. Dabei dreht sich das Auto immer in die Bewegungsrichtung. Da die Zellengrösse 1 Pixel ist, bewegt sich das auto kontinuierlich. Wir verwenden den MouseListener aus der Klasse GGMouseListener. Da das Auto bewegt wird, ist es naheliegend, den Mauslistener der Klasse Car zuzuordnen. Da Python mehrfache Vererbung erlaubt, kann Car von der Klasse Actor und auch von der Klasse GGMouseListener abgeleitet werden. Die Callbackmethode mouseEvent() wird in der Klasse Car definiert. Damit sich das Auto immer in die Bewegungsrichtung dreht, wird laufend die Bewegungsrichtung aus der Differenz der alten und neuen Koordinaten berechnet. Dabei wartet man immer, bis der Abstand zwischen dem alten und neuen Punkt grösser als 5 Pixel ist. |
# Gg8c.py from gamegrid import * import math # --------------------- class car -------------------------- class Car(Actor, GGMouseListener): def __init__(self): Actor.__init__(self, True, "sprites/redcar.gif") self.oldLocation = Location() def mouseEvent(self, e): location = toLocationInGrid(e.getX(), e.getY()) self.setLocation(location) dx = location.x - self.oldLocation.x; dy = location.y - self.oldLocation.y; if dx * dx + dy * dy < 25: return True phi = math.atan2(dy, dx) self.setDirection(math.degrees(phi)) self.oldLocation = location # --------------------- main --------------------------------- makeGameGrid(600, 600, 1, False) setTitle("Move car using mouse drag") setSimulationPeriod(50) setBgColor(Color.gray) car = Car() addActor(car, Location(50, 50)) addMouseListener(car, GGMouse.lDrag) show() doRun() |
Erklärungen zum Programmcode:
class Car(Actor, GGMouseListener): Die Klasse Car wird von Actor und GGMouseListener abgeleitet | |
addMouseListener(car, GGMouse.lDrag): Der GGMouse Listener wird mit der Maske lDrag registriert, damit nur der Drag-Event aktiv wird | |
Die alte Position wird in der Instanzvariablen oldLocation gespeichert, die im Konstruktor erzeugt wird |
Aufgaben: |
1) |
Im Spielfenster mit einem blauen Hintergrund werden 20 Ballons an zufällig gewählten Positionen erzeugt (balloon.gif). Mit einem Mausklick können sie vernichtet werden. |
2) |
Wie in der ersten Aufgabe werden 20 Ballons an zufällig gewählten Positionen erzeugt. Definiere eine Callbackfunktion pressCallback(e), mit der du einen Ballon mit der Maus wählen kannst und eine Callbackfunktion dragCallback(e), mit der du den gewählten Ballon verschieben kannst. Verschiebe dann alle Ballons so, dass sie in den obersten zwei Zeilen angeordnet sind. |
3) |
(Du definierst in der Klasse Balloon eine Funktion act(self), in der die Bewegungsrichtung mit self.setDirection(90) festgelegt wird. |