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.

55
game.py
View File

@@ -6,6 +6,7 @@ import os
import threading
import time
import serial.tools.list_ports # Import hinzugefügt
import pygame
class TimeGuessGame:
def __init__(self, root):
@@ -31,13 +32,14 @@ class TimeGuessGame:
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) ...
@@ -105,7 +107,6 @@ 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
@@ -114,7 +115,8 @@ class TimeGuessGame:
# --- 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.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 ---
@@ -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():
@@ -196,25 +197,30 @@ class TimeGuessGame:
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,7 +230,6 @@ 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:
@@ -304,7 +309,6 @@ class TimeGuessGame:
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
@@ -362,7 +366,8 @@ 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)
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)
@@ -371,7 +376,6 @@ class TimeGuessGame:
if self.connected:
self.start_button.config(state=tk.NORMAL)
def read_serial(self):
print("Serial Read-Thread gestartet.")
buffer = ""
@@ -414,7 +418,6 @@ class TimeGuessGame:
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
@@ -423,7 +426,6 @@ class TimeGuessGame:
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
if not self.connected and not message.startswith("PC_READY"):
@@ -450,6 +452,9 @@ class TimeGuessGame:
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
@@ -475,6 +480,16 @@ 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.status_label.config(text="Spiel beendet")
@@ -489,7 +504,6 @@ class TimeGuessGame:
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
@@ -501,7 +515,6 @@ class TimeGuessGame:
# Wenn keine Verbindung (mehr) besteht, nur loggen
print("PC_READY empfangen, aber nicht verbunden.")
# Handle andere unerwartete Nachrichten (optional)
# else:
# print(f"Unbekannte Nachricht vom Arduino: {message}")
@@ -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.