Added Soundeffects
This commit is contained in:
BIN
_start.mp3
Normal file
BIN
_start.mp3
Normal file
Binary file not shown.
59
game.py
59
game.py
@@ -6,6 +6,7 @@ import os
|
|||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import serial.tools.list_ports # Import hinzugefügt
|
import serial.tools.list_ports # Import hinzugefügt
|
||||||
|
import pygame
|
||||||
|
|
||||||
class TimeGuessGame:
|
class TimeGuessGame:
|
||||||
def __init__(self, root):
|
def __init__(self, root):
|
||||||
@@ -31,13 +32,14 @@ class TimeGuessGame:
|
|||||||
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()
|
self.create_ui()
|
||||||
|
|
||||||
|
pygame.mixer.init()
|
||||||
|
|
||||||
# Verbindung nicht automatisch beim Start herstellen
|
# Verbindung nicht automatisch beim Start herstellen
|
||||||
# Serielle Kommunikation wird in setup_connection gestartet
|
# Serielle Kommunikation wird in setup_connection gestartet
|
||||||
|
|
||||||
# Protokoll für das Schließen des Fensters
|
# Protokoll für das Schließen des Fensters
|
||||||
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
|
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
|
||||||
|
|
||||||
|
|
||||||
def create_ui(self):
|
def create_ui(self):
|
||||||
# ... (Restlicher Code von create_ui bleibt gleich bis zum Ranglisten-Teil) ...
|
# ... (Restlicher Code von create_ui bleibt gleich bis zum Ranglisten-Teil) ...
|
||||||
|
|
||||||
@@ -105,7 +107,6 @@ class TimeGuessGame:
|
|||||||
bg="#9E9E9E", fg="white")
|
bg="#9E9E9E", fg="white")
|
||||||
self.skip_button.pack(side=tk.LEFT, padx=5)
|
self.skip_button.pack(side=tk.LEFT, padx=5)
|
||||||
|
|
||||||
|
|
||||||
# --- Frame für Rangliste (Container) ---
|
# --- Frame für Rangliste (Container) ---
|
||||||
leaderboard_outer_frame = tk.Frame(self.root, padx=10, pady=10)
|
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
|
||||||
@@ -114,7 +115,8 @@ class TimeGuessGame:
|
|||||||
|
|
||||||
# --- Canvas und Scrollbar für die Rangliste ---
|
# --- Canvas und Scrollbar für die Rangliste ---
|
||||||
self.leaderboard_canvas = tk.Canvas(leaderboard_outer_frame)
|
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
|
self.scrollable_leaderboard_frame = tk.Frame(self.leaderboard_canvas) # Frame *innerhalb* des Canvas
|
||||||
|
|
||||||
# --- Änderung 1: ID speichern und Bindung an 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"))
|
self.leaderboard_canvas.configure(scrollregion=self.leaderboard_canvas.bbox("all"))
|
||||||
# --- Ende Änderung 2 ---
|
# --- Ende Änderung 2 ---
|
||||||
|
|
||||||
|
|
||||||
def update_leaderboard_display(self):
|
def update_leaderboard_display(self):
|
||||||
# Bestehende Einträge im scrollbaren Frame löschen
|
# Bestehende Einträge im scrollbaren Frame löschen
|
||||||
for widget in self.scrollable_leaderboard_frame.winfo_children():
|
for widget in self.scrollable_leaderboard_frame.winfo_children():
|
||||||
@@ -196,25 +197,30 @@ class TimeGuessGame:
|
|||||||
data_font = ("Arial", 10) # Kleinere Schrift für Daten
|
data_font = ("Arial", 10) # Kleinere Schrift für Daten
|
||||||
|
|
||||||
# Rang
|
# 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')
|
lbl_rank.grid(row=row_num, column=0, sticky='nsew')
|
||||||
|
|
||||||
# Name
|
# 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')
|
lbl_name.grid(row=row_num, column=1, sticky='nsew')
|
||||||
|
|
||||||
# Zielzeit
|
# 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')
|
lbl_target.grid(row=row_num, column=2, sticky='nsew')
|
||||||
|
|
||||||
# Gemessene Zeit
|
# 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')
|
lbl_elapsed.grid(row=row_num, column=3, sticky='nsew')
|
||||||
|
|
||||||
# Abweichung
|
# Abweichung
|
||||||
deviation = abs(entry['deviation'] / 1000)
|
deviation = abs(entry['deviation'] / 1000)
|
||||||
color = "green" if deviation < 0.5 else "orange" if deviation < 1.0 else "red"
|
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')
|
lbl_dev.grid(row=row_num, column=4, sticky='nsew')
|
||||||
|
|
||||||
# Wichtig: Nach dem Hinzufügen von Widgets und Konfigurieren der Spalten
|
# Wichtig: Nach dem Hinzufügen von Widgets und Konfigurieren der Spalten
|
||||||
@@ -224,7 +230,6 @@ class TimeGuessGame:
|
|||||||
self.scrollable_leaderboard_frame.update_idletasks()
|
self.scrollable_leaderboard_frame.update_idletasks()
|
||||||
self.leaderboard_canvas.configure(scrollregion=self.leaderboard_canvas.bbox("all"))
|
self.leaderboard_canvas.configure(scrollregion=self.leaderboard_canvas.bbox("all"))
|
||||||
|
|
||||||
|
|
||||||
# ... (Rest der Methoden: setup_connection, check_initial_connection, etc. bleiben unverändert) ...
|
# ... (Rest der Methoden: setup_connection, check_initial_connection, etc. bleiben unverändert) ...
|
||||||
def setup_connection(self):
|
def setup_connection(self):
|
||||||
if self.connected:
|
if self.connected:
|
||||||
@@ -304,7 +309,6 @@ class TimeGuessGame:
|
|||||||
messagebox.showerror("Verbindungsfehler", f"Keine Antwort vom Arduino auf {port_name}:\n{e}")
|
messagebox.showerror("Verbindungsfehler", f"Keine Antwort vom Arduino auf {port_name}:\n{e}")
|
||||||
self.disconnect_serial() # Verbindung sauber trennen
|
self.disconnect_serial() # Verbindung sauber trennen
|
||||||
|
|
||||||
|
|
||||||
def disconnect_serial(self):
|
def disconnect_serial(self):
|
||||||
"""Trennt die serielle Verbindung sauber."""
|
"""Trennt die serielle Verbindung sauber."""
|
||||||
self.game_active = False # Spiel stoppen, falls aktiv
|
self.game_active = False # Spiel stoppen, falls aktiv
|
||||||
@@ -362,7 +366,8 @@ class TimeGuessGame:
|
|||||||
self.name_entry.delete(0, tk.END)
|
self.name_entry.delete(0, tk.END)
|
||||||
|
|
||||||
except serial.SerialException as e:
|
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
|
self.disconnect_serial() # Bei Sendefehler Verbindung trennen
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
messagebox.showerror("Fehler", f"Fehler beim Starten des Spiels: {e}", parent=self.root)
|
messagebox.showerror("Fehler", f"Fehler beim Starten des Spiels: {e}", parent=self.root)
|
||||||
@@ -371,7 +376,6 @@ class TimeGuessGame:
|
|||||||
if self.connected:
|
if self.connected:
|
||||||
self.start_button.config(state=tk.NORMAL)
|
self.start_button.config(state=tk.NORMAL)
|
||||||
|
|
||||||
|
|
||||||
def read_serial(self):
|
def read_serial(self):
|
||||||
print("Serial Read-Thread gestartet.")
|
print("Serial Read-Thread gestartet.")
|
||||||
buffer = ""
|
buffer = ""
|
||||||
@@ -414,7 +418,6 @@ class TimeGuessGame:
|
|||||||
|
|
||||||
print("Serial Read-Thread beendet.")
|
print("Serial Read-Thread beendet.")
|
||||||
|
|
||||||
|
|
||||||
def handle_connection_loss(self):
|
def handle_connection_loss(self):
|
||||||
"""Wird aufgerufen, wenn ein serieller Fehler auftritt (im Hauptthread)."""
|
"""Wird aufgerufen, wenn ein serieller Fehler auftritt (im Hauptthread)."""
|
||||||
if self.connected: # Nur handeln, wenn wir dachten, wir wären verbunden
|
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)
|
messagebox.showerror("Verbindungsfehler", "Verbindung zum Arduino verloren!", parent=self.root)
|
||||||
self.disconnect_serial() # Ruft UI-Updates etc. auf
|
self.disconnect_serial() # Ruft UI-Updates etc. auf
|
||||||
|
|
||||||
|
|
||||||
def process_arduino_message(self, message):
|
def process_arduino_message(self, message):
|
||||||
# Diese Funktion wird jetzt über self.root.after() im Hauptthread aufgerufen
|
# Diese Funktion wird jetzt über self.root.after() im Hauptthread aufgerufen
|
||||||
if not self.connected and not message.startswith("PC_READY"):
|
if not self.connected and not message.startswith("PC_READY"):
|
||||||
@@ -440,7 +442,7 @@ class TimeGuessGame:
|
|||||||
'elapsed_time': 0,
|
'elapsed_time': 0,
|
||||||
'deviation': 0
|
'deviation': 0
|
||||||
}
|
}
|
||||||
self.target_time_label.config(text=f"Zielzeit: {target_time/1000:.1f} Sekunden")
|
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.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.instruction_label.config(text="Drücke Taster zum Starten...") # Erste Anweisung nach Zielzeit
|
||||||
|
|
||||||
@@ -450,6 +452,9 @@ class TimeGuessGame:
|
|||||||
self.status_label.config(text="Bereit zum Start") # Klarerer Status
|
self.status_label.config(text="Bereit zum Start") # Klarerer Status
|
||||||
|
|
||||||
elif message == "TIME_STARTED":
|
elif message == "TIME_STARTED":
|
||||||
|
startsound = pygame.mixer.Sound("start.mp3")
|
||||||
|
pygame.mixer.Sound.play(startsound)
|
||||||
|
|
||||||
self.status_label.config(text="Zeitmessung läuft...")
|
self.status_label.config(text="Zeitmessung läuft...")
|
||||||
self.instruction_label.config(
|
self.instruction_label.config(
|
||||||
text="Drücke den Taster erneut zum Stoppen") # Verkürzt
|
text="Drücke den Taster erneut zum Stoppen") # Verkürzt
|
||||||
@@ -460,7 +465,7 @@ class TimeGuessGame:
|
|||||||
elapsed_time = int(message.split(":")[1].strip())
|
elapsed_time = int(message.split(":")[1].strip())
|
||||||
self.current_game['elapsed_time'] = elapsed_time
|
self.current_game['elapsed_time'] = elapsed_time
|
||||||
self.elapsed_time_label.config(
|
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:"):
|
elif message.startswith("DEVIATION:"):
|
||||||
# Nur verarbeiten, wenn ein Spiel aktiv ist
|
# Nur verarbeiten, wenn ein Spiel aktiv ist
|
||||||
@@ -475,6 +480,16 @@ class TimeGuessGame:
|
|||||||
color = "green" if deviation_abs_sec < 0.5 else "orange" if deviation_abs_sec < 1.0 else "red"
|
color = "green" if deviation_abs_sec < 0.5 else "orange" if deviation_abs_sec < 1.0 else "red"
|
||||||
self.deviation_label.config(fg=color)
|
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":
|
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.status_label.config(text="Spiel beendet")
|
||||||
@@ -489,7 +504,6 @@ class TimeGuessGame:
|
|||||||
self.submit_button.config(state=tk.DISABLED)
|
self.submit_button.config(state=tk.DISABLED)
|
||||||
self.skip_button.config(state=tk.DISABLED)
|
self.skip_button.config(state=tk.DISABLED)
|
||||||
|
|
||||||
|
|
||||||
elif message == "PC_READY": # Arduino meldet Bereitschaft nach Neustart/Init
|
elif message == "PC_READY": # Arduino meldet Bereitschaft nach Neustart/Init
|
||||||
print("Arduino meldet PC_READY")
|
print("Arduino meldet PC_READY")
|
||||||
# Wenn wir verbunden sind oder versuchen zu verbinden, UI aktualisieren
|
# Wenn wir verbunden sind oder versuchen zu verbinden, UI aktualisieren
|
||||||
@@ -501,7 +515,6 @@ class TimeGuessGame:
|
|||||||
# Wenn keine Verbindung (mehr) besteht, nur loggen
|
# Wenn keine Verbindung (mehr) besteht, nur loggen
|
||||||
print("PC_READY empfangen, aber nicht verbunden.")
|
print("PC_READY empfangen, aber nicht verbunden.")
|
||||||
|
|
||||||
|
|
||||||
# Handle andere unerwartete Nachrichten (optional)
|
# Handle andere unerwartete Nachrichten (optional)
|
||||||
# else:
|
# else:
|
||||||
# print(f"Unbekannte Nachricht vom Arduino: {message}")
|
# print(f"Unbekannte Nachricht vom Arduino: {message}")
|
||||||
@@ -511,10 +524,9 @@ class TimeGuessGame:
|
|||||||
except IndexError as e:
|
except IndexError as e:
|
||||||
print(f"Fehler beim Splitten der Nachricht '{message}': {e}")
|
print(f"Fehler beim Splitten der Nachricht '{message}': {e}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Catch-all für unerwartete Fehler während der Nachrichtenverarbeitung
|
|
||||||
import traceback
|
import traceback
|
||||||
print(f"Unerwarteter Fehler beim Verarbeiten der Nachricht '{message}': {e}")
|
traceback.print_exc()
|
||||||
traceback.print_exc() # Gibt detaillierten Traceback aus
|
print(f"Unerwarteter Fehler bei der Nachrichtenverarbeitung: {e}")
|
||||||
|
|
||||||
def submit_score(self):
|
def submit_score(self):
|
||||||
name = self.name_entry.get().strip()
|
name = self.name_entry.get().strip()
|
||||||
@@ -644,8 +656,7 @@ class TimeGuessGame:
|
|||||||
print("Tkinter-Fenster wird zerstört.")
|
print("Tkinter-Fenster wird zerstört.")
|
||||||
self.root.destroy() # Tkinter-Fenster zerstören
|
self.root.destroy() # Tkinter-Fenster zerstören
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
root = tk.Tk()
|
root = tk.Tk()
|
||||||
app = TimeGuessGame(root)
|
game = TimeGuessGame(root)
|
||||||
root.mainloop()
|
root.mainloop()
|
||||||
BIN
starten.mp3
Normal file
BIN
starten.mp3
Normal file
Binary file not shown.
BIN
winner.mp3
Normal file
BIN
winner.mp3
Normal file
Binary file not shown.
Reference in New Issue
Block a user