Auf die Maus reagieren

Nun geht es an die Steuerung mit der Maus. Unser GameGrid muss auf das Mausklick-Ereignis reagieren. Bei einem Mausklick auf das Spielfeld muss es außerdem ermitteln, welche Zelle geklickt wurde und dort (wenn das Feld leer ist) das Symbol des Spielers hinsetzen.

Um ein bestimmtes Ereignis mit der Maus oder Tastatur auszuwerten, stellt uns GameGrid übrigens auch eine einfache Methode zur Verfügung, die wir bisher noch nicht genutzt haben – aber das wollen wir jetzt tun. Wir können nämlich gleich bei der Erstellung des GameGrid-Objekts, also des Spielfeldes, angeben, auf welche Ereignisse das Spielfeld mit welcher Funktion reagieren soll. Das geht so. Ersetze die Erstellung des Spielfeldes durch diese Zeile:

feld = GameGrid(3,3,100,Color.BLACK,False,mouseReleased=mausKlick)

Es ist also ein Parameter am Ende hinzugekommen:

mouseReleased=mausKlick

Das bedeutet konkret: Im Falle eines Mausklicks auf das Spielfeld soll GameGrid die Funktion mausKlick() ausführen (die noch geschrieben werden muss). In den vorherigen Programmbeispielen haben wir immer nach der Erstellung einen mouseEventListener hinzugefügt – was natürlich hier auch gut funktioniert hätte und uns alle Infos über das Ereignis liefert.

Dies hier ist aber eine Abkürzung, die Einrichtung eines speziellen Event-Listeners gleich bei der Erstellung des Spielfeldes durch Übergeben eines Parameters. In vielen Fällen, wie hier auch, ist das einfacher und reicht für dieses Spiel völlig aus.

Man könnte auch noch weitere solcher Ereignis-Parameter, durch Komma getrennt, hinzufügen, wenn man sie braucht. Zum Beispiel mousePressed (Maustaste heruntergedrückt), mouseClicked (Maustaste einmal komplett über dem Feld geklickt und losgelassen), keyPressed (Tastaturtaste gedrückt) usw. … aber hier brauchen wir nur mouseReleased – also das Ereignis, wenn die Maustaste gedrückt und auf dem Spielfeld wieder losgelassen wurde). mouseClicked ginge auch, aber mouseReleased ist unproblematischer, weil es immer funktioniert, auch wenn man zu schnell oder zu langsam klickt.

Jetzt schreiben wir also die Ereignisfunktion mausKlick(), die automatisch das Ereignisobjekt als Parameter erhält.

def mausKlick(ereignis):

So beginnt die Funktion, die aufgerufen wird, wenn die Maus auf dem Spielfeld geklickt wird. Die automatisch bei Ereignisfunktionen übergebene Variable ereignis (wir können sie in unserer Funktion nennen, wie wir wollen) ist ein Ereignisobjekt, dessen Eigenschaften uns Informationen geben, zum Beispiel, auf welche Pixelposition (x,y) gerade geklickt wurde.

Das kriegen wir so raus:

def mausKlick(ereignis):
xpos = ereignis.getX()
ypos = ereignis.getY()

Das Ereignisobjekt des Mausklicks gibt uns über die Methoden getX() und getY() die genaue Position, an die geklickt wurde.

Damit wir jetzt dort aber ein Symbol platzieren können, brauchen wir natürlich die Zellenposition (x: 0–2, y: 0–2). Wie ermitteln wir die? Wir könnten sie natürlich berechnen, indem wir die Pixelbreite und Pixelhöhe des Spielfeldes durch die Anzahl der Zellen teilen und dann anhand der Pixelposition die Zellenposition herausbekommen.

Es geht aber auch einfacher, denn gamegrid liefert uns bereits eine Methode dafür – weil man das schließlich sehr oft braucht, wenn man mit Zellen arbeitet.

Die Methode heißt toLocationInGrid(x,y). Damit wandelt man also die Pixelposition x,y in die Zellenposition um, in der sich dieser Punkt befindet.

def mausKlick(ereignis):
xpos = ereignis.getX()
ypos = ereignis.getY()
zellenPos = feld.toLocationInGrid(xpos,ypos)
symbol = Actor("sprites/mark_0.gif")
feld.addActor(symbol,zellenPos)

So sieht jetzt die mausKlick()-Funktion aus. Wenn mit der Maus auf das Spielfeld geklickt wird, werden zunächst die Koordinaten in Pixeln aus dem Ereignisobjekt ausgelesen. Danach werden sie in die Zellenposition des Felds umgerechnet, und an diese Position wird das Symbol, das erzeugt wird, auf dem Spielfeld gesetzt. Teste das mal! Füge die mausKlick()-Funktion vor der Erstellung des Feldes ein. Die Erstellung der beiden Symbole kannst du wieder löschen. So sieht das Programm dann also aus:

from gamegrid import *

def mausKlick(ereignis):
xpos = ereignis.getX()
ypos = ereignis.getY()
zellenPos = feld.toLocationInGrid(xpos,ypos)
symbol = Actor("sprites/mark_0.gif")
feld.addActor(symbol,zellenPos)

feld = GameGrid(3,3,100,Color.BLACK,False,mouseReleased=mausKlick)
feld.setTitle("Tic Tac Toe")
feld.setBgColor(Color.WHITE)
feld.show()
Mit jedem Mausklick kannst du so einen Kreis in eine Zelle setzen.

Abbildung 22.3    Mit jedem Mausklick kannst du so einen Kreis in eine Zelle setzen.

Sehr schön. Wieder ein Problem gelöst. Eigentlich fehlt jetzt nur noch die Spielverwaltung im Hintergrund: Welcher Spieler ist dran? Auf welche Felder darf gesetzt werden? Wann ist das Spiel gewonnen bzw. unentschieden beendet?

Diese Dinge haben es aber in sich. Da muss man sich einige Gedanken machen.