Nächstes Element: Das Brett
Nachdem der Ball jetzt also wunderbar funktioniert, kann das nächste Element ins Spiel kommen. Der Schläger bzw. das Brett, das man unten hin- und herschieben kann. Der Ball soll daran ebenso abprallen wie von der Wand.
Was brauchen wir dafür? Natürlich zuerst eine neue Actor-Klasse, die wir »Brett« nennen. Dann eine Steuerung per Tastatur, genauso wie beim Krebs im letzten Kapitel, und eine Kollisionssteuerung, falls der Ball das Brett berührt.
Beginnen wir erst einmal mit der Erzeugung des Bretts selber. Das kommt hinter die Definition der Klasse Ball.
class Brett(Actor):
pass
Das reicht fürs Erste – eine Klasse Brett, die noch leer ist – also identisch mit Actor. Später erweitern wir sie.
Nun erstellen wir das Brett als Spielfigur. So sieht jetzt die Erstellung der Objekte ball und brett aus:
ball = Ball("sprites/evalpeg_1.png")
feld.addActor(ball, Location(150,300),45)
brett = Brett("sprites/stick_1.gif")
feld.addActor(brett, Location(400,580))
Wenn du das Programm startest, sieht es so aus:
Abbildung 19.4 Das Schlägerbrett ist da – aber noch nicht steuerbar.
Jetzt muss das Brett also mit den Pfeiltasten nach links und nach rechts bewegt werden können. Du kennst das ja schon vom Krebs. Genauso wird es jetzt auch mit dem Brett gemacht. Es wird eine Funktion definiert, die die Tasten abfragt und mit dem Brett entsprechend nach links oder rechts geht. Sie wird nach den Klassendefinitionen ins Programm eingefügt:
def tasteGedrueckt(tastencode):
xpos = brett.getX()
if tastencode == 37: # nach links
if xpos > 30:
brett.setX(xpos - 5)
elif tastencode == 39: # nach rechts
if xpos < 770:
brett.setX(xpos + 5)
Nun muss diese Funktion nur noch als automatische Ereignisbehandlung dem feld zugefügt werden (am besten nach setSimulationPeriod(20)):
feld.addKeyRepeatListener(tasteGedrueckt)
So. Wenn du das Programm jetzt startest, lässt sich das gelbe Brett unten mit den Pfeiltasten wunderbar hin- und herbewegen.
Der nächste Schritt: Der Ball soll am Brett abprallen.
Dafür ist es am besten, wenn das Brett eine Kollisionsfunktion bekommt. Das Kollisionsobjekt für das Brett ist der Ball.
Also fügst du direkt nach der Erstellung des Bretts ihm noch den Ball als Kollisionsobjekt hinzu:
brett.addCollisionActor(ball)
Und nun muss der Klasse Brett (die bisher leer ist) noch die Kollisionsfunktion collide() gegeben werden. Was soll passieren, wenn Brett und Ball sich berühren? Klar, der Ball soll abprallen, so wie er auch von der unteren Wand abprallen würde, also senkrecht. Aber um das Spiel etwas lebendiger zu machen, kannst du den Abprallwinkel vom Brett zufällig variieren – ihn von –30 bis +30 je nach Zufallszahl verschieben. (Bitte denk dran, dass am Anfang des Programms noch ein from random import * stehen muss!)
class Brett(Actor):
def collide(self,actor1,actor2):
richtung = ball.getDirection()
neue_richtung = 360-richtung+randint(-30,30)
ball.setDirection(neue_richtung)
ball.move(5)
return 0
Beachte, dass die collide()-Funktion immer eine Zahl zurückgeben muss, also hier einfach return 0.
Starte das Programm – und du wirst sehen, dass es prinzipiell funktioniert. Aber eins ist noch nicht ganz korrekt: Der Ball prallt zwar vom Brett ab, aber er reagiert schon zahlreiche Pixel über dem Brett, sodass er das Brett selbst nie berührt. Das liegt daran, dass das Brett eine größere Kollisionsfläche hat, als eigentlich sichtbar ist. Du kannst das ändern, indem du definierst, welcher Bereich des Bildes eine Kollision auslösen soll.
Nach der Erstellung des Bretts fügst du Folgendes ein:
brett.setCollisionRectangle(Point(0,20),100,2)
Damit wird ein Rechteck innerhalb des Bretts als »Kollisionszone« definiert. Erst wenn der Ball diesen Punkt berührt, wird die Kollision ausgelöst. Wenn du es jetzt wieder probierst, sieht es realistischer aus.
Gut: Steuerung geht – Abprallen geht. Was kommt jetzt?
Bevor du die bunten Blöcke erstellst, die der Ball abschießen soll, kommt noch ein kleiner, aber wichtiger Schritt: Schließlich soll der Ball gar nicht am unteren Rand abprallen, sondern das Spiel ist beendet, wenn der Ball den unteren Rand berührt. Dementsprechend müssen wir die Bewegungsfunktion des Balls abändern:
class Ball(Actor):
def act(self):
richtung = self.getDirection()
if (self.getX() >= 800) or (self.getX() < 20):
# Richtung des Balls ändern, linke/rechte Wand
neue_richtung = 180-richtung
self.setDirection(neue_richtung)
self.move(5)
if (self.getY() < 20):
# Richtung des Balls ändern, obere Wand
neue_richtung = 360-richtung
self.setDirection(neue_richtung)
self.move(5)
if (self.getY() > 600):
# Wenn Ball Unterkante berührt
feld.doPause()
msgDlg("GAME OVER")
else:
self.move(5)
Das reicht fürs Erste. Jetzt ist es schon fast ein richtiges Spiel: Der Ball fliegt, prallt an den Ecken ab, kann mit dem steuerbaren Brett abgefangen werden – und das Spiel ist beendet, wenn der Ball die untere Kante des Spielfelds berührt.
Abbildung 19.5 Ups, nicht aufgepasst!