modified
This commit is contained in:
1 parent
84f0f9e8fb
commit
ecb59a6571
1 file changed
+57
-12
+57
-12
@@ -2,88 +2,133 @@ import pygame
|
||||
|
||||
|
||||
class Game:
|
||||
|
||||
def __init__(self):
|
||||
# Initialisiert alle Module von Pygame
|
||||
pygame.init()
|
||||
|
||||
# Erstellt das Hauptfenster mit einer Auflösung von 800x600 Pixeln
|
||||
self.screen = pygame.display.set_mode((800, 600))
|
||||
|
||||
# Setzt den Fenstertitel
|
||||
pygame.display.set_caption("Undo Doodle")
|
||||
|
||||
# Erstellt eine Clock, um die Bildwiederholrate (Framerate) zu steuern
|
||||
self.clock = pygame.time.Clock()
|
||||
|
||||
# Der Zustand ist eine Liste von Strichen.
|
||||
# Jeder Strich ist eine Liste von Punkten (tuples).
|
||||
# Initialisierung des Zustands:
|
||||
# Der Zustand ist eine Liste von Strichen. Jeder Strich ist eine Liste von Punkten (Tuples).
|
||||
initial_state = []
|
||||
|
||||
# Die Historie speichert die aufeinanderfolgenden, immutablen Zustände
|
||||
# Die Historie speichert die aufeinanderfolgenden, unveränderbaren (immutablen) Zustände.
|
||||
# Zu Beginn enthält sie nur den leeren Anfangszustand.
|
||||
self.history = [initial_state]
|
||||
|
||||
# Steuerungs-Flags für den Zeichenvorgang
|
||||
self.drawing = False
|
||||
self.current_stroke = []
|
||||
|
||||
@property
|
||||
def current_state(self):
|
||||
"""Liefert den aktuellen Zustand (oberstes Element der Historie)."""
|
||||
"""Der @property-Decorator sorgt dafür, dass diese Methode wie ein Attribut aufgerufen wird (ohne Klammern).
|
||||
|
||||
Sie liefert immer den aktuellen Zustand zurück – das ist das jeweils letzte Element am Ende der Historie.
|
||||
Für den Code, der die Klasse von außen benutzt, sieht es so aus, als würde man einfach nur einen Wert ablesen.
|
||||
Im Hintergrund kann die Methode aber komplizierte Berechnungen anstellen, Werte prüfen oder Daten umwandeln,
|
||||
ohne dass der Aufrufer das merken muss.
|
||||
"""
|
||||
return self.history[-1]
|
||||
|
||||
def run(self):
|
||||
# Die Hauptschleife des Spiels (Game Loop)
|
||||
running = True
|
||||
while running:
|
||||
# 1. Eingaben verarbeiten (Events)
|
||||
running = self.handle_events()
|
||||
# 2. Spiel-Logik aktualisieren (hier nicht nötig, aber im Loop enthalten)
|
||||
self.update()
|
||||
# 3. Alles auf den Bildschirm zeichnen
|
||||
self.draw()
|
||||
# Begrenzt das Spiel auf 60 Bilder pro Sekunde
|
||||
self.clock.tick(60)
|
||||
|
||||
|
||||
pygame.quit()
|
||||
|
||||
def handle_events(self):
|
||||
# Fängt alle Benutzer-Eingaben (Maus, Tastatur, Fenster schließen) ab
|
||||
for event in pygame.event.get():
|
||||
# Fall A: Benutzer schließt das Fenster
|
||||
if event.type == pygame.QUIT:
|
||||
return False
|
||||
|
||||
# Fall B: Eine Taste wird gedrückt
|
||||
elif event.type == pygame.KEYDOWN:
|
||||
# Mit 'u' oder Strg+Z einen Schritt zurückgehen (Undo)
|
||||
# Prüft, ob 'u' oder Strg + 'Z' gedrückt wurde (Undo-Befehl)
|
||||
if event.key == pygame.K_u or (event.key == pygame.K_z and (pygame.key.get_mods() & pygame.KMOD_CTRL)):
|
||||
# Wir können nur Undo machen, wenn noch mehr als der Urzustand in der Historie ist
|
||||
if len(self.history) > 1:
|
||||
# Entfernt den obersten/neuesten Zustand aus der Historie -> springt zum vorherigen zurück
|
||||
self.history.pop()
|
||||
print("Undo ausgeführt!")
|
||||
|
||||
# Fall C: Maustaste wird heruntergedrückt (Zeichnen starten)
|
||||
elif event.type == pygame.MOUSEBUTTONDOWN:
|
||||
if event.button == 1: # Linke Maustaste gedrückt
|
||||
if event.button == 1: # Linke Maustaste
|
||||
self.drawing = True
|
||||
# Startet einen neuen Strich und fügt direkt den ersten Punkt (Mausposition) hinzu
|
||||
self.current_stroke = [event.pos]
|
||||
|
||||
# Fall D: Maus wird bei gedrückter Taste bewegt (Linie ziehen)
|
||||
elif event.type == pygame.MOUSEMOTION:
|
||||
if self.drawing:
|
||||
# Fügt den aktuellen Punkt zur Liste des aktuellen Strichs hinzu
|
||||
self.current_stroke.append(event.pos)
|
||||
|
||||
# Fall E: Maustaste wird losgelassen (Strich beenden)
|
||||
elif event.type == pygame.MOUSEBUTTONUP:
|
||||
if event.button == 1 and self.drawing:
|
||||
self.drawing = False
|
||||
if self.current_stroke:
|
||||
# IMMUTABLE ANSATZ:
|
||||
# Erstelle einen völlig neuen Zustand (neue Liste),
|
||||
# anstatt den alten Zustand direkt zu verändern.
|
||||
# IMMUTABLE ANSATZ IN AKTION:
|
||||
# Statt den alten Zustand direkt zu verändern (z.B. mit .append()),
|
||||
# erstellen wir mit `self.current_state + [self.current_stroke]`
|
||||
# eine völlig neue Liste (ein neues Objekt).
|
||||
new_strokes = self.current_state + [self.current_stroke]
|
||||
|
||||
# Dieser neue Zustand wird als nächster Schritt an die Historie angehängt.
|
||||
self.history.append(new_strokes)
|
||||
|
||||
# Setzt den temporären Strich für den nächsten Zug zurück
|
||||
self.current_stroke = []
|
||||
|
||||
return True
|
||||
|
||||
def update(self):
|
||||
# Platzhalter für Logik-Updates
|
||||
pass
|
||||
|
||||
def draw(self):
|
||||
self.screen.fill((255, 255, 255)) # Hintergrund weiß füllen
|
||||
# Füllt den gesamten Bildschirm mit Weiß
|
||||
self.screen.fill((255, 255, 255))
|
||||
|
||||
# 1. Zeichne alle fertigen Striche aus dem aktuellen Zustand
|
||||
# 1. Zeichnet alle bereits fertigen Striche aus dem aktuellen Zustand
|
||||
# Dank @property greifen wir hier ganz einfach ohne Klammern auf `self.current_state` zu.
|
||||
for stroke in self.current_state:
|
||||
if len(stroke) > 1:
|
||||
# Zeichnet eine glatte Linie über alle Punkte des Striches (schwarz, Stärke 3)
|
||||
pygame.draw.lines(self.screen, (0, 0, 0), False, stroke, 3)
|
||||
|
||||
# 2. Zeichne den aktuellen Strich während des Ziehens in einer Vorschau-Farbe
|
||||
# 2. Zeichnet den aktuellen Strich in Echtzeit als Vorschau während des Ziehens
|
||||
if self.drawing and len(self.current_stroke) > 1:
|
||||
# Die Vorschau wird in einem helleren Grau angezeigt
|
||||
pygame.draw.lines(self.screen, (120, 120, 120), False, self.current_stroke, 3)
|
||||
|
||||
# Bringt die gezeichnete Leinwand gebündelt auf den Bildschirm (verhindert Flackern)
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Startet das Spiel, wenn die Datei direkt ausgeführt wird
|
||||
game = Game()
|
||||
game.run()
|
||||
Reference in new issue
Block a user