Added Soundeffects

This commit is contained in:
2025-04-25 16:23:43 +02:00
parent 15635d7f96
commit c046995fdc
7 changed files with 123 additions and 112 deletions

BIN
_start.mp3 Normal file

Binary file not shown.

BIN
fail.mp3 Normal file

Binary file not shown.

235
game.py
View File

@@ -5,14 +5,15 @@ import json
import os
import threading
import time
import serial.tools.list_ports # Import hinzugefügt
import serial.tools.list_ports # Import hinzugefügt
import pygame
class TimeGuessGame:
def __init__(self, root):
self.root = root
self.root.title("Zeit-Schätz-Spiel")
self.root.geometry("800x600")
self.root.resizable(True, True) # Resizable aktiviert
self.root.resizable(True, True) # Resizable aktiviert
# Serielle Verbindung
self.serial_port = None
@@ -28,16 +29,17 @@ class TimeGuessGame:
self.load_leaderboard()
# UI-Elemente
self.canvas_frame_id = None # Hinzugefügt: ID für das Canvas-Fenster
self.canvas_frame_id = None # Hinzugefügt: ID für das Canvas-Fenster
self.create_ui()
pygame.mixer.init()
# Verbindung nicht automatisch beim Start herstellen
# Serielle Kommunikation wird in setup_connection gestartet
# Protokoll für das Schließen des Fensters
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
def create_ui(self):
# ... (Restlicher Code von create_ui bleibt gleich bis zum Ranglisten-Teil) ...
@@ -58,7 +60,7 @@ class TimeGuessGame:
self.start_button = tk.Button(control_frame, text="Neues Spiel starten",
command=self.start_new_game, font=("Arial", 14),
bg="#4CAF50", fg="white", padx=10, pady=5,
state=tk.DISABLED) # Standardmäßig deaktiviert bis Verbindung steht
state=tk.DISABLED) # Standardmäßig deaktiviert bis Verbindung steht
self.start_button.pack(pady=10)
# Frame für Spielinformationen
@@ -90,7 +92,7 @@ class TimeGuessGame:
self.name_label.pack(side=tk.LEFT)
self.name_entry = tk.Entry(name_frame, font=("Arial", 12), width=20)
self.name_entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True) # Nimmt verfügbaren Platz ein
self.name_entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True) # Nimmt verfügbaren Platz ein
button_frame = tk.Frame(name_frame)
button_frame.pack(side=tk.LEFT)
@@ -105,24 +107,24 @@ class TimeGuessGame:
bg="#9E9E9E", fg="white")
self.skip_button.pack(side=tk.LEFT, padx=5)
# --- Frame für Rangliste (Container) ---
leaderboard_outer_frame = tk.Frame(self.root, padx=10, pady=10)
leaderboard_outer_frame.pack(fill=tk.BOTH, expand=True) # Füllt restlichen Platz
leaderboard_outer_frame.pack(fill=tk.BOTH, expand=True) # Füllt restlichen Platz
tk.Label(leaderboard_outer_frame, text="Rangliste", font=("Arial", 16, "bold")).pack()
# --- Canvas und Scrollbar für die Rangliste ---
self.leaderboard_canvas = tk.Canvas(leaderboard_outer_frame)
self.leaderboard_scrollbar = tk.Scrollbar(leaderboard_outer_frame, orient=tk.VERTICAL, command=self.leaderboard_canvas.yview)
self.scrollable_leaderboard_frame = tk.Frame(self.leaderboard_canvas) # Frame *innerhalb* des Canvas
self.leaderboard_scrollbar = tk.Scrollbar(leaderboard_outer_frame, orient=tk.VERTICAL,
command=self.leaderboard_canvas.yview)
self.scrollable_leaderboard_frame = tk.Frame(self.leaderboard_canvas) # Frame *innerhalb* des Canvas
# --- Änderung 1: ID speichern und Bindung an Canvas ---
# Das Frame in den Canvas einbetten und die ID speichern
self.canvas_frame_id = self.leaderboard_canvas.create_window(
(0, 0),
window=self.scrollable_leaderboard_frame,
anchor="nw" # Wichtig: Anker oben links
anchor="nw" # Wichtig: Anker oben links
)
# Konfigurations-Event an den *Canvas* binden, um die Breite des Frames anzupassen
@@ -145,12 +147,12 @@ class TimeGuessGame:
file_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="Datei", menu=file_menu)
file_menu.add_command(label="Rangliste zurücksetzen", command=self.reset_leaderboard)
file_menu.add_command(label="Beenden", command=self.on_closing) # Geändert zu on_closing
file_menu.add_command(label="Beenden", command=self.on_closing) # Geändert zu on_closing
connection_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="Verbindung", menu=connection_menu)
connection_menu.add_command(label="Verbinden", command=self.setup_connection)
connection_menu.add_command(label="Trennen", command=self.disconnect_serial) # Trennen Option
connection_menu.add_command(label="Trennen", command=self.disconnect_serial) # Trennen Option
# --- Änderung 2: Neue Methode zum Anpassen der Frame-Breite ---
def _on_canvas_configure(self, event):
@@ -163,7 +165,6 @@ class TimeGuessGame:
self.leaderboard_canvas.configure(scrollregion=self.leaderboard_canvas.bbox("all"))
# --- Ende Änderung 2 ---
def update_leaderboard_display(self):
# Bestehende Einträge im scrollbaren Frame löschen
for widget in self.scrollable_leaderboard_frame.winfo_children():
@@ -171,20 +172,20 @@ class TimeGuessGame:
# --- Spaltenkonfiguration mit Gewichten für dynamische Breite ---
# Definieren Sie die relativen Breiten (Gewichte) der Spalten
column_weights = [1, 5, 3, 3, 3] # Name etwas breiter gemacht
column_weights = [1, 5, 3, 3, 3] # Name etwas breiter gemacht
headers = ["Rang", "Name", "Zielzeit (s)", "Gemessene Zeit (s)", "Abweichung (s)"]
# Konfiguriere die Spalten im scrollable_leaderboard_frame, damit sie sich anpassen
# Wichtig: Dies wirkt sich nur aus, wenn scrollable_leaderboard_frame
# die Breite hat, um die Gewichte anzuwenden (daher _on_canvas_configure)
for i, weight in enumerate(column_weights):
self.scrollable_leaderboard_frame.columnconfigure(i, weight=weight, uniform='leaderboard') # 'uniform' kann helfen
self.scrollable_leaderboard_frame.columnconfigure(i, weight=weight, uniform='leaderboard') # 'uniform' kann helfen
# --- Kopfzeile erstellen mit grid ---
for i, header in enumerate(headers):
lbl = tk.Label(self.scrollable_leaderboard_frame, text=header,
font=("Arial", 11, "bold"), relief=tk.RIDGE, padx=5, pady=2, bd=1) # Etwas kleiner, mit Rand
lbl.grid(row=0, column=i, sticky='nsew') # nsew füllt Zelle komplett
font=("Arial", 11, "bold"), relief=tk.RIDGE, padx=5, pady=2, bd=1) # Etwas kleiner, mit Rand
lbl.grid(row=0, column=i, sticky='nsew') # nsew füllt Zelle komplett
# --- Einträge in die Rangliste einfügen mit grid ---
for i, entry in enumerate(self.leaderboard):
@@ -193,28 +194,33 @@ class TimeGuessGame:
bg_color = "#f0f0f0" if i % 2 == 0 else "#ffffff"
# Zellen erstellen und platzieren
data_font = ("Arial", 10) # Kleinere Schrift für Daten
data_font = ("Arial", 10) # Kleinere Schrift für Daten
# Rang
lbl_rank = tk.Label(self.scrollable_leaderboard_frame, text=str(i + 1), bg=bg_color, padx=5, pady=2, font=data_font)
lbl_rank = tk.Label(self.scrollable_leaderboard_frame, text=str(i + 1), bg=bg_color, padx=5, pady=2,
font=data_font)
lbl_rank.grid(row=row_num, column=0, sticky='nsew')
# Name
lbl_name = tk.Label(self.scrollable_leaderboard_frame, text=entry['name'], bg=bg_color, anchor='w', padx=5, pady=2, font=data_font)
lbl_name = tk.Label(self.scrollable_leaderboard_frame, text=entry['name'], bg=bg_color, anchor='w', padx=5,
pady=2, font=data_font)
lbl_name.grid(row=row_num, column=1, sticky='nsew')
# Zielzeit
lbl_target = tk.Label(self.scrollable_leaderboard_frame, text=f"{entry['target_time'] / 1000:.3f}", bg=bg_color, padx=5, pady=2, font=data_font)
lbl_target = tk.Label(self.scrollable_leaderboard_frame, text=f"{entry['target_time'] / 1000:.3f}",
bg=bg_color, padx=5, pady=2, font=data_font)
lbl_target.grid(row=row_num, column=2, sticky='nsew')
# Gemessene Zeit
lbl_elapsed = tk.Label(self.scrollable_leaderboard_frame, text=f"{entry['elapsed_time'] / 1000:.3f}", bg=bg_color, padx=5, pady=2, font=data_font)
lbl_elapsed = tk.Label(self.scrollable_leaderboard_frame, text=f"{entry['elapsed_time'] / 1000:.3f}",
bg=bg_color, padx=5, pady=2, font=data_font)
lbl_elapsed.grid(row=row_num, column=3, sticky='nsew')
# Abweichung
deviation = abs(entry['deviation'] / 1000)
color = "green" if deviation < 0.5 else "orange" if deviation < 1.0 else "red"
lbl_dev = tk.Label(self.scrollable_leaderboard_frame, text=f"{deviation:.3f}", fg=color, bg=bg_color, padx=5, pady=2, font=data_font)
lbl_dev = tk.Label(self.scrollable_leaderboard_frame, text=f"{deviation:.3f}", fg=color, bg=bg_color,
padx=5, pady=2, font=data_font)
lbl_dev.grid(row=row_num, column=4, sticky='nsew')
# Wichtig: Nach dem Hinzufügen von Widgets und Konfigurieren der Spalten
@@ -224,12 +230,11 @@ class TimeGuessGame:
self.scrollable_leaderboard_frame.update_idletasks()
self.leaderboard_canvas.configure(scrollregion=self.leaderboard_canvas.bbox("all"))
# ... (Rest der Methoden: setup_connection, check_initial_connection, etc. bleiben unverändert) ...
def setup_connection(self):
if self.connected:
messagebox.showinfo("Info", "Bereits verbunden.")
return
messagebox.showinfo("Info", "Bereits verbunden.")
return
try:
ports = list(serial.tools.list_ports.comports())
@@ -238,7 +243,7 @@ class TimeGuessGame:
return
port_names = [p.device for p in ports]
port_info = [f"{p.device} - {p.description}" for p in ports] # Mehr Infos anzeigen
port_info = [f"{p.device} - {p.description}" for p in ports] # Mehr Infos anzeigen
if len(ports) == 1:
selected_port_device = ports[0].device
@@ -249,12 +254,12 @@ class TimeGuessGame:
f"Verfügbare Ports:\n" + "\n".join(port_info) + "\n\nBitte Port eingeben (z.B. COM3 oder /dev/ttyACM0):",
parent=self.root)
if not selected_port_str:
return # Benutzer hat abgebrochen
return # Benutzer hat abgebrochen
# Prüfen, ob der eingegebene Port gültig ist
if selected_port_str not in port_names:
messagebox.showerror("Fehler", f"Ungültiger Port: {selected_port_str}")
return
messagebox.showerror("Fehler", f"Ungültiger Port: {selected_port_str}")
return
selected_port_device = selected_port_str
# Verbindung herstellen
@@ -262,13 +267,13 @@ class TimeGuessGame:
self.serial_port.close()
self.serial_port = serial.Serial(selected_port_device, 9600, timeout=0.1)
self.root.after(2000, self.check_initial_connection) # Warte 2s und prüfe Verbindung
self.root.after(2000, self.check_initial_connection) # Warte 2s und prüfe Verbindung
except serial.SerialException as e:
messagebox.showerror("Verbindungsfehler", f"Konnte Port {selected_port_device} nicht öffnen:\n{e}")
self.connected = False
self.connection_label.config(text="Nicht verbunden", fg="red")
self.start_button.config(state=tk.DISABLED)
messagebox.showerror("Verbindungsfehler", f"Konnte Port {selected_port_device} nicht öffnen:\n{e}")
self.connected = False
self.connection_label.config(text="Nicht verbunden", fg="red")
self.start_button.config(state=tk.DISABLED)
except Exception as e:
messagebox.showerror("Verbindungsfehler", str(e))
self.connected = False
@@ -280,41 +285,40 @@ class TimeGuessGame:
# (Optional: Sende einen PING oder erwarte eine READY Nachricht)
try:
if self.serial_port and self.serial_port.is_open:
# Optional: Warte auf eine "READY" Nachricht vom Arduino
# self.serial_port.write(b"CHECK_READY\n") # Beispielbefehl
# Oder gehe einfach davon aus, dass es geklappt hat
self.connected = True
self.connection_label.config(text=f"Verbunden mit {self.serial_port.port}", fg="green")
self.start_button.config(state=tk.NORMAL)
self.instruction_label.config(text="Drücke 'Neues Spiel starten' oder den Taster") # Aktualisiert
# Optional: Warte auf eine "READY" Nachricht vom Arduino
# self.serial_port.write(b"CHECK_READY\n") # Beispielbefehl
# Oder gehe einfach davon aus, dass es geklappt hat
self.connected = True
self.connection_label.config(text=f"Verbunden mit {self.serial_port.port}", fg="green")
self.start_button.config(state=tk.NORMAL)
self.instruction_label.config(text="Drücke 'Neues Spiel starten' oder den Taster") # Aktualisiert
# Starte den Lese-Thread erst *nach* erfolgreicher Verbindung
if self.serial_thread is None or not self.serial_thread.is_alive():
self.serial_thread = threading.Thread(target=self.read_serial, daemon=True)
self.serial_thread.start()
# Starte den Lese-Thread erst *nach* erfolgreicher Verbindung
if self.serial_thread is None or not self.serial_thread.is_alive():
self.serial_thread = threading.Thread(target=self.read_serial, daemon=True)
self.serial_thread.start()
messagebox.showinfo("Verbindung", f"Erfolgreich mit {self.serial_port.port} verbunden!")
messagebox.showinfo("Verbindung", f"Erfolgreich mit {self.serial_port.port} verbunden!")
else:
# Dieser Fall sollte eigentlich nicht eintreten, wenn Serial() erfolgreich war
raise serial.SerialException("Port nicht mehr offen nach Wartezeit.")
# Dieser Fall sollte eigentlich nicht eintreten, wenn Serial() erfolgreich war
raise serial.SerialException("Port nicht mehr offen nach Wartezeit.")
except Exception as e:
port_name = self.serial_port.port if self.serial_port else "Unbekannt"
messagebox.showerror("Verbindungsfehler", f"Keine Antwort vom Arduino auf {port_name}:\n{e}")
self.disconnect_serial() # Verbindung sauber trennen
port_name = self.serial_port.port if self.serial_port else "Unbekannt"
messagebox.showerror("Verbindungsfehler", f"Keine Antwort vom Arduino auf {port_name}:\n{e}")
self.disconnect_serial() # Verbindung sauber trennen
def disconnect_serial(self):
"""Trennt die serielle Verbindung sauber."""
self.game_active = False # Spiel stoppen, falls aktiv
self.game_active = False # Spiel stoppen, falls aktiv
if self.serial_port and self.serial_port.is_open:
try:
self.serial_port.close()
except Exception as e:
print(f"Fehler beim Schließen des Ports: {e}")
self.serial_port = None
self.connected = False # Wichtig: Setze connected auf False
self.connected = False # Wichtig: Setze connected auf False
# UI Updates im Hauptthread sicherstellen
self.root.after(0, self._update_ui_disconnected)
print("Serielle Verbindung getrennt.")
@@ -342,7 +346,7 @@ class TimeGuessGame:
# Starte ein neues Spiel
print("Sende START_GAME an Arduino")
self.serial_port.write(b"START_GAME\n")
self.serial_port.flush() # Sicherstellen, dass Daten gesendet werden
self.serial_port.flush() # Sicherstellen, dass Daten gesendet werden
self.game_active = True
# UI zurücksetzen
@@ -351,7 +355,7 @@ class TimeGuessGame:
self.deviation_label.config(text="Abweichung: -")
self.status_label.config(text="Spiel wird vorbereitet...")
self.instruction_label.config(text="Warte auf Spielstart...")
self.deviation_label.config(fg="black") # Farbe zurücksetzen
self.deviation_label.config(fg="black") # Farbe zurücksetzen
# Deaktiviere Start-Button während des Spiels
self.start_button.config(state=tk.DISABLED)
@@ -362,8 +366,9 @@ class TimeGuessGame:
self.name_entry.delete(0, tk.END)
except serial.SerialException as e:
messagebox.showerror("Kommunikationsfehler", f"Fehler beim Senden an Arduino:\n{e}\nVerbindung wird getrennt.", parent=self.root)
self.disconnect_serial() # Bei Sendefehler Verbindung trennen
messagebox.showerror("Kommunikationsfehler",
f"Fehler beim Senden an Arduino:\n{e}\nVerbindung wird getrennt.", parent=self.root)
self.disconnect_serial() # Bei Sendefehler Verbindung trennen
except Exception as e:
messagebox.showerror("Fehler", f"Fehler beim Starten des Spiels: {e}", parent=self.root)
self.game_active = False
@@ -371,11 +376,10 @@ class TimeGuessGame:
if self.connected:
self.start_button.config(state=tk.NORMAL)
def read_serial(self):
print("Serial Read-Thread gestartet.")
buffer = ""
while self.connected: # Schleife läuft nur solange connected=True
while self.connected: # Schleife läuft nur solange connected=True
if self.serial_port and self.serial_port.is_open:
try:
# Daten lesen, wenn verfügbar
@@ -387,7 +391,7 @@ class TimeGuessGame:
# Verarbeite vollständige Zeilen im Puffer
while '\n' in buffer:
line, buffer = buffer.split('\n', 1)
line = line.strip() # Entferne Leerzeichen und ggf. \r
line = line.strip() # Entferne Leerzeichen und ggf. \r
if line:
print(f"Arduino: {line}") # Debug-Ausgabe
# Stelle sicher, dass UI-Updates im Hauptthread laufen
@@ -397,32 +401,30 @@ class TimeGuessGame:
print(f"Serieller Fehler im Lesethread: {e}")
# Bei Lesefehler Verbindung als verloren markieren
# Stelle sicher, dass dies im Hauptthread passiert
if self.connected: # Nur wenn wir dachten, wir wären verbunden
self.root.after(0, self.handle_connection_loss)
break # Thread beenden
if self.connected: # Nur wenn wir dachten, wir wären verbunden
self.root.after(0, self.handle_connection_loss)
break # Thread beenden
except Exception as e:
# Verhindert Absturz bei unerwarteten Dekodierungsfehlern etc.
print(f"Allgemeiner Fehler im Lesethread: {e}")
# Optional: Hier auch Verbindung trennen?
time.sleep(0.1) # Kurze Pause bei unerwartetem Fehler
time.sleep(0.1) # Kurze Pause bei unerwartetem Fehler
else:
# Wenn Port nicht mehr offen ist oder None, Thread beenden
print("Port nicht mehr offen oder nicht vorhanden. Read-Thread wird beendet.")
break # Beendet die while self.connected Schleife
# Wenn Port nicht mehr offen ist oder None, Thread beenden
print("Port nicht mehr offen oder nicht vorhanden. Read-Thread wird beendet.")
break # Beendet die while self.connected Schleife
time.sleep(0.05) # Kurze Pause, um CPU zu schonen
time.sleep(0.05) # Kurze Pause, um CPU zu schonen
print("Serial Read-Thread beendet.")
def handle_connection_loss(self):
"""Wird aufgerufen, wenn ein serieller Fehler auftritt (im Hauptthread)."""
if self.connected: # Nur handeln, wenn wir dachten, wir wären verbunden
# Verhindert mehrere Fehlermeldungen bei schnellen Fehlern
self.connected = False # Sofort auf False setzen
messagebox.showerror("Verbindungsfehler", "Verbindung zum Arduino verloren!", parent=self.root)
self.disconnect_serial() # Ruft UI-Updates etc. auf
if self.connected: # Nur handeln, wenn wir dachten, wir wären verbunden
# Verhindert mehrere Fehlermeldungen bei schnellen Fehlern
self.connected = False # Sofort auf False setzen
messagebox.showerror("Verbindungsfehler", "Verbindung zum Arduino verloren!", parent=self.root)
self.disconnect_serial() # Ruft UI-Updates etc. auf
def process_arduino_message(self, message):
# Diese Funktion wird jetzt über self.root.after() im Hauptthread aufgerufen
@@ -440,19 +442,22 @@ class TimeGuessGame:
'elapsed_time': 0,
'deviation': 0
}
self.target_time_label.config(text=f"Zielzeit: {target_time/1000:.1f} Sekunden")
self.status_label.config(text="Spiel läuft") # Status hier anpassen
self.instruction_label.config(text="Drücke Taster zum Starten...") # Erste Anweisung nach Zielzeit
self.target_time_label.config(text=f"Zielzeit: {target_time / 1000:.1f} Sekunden")
self.status_label.config(text="Spiel läuft") # Status hier anpassen
self.instruction_label.config(text="Drücke Taster zum Starten...") # Erste Anweisung nach Zielzeit
elif message == "WAITING_FOR_BUTTON":
self.instruction_label.config(
text="Drücke den Taster zum Starten der Zeitmessung")
self.status_label.config(text="Bereit zum Start") # Klarerer Status
self.instruction_label.config(
text="Drücke den Taster zum Starten der Zeitmessung")
self.status_label.config(text="Bereit zum Start") # Klarerer Status
elif message == "TIME_STARTED":
startsound = pygame.mixer.Sound("start.mp3")
pygame.mixer.Sound.play(startsound)
self.status_label.config(text="Zeitmessung läuft...")
self.instruction_label.config(
text="Drücke den Taster erneut zum Stoppen") # Verkürzt
text="Drücke den Taster erneut zum Stoppen") # Verkürzt
elif message.startswith("ELAPSED_TIME:"):
# Nur verarbeiten, wenn ein Spiel aktiv ist
@@ -460,7 +465,7 @@ class TimeGuessGame:
elapsed_time = int(message.split(":")[1].strip())
self.current_game['elapsed_time'] = elapsed_time
self.elapsed_time_label.config(
text=f"Deine Zeit: {elapsed_time/1000:.3f} Sekunden")
text=f"Deine Zeit: {elapsed_time / 1000:.3f} Sekunden")
elif message.startswith("DEVIATION:"):
# Nur verarbeiten, wenn ein Spiel aktiv ist
@@ -475,32 +480,40 @@ class TimeGuessGame:
color = "green" if deviation_abs_sec < 0.5 else "orange" if deviation_abs_sec < 1.0 else "red"
self.deviation_label.config(fg=color)
if deviation_abs_sec >= 10:
fail = pygame.mixer.Sound("fail.mp3")
pygame.mixer.Sound.play(fail)
elif deviation_abs_sec == 0:
winner = pygame.mixer.Sound("winner.mp3")
pygame.mixer.Sound.play(winner)
else:
fail = pygame.mixer.Sound("good.mp3")
pygame.mixer.Sound.play(fail)
elif message == "GAME_ENDED":
self.game_active = False # Wichtig: Spielstatus aktualisieren
self.game_active = False # Wichtig: Spielstatus aktualisieren
self.status_label.config(text="Spiel beendet")
self.instruction_label.config(
text="Trage Namen ein oder starte neu") # Verkürzt
if self.connected: # Nur aktivieren, wenn noch verbunden
self.start_button.config(state=tk.NORMAL)
self.submit_button.config(state=tk.NORMAL) # Buttons aktivieren
self.skip_button.config(state=tk.NORMAL)
text="Trage Namen ein oder starte neu") # Verkürzt
if self.connected: # Nur aktivieren, wenn noch verbunden
self.start_button.config(state=tk.NORMAL)
self.submit_button.config(state=tk.NORMAL) # Buttons aktivieren
self.skip_button.config(state=tk.NORMAL)
else:
# Sicherstellen, dass Buttons deaktiviert bleiben, wenn keine Verbindung
self.submit_button.config(state=tk.DISABLED)
self.skip_button.config(state=tk.DISABLED)
elif message == "PC_READY": # Arduino meldet Bereitschaft nach Neustart/Init
print("Arduino meldet PC_READY")
# Wenn wir verbunden sind oder versuchen zu verbinden, UI aktualisieren
if self.connected or (self.serial_port and self.serial_port.is_open):
self.status_label.config(text="Arduino bereit")
self.start_button.config(state=tk.NORMAL)
self.instruction_label.config(text="Drücke 'Neues Spiel starten'")
else:
# Wenn keine Verbindung (mehr) besteht, nur loggen
print("PC_READY empfangen, aber nicht verbunden.")
# Sicherstellen, dass Buttons deaktiviert bleiben, wenn keine Verbindung
self.submit_button.config(state=tk.DISABLED)
self.skip_button.config(state=tk.DISABLED)
elif message == "PC_READY": # Arduino meldet Bereitschaft nach Neustart/Init
print("Arduino meldet PC_READY")
# Wenn wir verbunden sind oder versuchen zu verbinden, UI aktualisieren
if self.connected or (self.serial_port and self.serial_port.is_open):
self.status_label.config(text="Arduino bereit")
self.start_button.config(state=tk.NORMAL)
self.instruction_label.config(text="Drücke 'Neues Spiel starten'")
else:
# Wenn keine Verbindung (mehr) besteht, nur loggen
print("PC_READY empfangen, aber nicht verbunden.")
# Handle andere unerwartete Nachrichten (optional)
# else:
@@ -511,10 +524,9 @@ class TimeGuessGame:
except IndexError as e:
print(f"Fehler beim Splitten der Nachricht '{message}': {e}")
except Exception as e:
# Catch-all für unerwartete Fehler während der Nachrichtenverarbeitung
import traceback
print(f"Unerwarteter Fehler beim Verarbeiten der Nachricht '{message}': {e}")
traceback.print_exc() # Gibt detaillierten Traceback aus
traceback.print_exc()
print(f"Unerwarteter Fehler bei der Nachrichtenverarbeitung: {e}")
def submit_score(self):
name = self.name_entry.get().strip()
@@ -644,8 +656,7 @@ class TimeGuessGame:
print("Tkinter-Fenster wird zerstört.")
self.root.destroy() # Tkinter-Fenster zerstören
if __name__ == "__main__":
root = tk.Tk()
app = TimeGuessGame(root)
game = TimeGuessGame(root)
root.mainloop()

BIN
good.mp3 Normal file

Binary file not shown.

BIN
start.mp3 Normal file

Binary file not shown.

BIN
starten.mp3 Normal file

Binary file not shown.

BIN
winner.mp3 Normal file

Binary file not shown.