====== Ball game program ====== 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() ===== Link zur Snake-Seite ===== * [[lehrkraefte:snr:informatik:glf22:python:snake|Snake]]