Einführung in Pygame
I
n diesem Kapitel lernst du, mit der Python-Bibliothek Pygame in WebTigerPython einfache 2D-Spiele zu entwickeln, die auch auf Tablets laufen. Pygame ist eine Bibliothek für Python, mit der du ganz einfach eigene Spiele programmieren kannst. Sie bietet dir Werkzeuge um Grafiken anzuzeigen, Figuren zu bewegen und auf Tastendrücke und Mausklicks zu reagieren. Du kennst bereits die wesentlichen Python-Grundlagen (Variablen, Schleifen, Bedingungen Funktionen, Listen, Dictionaries, Tupel) und wirst nun lernen, interaktive Spiele mit Grafiken, Animationen und Benutzersteuerung zu erstellen.
Wenn ein Pygame-Programm aus einer Python--Entwicklungsumgebung oder der Console gestartet wird (s. Abbildung links), besteht das Grafik-Fenster aus einer Titelzeile mit dem Namen des Programms, Buttons zum Schließen und Ausblenden in der Titelzeile sowie einer Zeichenfläche. Im WebTigerPython wird das Pygame-Fenster als rahmenlose Fläche im Grafik-Fenster angezeigt, ohne Fenstertitel oder Schließen-Button (s.Abbildung rechts). Da der Schließen-Button WebTigerPython nicht vorhanden ist, beenden wir ein Programm durch Klick mit der rechten Maustaste. Da das bei Tablets nicht funktioniert, musst du bei diesesn Geräten ein Programm vorläufig durch Touch auf die rote Stopp -Taste beenden.
Das folgende Programm öffnet ein hellgraues Rechteck als Zeichenfläche. Das Pygame-Fenster wird in der linken unteren Ecke mit der angegebenen Breite und Höhe in das WTP Grafik-Fenster eingefügt. Kopiere das Programm mit dem Kopiere-Button in die Zwischenablage, öffne Webtigerpython und füge das Programm aus der Zwischenablage in das Editor-Fenster ein (rechte Maustaste, einsetzen). Starte das Programm und schließe es mit der rechten Maustaste oder drücke auf einem Tablet den Stopp-Button von WTP.
Programm 1.
import pygame
WIDTH = 650
HEIGHT = 450
WHITE = (255, 255, 255)
BLACK = (0, 0, 0, 0)
RED = (255, 0, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
LIGHTGREY = (240, 240, 240)
def init():
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Ein leeres Fenster")
screen.fill(LIGHTGREY)
pygame.display.flip()
return screen
def handle_events():
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
return True
def main():
screen = init()
running = True
while running:
running = handle_events()
pygame.quit()
main()
Struktur eines Pygame-Prgramms
Jedes Pygame-Programm beginnt mit dem Import der Pygame-Bibliothek. Dann folgt die Deklaration der benötigten Konstanten, wie in unserem ersten Bespiel verschiedene Farben als RGB-Tupel, die Breite und Höhe des Pygame-Fensters. Außerdem enthält jedes Programm mindestens die drei Funktionen init(), handle_events() und main():
init()
Die Funktion init zeichnet das Pygame-Grafikfenster in der angegebenen Farbe..
Wichtige Pygame-Anweisungen
| Zeile | Erläuterung |
|---|---|
| 14 | Alle benötigten Pygame-Module werden gestartet. |
| 15 | Das Grafikfenster mit der angegebenen Höhe und Breite wird gezeichnet. |
| 16 | Mit dieser Anweisung kann dem Programm ein Name gegeben werden, der normalerweise in der Titelzeile des Fensters erscheint. Hat in WTP keine Wirkung |
| 18 | Das Grafikfenster wird mit der Farbe HELLGRAU gefüllt. |
| 19 | Das Grafikfenster wird aktualisiert, damit alle Änderungen sichtbar werden. |
| 20 | Das Grafikfenster wird zur weiteren Verwendung zurückgegeben. |
DIese Fuktion kann für alle Programme aus Programm 1 übernommen werden. Lediglich die Hintergrundfarbe des Fensters sollte bei Bedarf geändert werden. Die Größe kann durch Verändern der Konstanten WIDTH und HEIGHT angepasst werden.
def handle_events()
Diese Funktion verarbeitet alle im Programm vorkommenden Ereignisse wie zum Beispiel Tastatureingaben sowie Mausclicks und -bewegungen. Alle Ereignisse (englisch events) werden von pygame in einer Event-Liste gesammelt. Diese Funktion wird regelmäßig aufgerufen . Wenn die Event-Liste nicht leer ist, werden nacheinander alle gesammelten Ereigniss bearbeitet solange die Funktion nicht durch return beendet wird. In unserem ersten Beispiel wird lediglich mit event.type == pygame.MOUSEBUTTONDOWN abgefragt, ob eine Maustaste gedrückt wurd und mit event.button == 3, ob es die rechte Maustaste war. Wenn beide Bedingungen erfüllt sind, gibt die Funktion den Wert False zurück und das Programm wird beendet. Wenn die Rückgabe True ist, läuft das Programm weiter. Startet man ein pygame-Programm in einer nicht browserbasierten Entwicklungsumgebung sind die hier auskommentierten Zeilen 24 und 25 zwingend erforderlich, um das Programm über den roten Schließen-Button beenden zu können.
def main()
Diese Funktion ist das sogeannte "Hauptprogramm". Zunächst wird mit screen = init() das Grafikfenster erzeugt und in der Variablen screen gespeichert. Die Variable running , deren Wert bestimmt, ob das Programm läuft, wird auf True gesetzt. In der sich anschließenen Programm-Schleife wird kontinuierlich die Funktion handle_events aufgerufen. Erst wenn diese den Wert False zurückliefert wird die Variable running auf False gesetzt und die Schleife und damit das Programm beendet. pygame.quit() bereinigt den Speicher.
Das Programm wird durch den Aufruf von main() gestartet.
|
Bearbeite jetzt Aufgabe 1 unter dem Reiter Aufgabe 1. |
Formen zeichnen
In diesem Abschnitt lernst du, geometrische Formen mit Pygame zu zeichnen. Wenn du die Funktion
def draw_shapes(screen):
# Gefülltes Rechteck
pygame.draw.rect(screen, BLUE, (50, 50, 100, 50))
# Rechteck nur mit Rand
pygame.draw.rect(screen, RED, (200, 50, 100, 50), 4)
# Rechteck mit Füllung und sichtbarem Rand
pygame.draw.rect(screen, GREEN, (350, 50, 100, 50))
pygame.draw.rect(screen, RED, (350, 50, 100, 50), 4)
# Gefüllter Kreis
pygame.draw.circle(screen, RED, (100, 180), 40)
# Kreis nur mit Rand
pygame.draw.circle(screen, BLUE, (250, 180), 40, 4)
# Kreis mit Füllung und sichtbarem Rand
pygame.draw.circle(screen, GREEN, (400, 180), 40)
pygame.draw.circle(screen, RED, (400, 180), 40, 4)
#Bogen
pygame.draw.arc(screen, (0, 0, 0), (100, 220, 300, 120), math.radians(0), math.radians(180), 6)# Gefülltes Polygon (Dreieck)
pygame.draw.polygon(screen, GREEN, [(100, 300), (150, 360), (50, 360)])
# Polygon nur mit Rand
pygame.draw.polygon(screen, BLUE, [(250, 300), (300, 360), (200, 360)], 4)
# Polygon mit Füllung und sichtbarem Rand
pygame.draw.polygon(screen, RED, [(400, 300), (450, 360), (350, 360)])
pygame.draw.polygon(screen, BLUE, [(400, 300), (450, 360), (350, 360)], 4)
pygame.display.flip()
in das erste Programm hinter der Funktion init() einfügst und in der main-Funktion vor der Schleife draw_shapes(screen) aufrufst, wird nebenstehendes Bild gezeichnet. Bei allen Zeichenanweisungen für Formen ist der erste Parameter die von init gelieferte Variable screen, dann folgt die Farbe als RGB-Tupel bzw. vorher definierte Konstante, dann verschiedene Parameter (Tupel oder einzelne Werte), die von der zu zeichnenden Form abhängen. So muss man bei Rechtecken ein Vier-Tupel mit x und y-Koordinate der linken oberen Ecke sowie Breite und Höhe angeben, bei einem Kreis ein Tupel mit den Koordinaten des Mittelpunktes und den Radius, bei einem Polygon werden die Koordinaten der Ecklunkte in einer Liste an die Zeichenfunktion übergeben. Wenn man als letzten Parameter zusätzlich eine Zahl einfügt, die die Rahmenbreite der Figur festlegt, wird nur der Rahmen in der angegebenen Farbe ohne Füllung gezeichnet, fehlt dieser Parameter wird eine in der angegebenen Farbe gefüllte Figur gezeichnet. Die folgendeTabelle listet alle wesentlichen Zeichenfunktionen von Pygame auf:
| Funktion | Bedeutung | Wichtige Parameter |
|---|---|---|
| pygame.draw.rect(screen, col, rect, width) | Zeichnet den Rahmen eines Rechtecks mit den angegebenen Maßen. Die Farbe (col) bestimmt die Rahmenfarbe und width die Breite des Rahmens in Pixel. | screen: Grafikfenster col: (R,G,B)-Tupel rect: (x, y, width, height)-Tupel width: int als Rahmenbreite |
| pygame.draw.rect(screen, col, rect) | Zeichnet ein mit der angegebenen Farbe ausgefülltes Rechteck mit den angegebenen Maßen. | screen: Grafikfenster col: (R,G,B)-Tupel rect: (x, y, width, height)-Tupel |
| pygame.draw.circle(screen, col, center, radius, width) | Zeichnet den Rand eines Kreises mit dem angegebenen Mittelpunkt und dem Radius. Der Rand wird in der angegebenen Farbe mit der angegebenen Breite gezeichnet.. | screen: Grafikfenster ;col: (RGB)-Tupel center: (x, y)-Tupel radius: int width: int als Rahmenbreite |
| pygame.draw.circle(screen, col, center, radius) | Zeichnet einen Kreis mit dem angegebenen Mittelpunkt und dem angegebenen Radius, gefüllt mit der angegebenen Farbe. | screen: Grafikfenster: col: (RGB)-Tupel center: (x, y)-Tupel radius: int |
| pygame.draw.line(screen, col, start_point, end_point, width) | Zeichnet eine gerade Linie vom Startpunkt zum Endpunkt mit der angegebenen Breite in der angegebenen Farbe. | screen: Grafikfenster col: (RGB)-Tupel start_point: (x1, y1) end_point: (x2, y2) width: Linienbreite |
| pygame.draw.ellipse(screen, col, rect, width) | Zeichnet den Rand einer Ellipse, die von dem angegebenen Rechteck (unsichtbar) umrahmt wird. Der Rand wird in der angegebenen Farbe mit der angegebenen Breite gezeichnet. | screen: Grafikfenster col: (R,G, B)-Tupel rect: (x, y, width, height) width: int als Rahmenbreite |
| pygame.draw.ellipse(screen, col, rect). | Zeichnet eine Ellipse, die von dem angegebenen Rechteck (unsichtbar) umrahmt wird, gefüllt mit der angegebenen Farbe. | screen: Grafikfenster col: (R,G, B)-Tupel rect: (x, y, width, height) |
| pygame.draw.polygon(screen, col, points, width) | Zeichnet den Rand eines Vielecks, indem die in der Liste enthaltenen Punkte verbunden werden. | screen: Grafikfenster col: (R,G,B) - Tupel points: Liste von (x, y) width: int als Rahmenbreite |
| pygame.draw.polygon(screen, col, points) | Zeichnet ein Vielecks, indem die in der Liste enthaltenen Punkte verbunden werden. Das Vieleck wird mit der angegebenen Farbe gefüllt | screen, farbe punkte: Liste von (x, y) |
| pygame.draw.arc(screen, col, rect, start_angle, stop_angle, width) | Zeichnet einen Kreisbogen- Das angegebene Rechteck gibt den Rahmen einer Ellipse an, von der der angegebene Bogen ausgeschnitten uwrd. Die beiden Winkel im Bogenmaß bestimmen den Ausschnitt des Ellipsenbogens. | screen: Grafikfenster col: (R,G,B)-Tupel rect: (x, y, width, height)-Tupel, das die Ellipse beschreibt, von der der Bogen ein Teil ist. start_angle: Der Startwinkel des Bogens (im Bogenmaß), gemessen vom rechten Rand der Ellipse gegen den Uhrzeigersinn. bogenmass = math.radian(winkel) stop_angle: Der Endwinkel des Bogens (im Bogenmaß). width: Die Strichbreite des Bogens |
Hier ist das vollständige Programm, das du kopieren und in WebTigerPython einfügen kannst.
Programm 2
import pygame
import math
WIDTH = 650
HEIGHT = 450
BLUE = (0, 0, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
LIGHTGREY = (240, 240, 240)
def init():
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
screen.fill(LIGHTGREY)
pygame.display.flip()
return screen
def draw_shapes(screen):
# Gefülltes Rechteck
pygame.draw.rect(screen, BLUE, (50, 50, 100, 50))
# Rechteck nur mit Rand
pygame.draw.rect(screen, RED, (200, 50, 100, 50), 4)
# Rechteck mit Füllung und sichtbarem Rand
pygame.draw.rect(screen, GREEN, (350, 50, 100, 50))
pygame.draw.rect(screen, RED, (350, 50, 100, 50), 4)
# Gefüllter Kreis
pygame.draw.circle(screen, RED, (100, 180), 40)
# Kreis nur mit Rand
pygame.draw.circle(screen, BLUE, (250, 180), 40, 4)
# Kreis mit Füllung und sichtbarem Rand
pygame.draw.circle(screen, GREEN, (400, 180), 40)
pygame.draw.circle(screen, RED, (400, 180), 40, 4)
#Zeichnet einen Bogen
pygame.draw.arc(screen, (0, 0, 0), (100, 220, 300, 120), math.radians(0), math.radians(180), 6)
# Gefülltes Polygon (Dreieck)
pygame.draw.polygon(screen, GREEN, [(100, 300), (150, 360), (50, 360)])
# Polygon nur mit Rand
pygame.draw.polygon(screen, BLUE, [(250, 300), (300, 360), (200, 360)], 4)
# Polygon mit Füllung und sichtbarem Rand
pygame.draw.polygon(screen, RED, [(400, 300), (450, 360), (350, 360)])
pygame.draw.polygon(screen, BLUE, [(400, 300), (450, 360), (350, 360)], 4)
pygame.display.flip()
def handle_events():
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 3: # Rechte Maustaste
return False
return True
def main():
screen = init()
draw_shapes(screen)
running = True
while running:
running = handle_events()
pygame.quit()
main()
|
Bearbeite jetzt die Aufgabe 2 unter dem Reiter Aufgabe 1. |
Bisher haben wir nur verschiedene zweidimenstionale Grafiken programmiert. Pygame bietet aber auch die Möglichkeit Text im Grafikfenster abzubilden. Die folgende Funktion zeichnet den als Parameter an text_string übergebenen Text an der Position (0,0) in das Grafikfenster.
def draw_text(screen, text_string):
font = pygame.font.Font(None, 48)
text = font.render(text_string, True, (255, 255, 255))
text_rect = text.get_rect()
screen.blit(text, text_rect)
Die Ausgabe von Texten im Grafikfenster erfolgt in 4 Schritten:
- font = pygame.font.Font(Schriftart, Schriftgröße)
Dies Anweisung erzeugt eine Schriftart. Die Schriftart kann als String (z.B. "Arial", "Comic Sans MS",..) beliebig gewählt werden, ebenso die Schriftgröße als ganze Zahl in Punkten. Gibt man für die Schriftart None ein, wird die Systemschrift genommen. - text = font.render(Text, True, Farbe als RN-Tupel) Diese Anweisung wandelt den Text in eine Grafik um, Als erster Parameter wird der zu zeichnende Text übergeben, der zweite Parameter sollte immmer True sein, damit die Schrift schön glatt geschrieben wird, dann folgt die Schriftfarbe als RGB-Tuperl oder als Konstante.
- text_rect = text.get_rect()
In dieser Anweisung wird text_rect das Rechteck der Schriftgrafik als 4-Tupel zugewiesen. Die ersten beiden Komponenten des Tupesl sind der Startpunkt 0,0. Möchte man die Bildgrafik zentriert auf den Bildschirm schreiben verwendet man die Anweisung text_rect = text.get_rect(enter=(WIDTH // 2, HEIGHT // 2)) - screen.blit(text, text_rect)
Diese Anweisung zeichnet den Text. Anstelle von text_rect kann man auch ein Koordinatentupel als Startpunkt für den Text eingeben und dann die 3. Anweisung weglassen.
|
Teste die Funktion in WebTigerPython. Verwende dabei verschiedene Schriftarten und Schriftgrößen sowie verschiedene Positionen des Textes |

Als Anwendungsbeispiel programmieren wir eine Digitaluhr, die neben der Zeit auch das aktuelle Datum anzeigt. Zunächst müssen wir noch klären, wie man in Python an die aktuelle Zeit und das aktuelle Datum kommt.
Die folgende Funktion liest die aktuelle Zeit und das aktuelle Datum ein und gibt die Daten als formatierte Strings zurück.
from datetime import datetime
def get_current_time():
now = datetime.now()
time_str = now.strftime("%H:%M:%S")
date_str = now.strftime("%d.%m.%Y")
return time_str, date_str
| Zeile | Erläuterung |
|---|---|
| 1 | Die Funktion datetime wird von der Bibliothek datetime importiert |
| 4 | Der Variablen now wird das aktuelle Datum und die aktuelle Zeit zugewiesen. |
| 5 | Der Variablen time_str wird ein formatierteer String der aktuellen Zeit zugewiesen. |
| 6 | Der Variablen date_str wird ein formatierter String des aktuellen Datums zugewiesen. |
| 7 | Der Zeit- und der Datumsstring werden zurückgegeben. |
|
Entwickle mithilfe der Funktionen get_current_time und draw_text das Programm zur Simulation einer Digitaluhr. Beachte: Der Bildschirm muss einmal pro Sekunde aktualisiert werden. |
import pygame
from datetime import datetime
WIDTH = 650
HEIGHT = 450
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
LIGHTGREY = (240, 240, 240)
DARKGREY = (50, 50, 50)
def init():
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
screen.fill(BLACK)
pygame.display.flip()
return screen
def draw_digital_clock(screen, time_str):
# Font für die Digitaluhr
font = pygame.font.Font(None, 120)
text = font.render(time_str, True, GREEN)
text_rect = text.get_rect(center=(WIDTH // 2, HEIGHT // 2))
screen.blit(text, text_rect)
def draw_date(screen, date_str):
# Font für das Datum
font = pygame.font.Font(None, 36)
text = font.render(date_str, True, WHITE)
text_rect = text.get_rect(center=(WIDTH // 2, HEIGHT // 2 + 100))
screen.blit(text, text_rect)
def handle_events():
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 3: # Rechte Maustaste
return False
return True
def main():
clock = pygame.time.Clock()
screen = init()
running = True
while running:
# Aktuelle Zeit holen
now = datetime.now()
time_str = now.strftime("%H:%M:%S")
date_str = now.strftime("%d.%m.%Y")
# Bildschirm löschen
screen.fill(BLACK)
# Uhr zeichnen
draw_digital_clock(screen, time_str)
draw_date(screen, date_str)
# Display aktualisieren
pygame.display.flip()
# Events verarbeiten
running = handle_events()
# FPS begrenzen
clock.tick(1) # 1 FPS für Sekundenaktualisierung
pygame.quit()
main()
Formen bewegen
In diesem Abschnitt lernst du, wie du eine beliebige Form auf der Zeichenfläche programmgesteuert bewegen kannst. Wir entwickeln ein Programm, in dem sich ein roter Kreis auf der Zeichenfläche wie eine Kugel auf einem Billardtisch bewegt. Das nebenstehende Video zeigt dir den Ablauf des Programms.
Wenn man ein Objekt in der Zeichenfläche bewegen will, muss man seine Position verändern. Bei einem Kreis müssen wir die Koordinaten des Mittelpunktes verändern. Dazu müssen die Koordinaten in Variablen gespeichert werden. Wir schreiben zunächst eine Funktion, die einen Kreis zeichnet. Die Koordinaten des Mittelpunktes, den Radius sowie die Füllfarbe übergeben wir als Parameter an die Funktion.
Aus diesen Überlegungen ergibt sich folgende Funktion:
def draw_circle(screen,x, y, r, color):
pygame.draw.circle(screen, color, (x,y), r)
Zu Beginn der main-Funktion müssen wir den Variablen für die Kreisdaten die Anfangswerte zuweisen. Wir wählen die Namen x und y für die Koordinaten des Mittelpunktes, radius für den Radius und color für die Farbe. Außerdem benötigen wir Variablen, für die Positionsveränderung des Kreises. Wir beginnen mit einer horizontalen Bewegung des Kreises und deklarieren daher die Variable dx = 2, d.h. bei jedem Schritt soll sich der Kreis um 2 Pixel nach rechts bewegen. Der Aufruf der Funktion circle_draw muss innerhalb der Programm-Schleife erfolgen, weil sich die Position des Kreises bei jedem Durchlauf verändert. Zu Beginn der Programm-Schleife müssen wir das Grafikfenster löschen. Das geschieht mit der Anweisung screen.fill(LIGHTGREY). Am Ende der Programm-Schleife werden die Objekte neu zeichnen mit der Anweisung pygame.display.flip(). Um den Kreis bei jedem Schleifendurchlauf um 2 Pixel nach rechts zu bewegen, erhöhen wir die x-Position des Mittelpunktes nach dem Zeichnen des Kreises um dx. Zuletzt müssen wir noch festlegen, wie schnell sich der Kreis bewegen soll. Dazu verwenden wir die in pygame enthaltene Uhr. Nach der Initialisierung der Zeichenfläche müssen wir dazu die Anweisung clock = pygame.Clock.time einfügen. Mit clock.tick(ganze Zahl) legen wir fest, wie oft die Schleife in der Sekunde durchlaufen werden soll. Wir fügen dazu als letzte Anweisung der Programm-Schleife clock.tick(60) in die Funktion main() ein.Mit der Zahl kannst du experimentieren, um die gewünschte Geschwindigkeit festzulegen. Je größer die Zahl ist, umso schneller bewegt sich der Kreis. Natürlich wird durch die technischen Möglichkeiten des Bildschirmes eine Obergrenze festgelegt. Damit haben wir nun folgende main-Funktion:
def main():
clock = pygame.time.Clock()
screen = init()
x, y = 200, 300
radius = 30
color = RED
dx = 2
running = True
while running:
screen.fill(LIGHTGREY)
draw_circle(screen,x, y, radius, color)
x = x + dx
pygame.display.flip()
running = handle_events()
clock.tick(60)
pygame.quit()
Wenn du diese Programm in WebTigerPython startest, erscheint der rote Ball in der Zeichenfläche und bewegt sich langsam nach rechts, bis er verschwindet. Was ist zu tun? Wir müssen prüfen, ob sich der Kreis am rechten Rand befindet. Wenn das der Fall ist, muss die Bewegunsrichtung geändert werden, indem dx auf -2 gsetzt wird, Entsprechend, muss dx wieder 2 zugewiesen werden, wenn sich der Kreis am linken Rand der Zeichenfläche befindet. Allgemein kann man sagen, dass der Wert von dx mit -1 multipliziert werden muss, wenn sich der Kreis am rechten oder linken Rand der Zeichenfläche befindet, Um das festzustellen, entwickeln wird die Funktion edge_left_right() die True zurückliefert, wenn sich der Kreis am rechten oder linken Rand befindet.
def edge_left_right(x, r):
if x + r > WIDTH or x - r < 0:
returnTrue
return False
|
Erläutere die Funktion edge_left_right. |
Hier ist nun das vollständige Programm, das du kopieren und in WebTigerPython testen kannst.
Programm 4
import pygame
WIDTH = 650
HEIGHT = 450
WHITE = (255, 255, 255)
BLACK = (0, 0, 0, 0)
RED = (255, 0, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
LIGHTGREY = (240, 240, 240)
def init():
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
screen.fill(LIGHTGREY) # Schwarzer Hintergrund
pygame.display.flip()
return screen
def draw_circle(screen,x, y, r, color):
pygame.draw.circle(screen, RED, (x,y), r)
def edge_left_right(x, r):
if x + r > WIDTH or x - r < 0:
return True
return False
def handle_events():
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 3: # Rechte Maustaste
return False
return True
def main():
clock = pygame.time.Clock()
screen = init()
x, y = 200, 300
radius = 30
color = RED
dx = 2
running = True
while running:
screen.fill(LIGHTGREY)
draw_circle(screen,x, y, radius, color)
if edge_left_right(x, radius):
dx = dx * -1
x = x + dx
pygame.display.flip()
running = handle_events()
clock.tick(60)
pygame.quit()
main()
|
Erweitere das Programm so, dass sich der Ball in alle Richtungen bewegt und auch am oberen und unteren Bildrand abprallt.
Verwende eien Variable dy zur Veränderung der y-Position. Schreibe eine Funktion edge_up_down(y, r) entsprechend der Prüfung am rechten oder linken Rand und rufe sie in main auf. |
import pygame
WIDTH = 650
HEIGHT = 450
WHITE = (255, 255, 255)
BLACK = (0, 0, 0, 0)
RED = (255, 0, 0, 0)
GREEN= (0, 255, 0)
BLUE = (0, 0, 255)
LIGHTGREY = (240, 240, 240)
def init():
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
screen.fill(LIGHTGREY) # Schwarzer Hintergrund
pygame.display.flip()
return screen
def draw_circle(screen,x, y, r):
pygame.draw.circle(screen, RED, (x,y), r)
def edge_left_right(x, r):
if x + r > WIDTH or x - r < 0:
return True
return False
def edge_up_down(y, r):
if y + r > HEIGHT or y - r < 0:
return True
return False
def handle_events():
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 3: # Rechte Maustaste
return False
return True
def main():
clock = pygame.time.Clock()
screen = init()
x, y = 200, 300
r = 30
dx = 2
dy = 1
running = True
while running:
screen.fill(LIGHTGREY)
draw_circle(screen,x, y, r)
x = x + dx
y = y + dy
if edge_left_right(x, r):
dx = dx * -1
if edge_up_down(y, r):
dy = dy * -1
pygame.display.flip()
running = handle_events()
clock.tick(60)
pygame.quit()
main()
|
Bearbeite jetzt die Aufgabe 3 unter dem Reiter Aufgabe 1. |
Mehrere Kreise
Das Programm soll nun so erweitert werden, dass sich mehrere Kreise gleichzeitig auf der Zeichenfläche bewegen. Um uns die Daten jedes Kreises zu merken, müssten wir für jeden Ball einen eigenen Variablensatz mit den Koordinaten des Mittelpunktes, des Radius, der Farbe und der Bewegungsdistanzen in x- und y- Richtung deklarieren. Das würde das Programm sehr lang und damit sehr unübersichtlich machen.
Wenn man mehrere Daten zusammenfassen will, bietet es sich an eine Liste zu verwenden. Die Daten eines einzelnen Kreises speichern wir in einem Dictionary mit den Schlüsseln "x", "y", "radius", "color", "dx", und "dy". Die folgende Liste circle enthält die Daten zweier Kreise.
Beispiel
circles = [{"x":100, "y":200, "radius": 30,color: RED, "dx": 2, "dy": -1}, {"x":300, "y":70, "radius": 20,color: GREEN, "dx": -2, "dy": 1}]
Um das Programm übersichtlich zu halten, enwickeln wir zunächst einige Hilfsfunktionen.
Die folgende Funktion get_circle_dict(x, y, r, col, dx, dy) liefert das Dictionary mit den als Parameter übergebenen Daten eines Kreises zurück.
def get_circle_dict(x, y, r, col, dx, dy):
return {"x":x, "y":y, "radius": r, "color":col,"dx":dx, "dy":dy}
Die folgende Funktion get_random_circle_list(n) erzeugt eine Liste mit n Circle-Dictionaries. Dabei werden die Daten zufällig bestimmt. Der Radius erhält einen Wert zwschen 10 und 20, x bekommt einen Wert zischen dem Radius und der Fensterbreite minus dem Radius. Damit ist garantiert, dass der Kreis in der Zeichenfläche liegt. Entsprechend bekommt y einen Wert zwischen dem Radius und der Höhe des Zeichenfensters minus dem Radius zugewiesen.. dx und dy erhalten zufällige Werte zwischen 2 und -2. Wenn der Wert 0 ist, muss er noch korrigiert werden, damit sich der Kreis bewegt. Die Zufallsfarbe wird durch zufällige Bestimmung der RGB-Werte zischen 0 und 255 festgelegt.
def get_random_circle_list(n):
circle_list = []
for _ in range(n):
radius = random.randint(10, 20)
x = random.randint(radius, WIDTH - radius)
y = random.randint(radius, HEIGHT - radius)
dx = random.randint(-2,2)
if dx == 0:
dx = dx + 1
dy = random.randint(-2,2)
if dy == 0:
dy = dy - 1
col = (random.randint(0, 255),random.randint(0, 255),random.randint(0, 255))
circle_list.append(get_circle_dict(x, y, radius, col, dx, dy ))
return circle_list
Selbstverständlich müssen auch die Funktion draw_circle, edge_left_right und edge_up_down der neuen Datenstruktur angepasst werden. Außerdem implementieren wird eine weitere Funktion move_circle(c) die den Kreis um die vorgegebenen Distanzen bewegt. Das Circle-Dictionary wird jeweils an den Parameter c übergeben und auf die Daten wird in den Funktionen über die keys zugegriffen. Wenn man durch Zugriff auf den key einen Wert des Dictionaris verändert, ändert sich damit automatisch der Wert auch im entsprechenden Dictionary der Liste, da der Parameter lediglich einen Verweis auf dieses Dictionary enthält.
def draw_circle(screen,c):
pygame.draw.circle(screen, c["color"], ( c["x"], c["y"]), c["radius"])
def edge_left_right(c):
if c["x"] + c["radius"] > WIDTH or c["x"] - c["radius"] < 0:
return True
return False
def edge_up_down(c):
if c["y"] + c["radius"] > HEIGHT or c["y"] - c["radius"] < 0:
return True
return False
def move_circle(c):
c["x"]=c["x"]+c["dx"]
c["y"]=c["y"]+c["dy"]
Die veränderte Main-Funktion nutzt diese Funktionen.
def main():
clock = pygame.time.Clock()
screen = init()
circles = get_random_circle_list(100)
running = True
while running:
screen.fill(LIGHTGREY)
for circle in circles:
draw_circle(screen, circle)
move_circle(circle)
if edge_left_right(circle):
circle["dx"]=circle["dx"]* -1
if edge_up_down(circle):
circle["dy"]=circle["dy"]* -1
pygame.display.flip()
running = handle_events()
clock.tick(60)
pygame.quit()
|
Erweitere das Python-Programm mit dem sich bewegenden Kreis mithilfe der hier erläuterten Funktionen so, dass sich 100 Kreise auf der Zeichenfläche bewegen. |
import pygame
import random
# mehrere Kreise
WIDTH = 650
HEIGHT = 450
WHITE = (255, 255, 255)
BLACK = (0, 0, 0, 0)
RED = (255, 0, 0, 0)
GREEN = (0, 255, 0)
DARKGREEN = (34, 139, 34)
BLUE = (0, 0, 255)
LIGHTGREY = (240, 240, 240)
def init():
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
screen.fill(LIGHTGREY) # Schwarzer Hintergrund
pygame.display.flip()
return screen
def get_circle_dict(x, y, r, col, dx, dy):
return {"x":x, "y":y, "radius": r, "color":col,"dx":dx, "dy":dy}
def draw_circle(screen,c):
pygame.draw.circle(screen, c["color"], ( c["x"],c["y"]), c["radius"])
def edge_left_right(c):
if c["x"] + c["radius"]> WIDTH or c["x"] - c["radius"] < 0:
return True
return False
def edge_up_down(c):
if c["y"] + c["radius"]> HEIGHT or c["y"] - c["radius"] < 0:
return True
return False
def move_circle(c):
c["x"]=c["x"]+c["dx"]
c["y"]=c["y"]+c["dy"]
def get_random_circle_list(n):
circle_list = []
for _ in range(n):
radius = random.randint(10, 20)
x = random.randint(radius, WIDTH - radius)
y = random.randint(radius, HEIGHT - radius)
dx = random.randint(-2,2)
if dx == 0:
dx = dx + 1
dy = random.randint(-2,2)
if dy == 0:
dy = dy - 1
col = (random.randint(0, 255),random.randint(0, 255),random.randint(0, 255))
circle_list.append(get_circle_dict(x, y, radius, col, dx, dy ))
return circle_list
def handle_events():
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 3: # Rechte Maustaste
return False
return True
def main():
clock = pygame.time.Clock()
screen = init()
circles = get_random_circle_list(100)
running = True
while running:
screen.fill(LIGHTGREY)
for circle in circles:
draw_circle(screen, circle)
move_circle(circle)
if edge_left_right(circle):
circle["dx"]=circle["dx"]* -1
if edge_up_down(circle):
circle["dy"]=circle["dy"]* -1
pygame.display.flip()
running = handle_events()
clock.tick(60)
main()
|
Bearbeite die Aufgaben 3 und 4 unter dem Reiter Aufgaben 1 |
Lösung