import pygame
from pygame.locals import *
from random import *
# Spielgeschwindigkeit bzw. genauer Frequenz der Spielzyklen am Anfang.
FRAMES_PER_SECOND_AM_ANFANG = 40
# Das Spielfeld besteht aus kleinen rechteckigen Boxen mit Koordinaten
# 0 bis MAXX (jeweils einschliesslich) in x-Richtung und
# 0 bis MAXY (jeweils einschliesslich) in y-Richtung.
# Achtung: y-Achse zeigt nach unten (wie Zeilennummern)
MAXX = 30
MAXY = 20
# Festlegung von Breite und Höhe einer Box in Pixel.
# Meist sind Breite und Höhe gleich, was quadratische Boxen liefert.
SEITENLAENGE_BOX = 25
# Radius des Balles am Anfang.
RADIUS_BALL_AM_ANFANG = 0.7
# Anzahl Leben am Anfang.
LEBEN_AM_ANFANG = 10
# Einige von den obigen Werten abhängige Konstanten.
ANZAHL_BOXEN_X = MAXX + 1
ANZAHL_BOXEN_Y = MAXY + 1
FENSTER_BREITE = ANZAHL_BOXEN_X * SEITENLAENGE_BOX
FENSTER_HOEHE = ANZAHL_BOXEN_Y * SEITENLAENGE_BOX
PLATZ_FUER_TEXT = 3 * SEITENLAENGE_BOX
# Farben per Rot-, Grün- und Blauwert
# (jeweils auf Skala von 0 bis 255).
# Wer will, kann hier zusätzliche eigene Farben festlegen.
# rot grün blau
ROT = (255, 0, 0)
GRUEN = ( 0, 255, 0)
BLAU = ( 0, 0, 255)
GELB = (255, 255, 0)
MAGENTA = (255, 0, 255)
CYAN = ( 0, 255, 255)
WEISS = (255, 255, 255)
SCHWARZ = ( 0, 0, 0)
HELLGRAU = (80, 80, 80)
DUNKELGRAU = (160, 160, 160)
HINTERGRUND_FARBE = SCHWARZ
# HINTERGRUND_FARBE = HELLGRAU
#
# Definition der Klasse Punkt. Bitte einfach akzeptieren.
#
class Punkt:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f'({self.x}, {self.y})'
def __repr__(self):
return f'({self.x}, {self.y})'
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __add__(self, other):
return Punkt(self.x + other.x, self.y + other.y)
def __sub__(self, other):
return Punkt(self.x - other.x, self.y - other.y)
def laenge(self):
return (self.x * self.x + self.y * self.y) ** 0.5
#
# Ende der Definition der Klasse Punkt.
#
#
# Einige Funktionsdefinitionen
#
def zeichne_box(p, farbe):
rechteck = pygame.Rect(p.x * SEITENLAENGE_BOX + 1, p.y * SEITENLAENGE_BOX + 1, SEITENLAENGE_BOX - 1, SEITENLAENGE_BOX - 1)
pygame.draw.rect(leinwand, farbe, rechteck)
def zeichne_kreis(p, r, farbe):
pygame.draw.circle(leinwand, farbe, ((p.x + 0.0) * SEITENLAENGE_BOX + 1, (p.y + 0.0) * SEITENLAENGE_BOX + 1), r * SEITENLAENGE_BOX, width=0)
def zeichne_gitter():
for x in range(ANZAHL_BOXEN_X + 1):
pygame.draw.line(leinwand, HELLGRAU, (x * SEITENLAENGE_BOX, 0), (x * SEITENLAENGE_BOX, FENSTER_HOEHE))
for y in range(ANZAHL_BOXEN_Y + 1):
pygame.draw.line(leinwand, HELLGRAU, (0, y * SEITENLAENGE_BOX), (FENSTER_BREITE, y * SEITENLAENGE_BOX))
def schreibe(x, y, text, groesse):
schrift = pygame.font.SysFont('freemono', round(groesse * SEITENLAENGE_BOX))
formatierter_text = schrift.render(text, True, WEISS, SCHWARZ)
rechteck = formatierter_text.get_rect()
rechteck.center = (round((x + 0.5) * SEITENLAENGE_BOX), round((y + 0.5) * SEITENLAENGE_BOX))
leinwand.blit(formatierter_text, rechteck)
# Nicht verwendet, aber man könnte damit statt der farbigen Boxen Bilder anzeigen.
def zeige_bild(bild, p):
rechteck = pygame.Rect(p.x * SEITENLAENGE_BOX + 1, p.y * SEITENLAENGE_BOX + 1, SEITENLAENGE_BOX - 1, SEITENLAENGE_BOX - 1)
leinwand.blit(bild, rechteck)
def abstand(p, q):
return (p-q).laenge()
#
# Ende des Abschnitts mit den Funktionsdefinitionen.
#
#
# Hier geht das eigentliche Programm los.
#
# Initialisierung des Spielfelds
pygame.init()
uhr = pygame.time.Clock()
leinwand = pygame.display.set_mode((FENSTER_BREITE + 1, FENSTER_HOEHE + 1 + PLATZ_FUER_TEXT))
pygame.display.set_caption('My favorite game')
# Initialisierung der Daten des Spielers, insbesondere Startposition
spieler = Punkt(MAXX // 2, MAXY // 2)
farbe_spieler = GRUEN
# Initialisieren der Daten des Balls
radius_ball = RADIUS_BALL_AM_ANFANG
ball = Punkt(radius_ball, randrange(MAXY // 4, 3 * MAXY // 4))
bewegungsrichtung_ball = Punkt(0.1 + 0.4 * random(), randrange(-1, 2, 2) * 0.1 + 0.4 * random())
farbe_ball = MAGENTA
frames_per_second = FRAMES_PER_SECOND_AM_ANFANG
spiel_aktiv = True
leben = LEBEN_AM_ANFANG
# Hier startet die sogenannte "game loop".
while spiel_aktiv:
leinwand.fill(HINTERGRUND_FARBE)
zeichne_gitter()
zeichne_kreis(ball, radius_ball, farbe_ball)
# zeichne_box(ball, farbe_ball)
zeichne_box(spieler, farbe_spieler)
schreibe(MAXX // 4, MAXY + 1, f'Lives: {leben}', 0.7)
schreibe(3 * MAXX // 4, MAXY + 1, f'Update frequenqy: {frames_per_second}', 0.7)
schreibe(MAXX // 4, MAXY + 2, f'Player position: {spieler}', 0.7)
schreibe(3 * MAXX // 4, MAXY + 2, f'Ball position: ({ball.x:.1f}, {ball.y:.1f})',0.7)
schreibe(MAXX // 4, MAXY + 3, f'Enter key moves player to center', 0.7)
schreibe(3 * MAXX // 4, MAXY + 3, f'Ball direction: ({bewegungsrichtung_ball.x:.1f}, {bewegungsrichtung_ball.y:.1f})',0.7)
pygame.display.update()
uhr.tick(frames_per_second)
if leben >= 20 or leben <= 0:
spiel_aktiv = False
ende = 'gewonnen oder verloren'
if abstand(spieler, ball) < radius_ball + 0.9:
leben = leben + 1
radius_ball = max(0.3, 0.9 * radius_ball)
# Spieler bekommt neue Position.
spieler.x = 2 * MAXX // 3
spieler.y = randrange(MAXY + 1)
# Ball bekommt neue Position und Richtung.
ball = Punkt(radius_ball, randrange(MAXY // 4, 3 * MAXY // 4))
bewegungsrichtung_ball = Punkt(0.1 + 0.4 * random(), randrange(-1, 2, 2) * 0.1 + 0.4 * random())
# Spielerposition bei Tastendruck verändern.
#
# Teilaufgabe 1: Passe die folgenden 21 Zeilen so an,
# dass die Pfeiltasten das grüne Quadrat wie gewünscht steuern.
#
for ereignis in pygame.event.get():
if ereignis.type == KEYDOWN:
if ereignis.key == K_LEFT:
print("Pfeiltaste ... gedrückt.")
spieler.y = spieler.y + 1
if spieler.y >= MAXY:
spieler.y = 1
elif ereignis.key == K_RIGHT:
print("Pfeiltaste ... gedrückt.")
spieler.x = spieler.x - 1
if spieler.x < 0:
spieler.x = 3
elif ereignis.key == K_UP:
print("Pfeiltaste hoch gedrückt.")
spieler.x = spieler.x + 2
elif ereignis.key == K_DOWN:
print("Pfeiltaste runter gedrückt.")
spieler.y = spieler.y - 1
if spieler.y < 0:
spieler.y = spieler.x
spieler.x = 0
elif ereignis.key == K_ESCAPE:
print("Escape-Taste gedrückt.")
spiel_aktiv = False
ende = 'Abbruch'
elif ereignis.key == K_RETURN:
print("Enter/Return-Taste gedrückt.")
spieler.x = MAXX // 2
spieler.y = MAXY // 2
elif ereignis.key == K_q:
print("Taste 'q' gedrückt.")
spiel_aktiv = False
ende = 'Abbruch'
elif ereignis.type == QUIT:
print("Button zum Schliessen des Pygame-Fensters angeklickt.")
spiel_aktiv = False
ende = 'Abbruch'
# Position des Balls verändern.
ball = ball + bewegungsrichtung_ball
#
# Teilaufgabe 2: Passe die folgenden 10 Zeilen so an,
# dass der Ball rechts, oben und unten normal reflektiert wird.
#
if ball.y - radius_ball < 0:
bewegungsrichtung_ball.y = - bewegungsrichtung_ball.y
bewegungsrichtung_ball.x = - bewegungsrichtung_ball.y
if ball.y + radius_ball > MAXY + 1:
bewegungsrichtung_ball.y = - 0.1
bewegungsrichtung_ball.x = 0.4
if ball.x + radius_ball > MAXX + 1:
bewegungsrichtung_ball.x = - bewegungsrichtung_ball.x
# Die folgende Zeile nicht verändern.
leben = leben - 2
# Ab hier nichts mehr verändern!
if ball.x - radius_ball < 0:
bewegungsrichtung_ball.x = 0.1 + 0.4 * random()
if bewegungsrichtung_ball.y > 0:
bewegungsrichtung_ball.y = 0.1 + 0.4 * random()
else:
bewegungsrichtung_ball.y = -(0.1 + 0.4 * random())
if ende == 'gewonnen oder verloren':
if leben >= 20:
schreibe(MAXX // 2, MAXY // 2, 'Congratulations!', 2)
else:
schreibe(MAXX // 2, MAXY // 2, 'GAME OVER', 2)
schreibe(MAXX // 2, MAXY // 2 + 3, 'press any key', 1)
pygame.display.update()
pygame.time.delay(500)
pygame.event.clear()
pygame.event.wait()
pygame.quit()
exit()