vrp-gruppe-sechs/quad-splash/game_manager.gd

317 lines
9.4 KiB
GDScript

extends Node
## GameManager - Globaler Singleton für Spielverwaltung
## Kompatibel mit XR Tools 4 Staging System
## WICHTIG: Als AutoLoad hinzufügen unter Project Settings > AutoLoad
## Name: GameManager, Path: res://scripts/game_manager.gd
# === SIGNALS ===
signal score_changed(new_score: int)
signal level_completed(level_name: String, score: int, time: float)
signal game_state_changed(new_state: GameState)
signal high_score_updated(new_high_score: int)
# === ENUMS ===
enum GameState {
MENU, # Im Hauptmenü
LOADING, # Level wird geladen
PLAYING, # Spiel läuft
PAUSED, # Spiel pausiert
LEVEL_COMPLETE, # Level abgeschlossen
GAME_OVER # Spiel beendet
}
# === PERSISTENTE DATEN ===
const SAVE_FILE_PATH = "user://savegame.save"
# Spieler-Fortschritt
var total_score: int = 0
var high_score: int = 0
var completed_levels: Array[String] = []
var player_preferences: Dictionary = {}
# Aktuelle Session-Daten
var current_level: String = ""
var current_level_score: int = 0
var current_state: GameState = GameState.MENU
var level_start_time: float = 0.0
var level_elapsed_time: float = 0.0
var is_timer_running: bool = false
# Level-Konfiguration
var level_list: Array[String] = [
"res://scenes/levels/level_01.tscn",
"res://scenes/levels/level_02.tscn",
"res://scenes/levels/level_03.tscn"
]
var current_level_index: int = 0
# === INITIALISIERUNG ===
func _ready() -> void:
print("[GameManager] Initialisierung gestartet")
load_game()
print("[GameManager] Bereit - High Score: ", high_score)
func _process(delta: float) -> void:
if is_timer_running:
level_elapsed_time += delta
# === LEVEL MANAGEMENT ===
func start_level(level_path: String = "") -> void:
"""Startet ein neues Level"""
# Wenn kein Pfad angegeben, verwende aktuellen Index
if level_path.is_empty():
if current_level_index >= level_list.size():
print("[GameManager] Alle Level abgeschlossen!")
end_game()
return
level_path = level_list[current_level_index]
current_level = level_path
current_level_score = 0
level_start_time = Time.get_ticks_msec() / 1000.0
level_elapsed_time = 0.0
is_timer_running = true
change_state(GameState.LOADING)
print("[GameManager] Starte Level: ", level_path)
# Level über XR Tools Staging System laden
load_scene_via_staging(level_path)
func load_scene_via_staging(scene_path: String, spawn_point = null) -> void:
"""Lädt eine Szene über das XR Tools Staging System"""
# Finde XRToolsSceneBase in der Szenen-Hierarchie
var scene_base = find_scene_base()
if scene_base and scene_base.has_method("load_scene"):
if spawn_point:
scene_base.load_scene(scene_path, spawn_point)
else:
scene_base.load_scene(scene_path)
change_state(GameState.PLAYING)
else:
push_error("[GameManager] XRToolsSceneBase nicht gefunden! Staging System nicht verfügbar.")
# Fallback für Tests ohne XR
if Engine.is_editor_hint() == false:
get_tree().change_scene_to_file(scene_path)
change_state(GameState.PLAYING)
func find_scene_base() -> Node:
"""Findet die XRToolsSceneBase Instanz in der Szene"""
# Versuche über XRTools Helper-Funktion
if XRTools and XRTools.has_method("find_xr_ancestor"):
var scene_base = XRTools.find_xr_ancestor(self, "*", "XRToolsSceneBase")
if scene_base:
return scene_base
# Fallback: Durchsuche Szenenbaum
return find_node_by_class(get_tree().root, "XRToolsSceneBase")
func find_node_by_class(node: Node, class_name: String) -> Node:
"""Rekursive Suche nach Node mit bestimmter Klasse"""
if node.get_class() == class_name or node.get_script() and str(node.get_script()).contains(class_name):
return node
for child in node.get_children():
var result = find_node_by_class(child, class_name)
if result:
return result
return null
func complete_level() -> void:
"""Level wurde erfolgreich abgeschlossen"""
is_timer_running = false
# Bonus für schnelle Zeit berechnen
var time_bonus = calculate_time_bonus(level_elapsed_time)
var final_score = current_level_score + time_bonus
# Zum Gesamtscore hinzufügen
add_score(final_score)
# Level als abgeschlossen markieren
if not completed_levels.has(current_level):
completed_levels.append(current_level)
print("[GameManager] Level abgeschlossen! Score: ", final_score, " Zeit: ", level_elapsed_time, "s")
level_completed.emit(current_level, final_score, level_elapsed_time)
change_state(GameState.LEVEL_COMPLETE)
# Speichern
save_game()
# Nach kurzer Verzögerung nächstes Level laden
await get_tree().create_timer(3.0).timeout
next_level()
func next_level() -> void:
"""Lädt das nächste Level"""
current_level_index += 1
start_level()
func restart_level() -> void:
"""Startet das aktuelle Level neu"""
start_level(current_level)
func return_to_menu() -> void:
"""Kehrt zum Hauptmenü zurück"""
is_timer_running = false
change_state(GameState.MENU)
# Lade die Eingangsszene mit dem Hauptmenü
load_scene_via_staging("res://scenes/Level_Base.tscn")
func end_game() -> void:
"""Beendet das Spiel"""
is_timer_running = false
change_state(GameState.GAME_OVER)
save_game()
print("[GameManager] Spiel beendet. Finaler Score: ", total_score)
# === SCORE MANAGEMENT ===
func add_score(points: int) -> void:
"""Fügt Punkte zum Score hinzu"""
current_level_score += points
total_score += points
score_changed.emit(total_score)
# High Score Update
if total_score > high_score:
high_score = total_score
high_score_updated.emit(high_score)
print("[GameManager] Neuer High Score: ", high_score)
func calculate_time_bonus(time_seconds: float) -> int:
"""Berechnet Zeitbonus basierend auf Levelzeit"""
# Beispiel: Je schneller, desto mehr Bonus
# Maximum 1000 Punkte bei unter 30 Sekunden
var bonus = max(0, 1000 - int(time_seconds * 10))
return bonus
func reset_score() -> void:
"""Setzt den Score zurück"""
total_score = 0
current_level_score = 0
score_changed.emit(total_score)
# === STATE MANAGEMENT ===
func change_state(new_state: GameState) -> void:
"""Ändert den Spielzustand"""
if current_state != new_state:
current_state = new_state
game_state_changed.emit(new_state)
print("[GameManager] State geändert zu: ", GameState.keys()[new_state])
func get_state() -> GameState:
"""Gibt den aktuellen Spielzustand zurück"""
return current_state
func pause_game() -> void:
"""Pausiert das Spiel"""
if current_state == GameState.PLAYING:
is_timer_running = false
get_tree().paused = true
change_state(GameState.PAUSED)
func resume_game() -> void:
"""Setzt das Spiel fort"""
if current_state == GameState.PAUSED:
is_timer_running = true
get_tree().paused = false
change_state(GameState.PLAYING)
# === TIMER FUNCTIONS ===
func get_level_time() -> float:
"""Gibt die aktuelle Levelzeit zurück"""
return level_elapsed_time
func stop_timer() -> void:
"""Stoppt den Timer"""
is_timer_running = false
func start_timer() -> void:
"""Startet den Timer"""
is_timer_running = true
if level_start_time == 0.0:
level_start_time = Time.get_ticks_msec() / 1000.0
# === PERSISTIERUNG ===
func save_game() -> void:
"""Speichert den Spielfortschritt"""
var save_data = {
"high_score": high_score,
"total_score": total_score,
"completed_levels": completed_levels,
"current_level_index": current_level_index,
"player_preferences": player_preferences,
"version": "1.0"
}
var file = FileAccess.open(SAVE_FILE_PATH, FileAccess.WRITE)
if file:
file.store_var(save_data)
file.close()
print("[GameManager] Spiel gespeichert: ", SAVE_FILE_PATH)
else:
push_error("[GameManager] Fehler beim Speichern: ", FileAccess.get_open_error())
func load_game() -> void:
"""Lädt den Spielfortschritt"""
if not FileAccess.file_exists(SAVE_FILE_PATH):
print("[GameManager] Keine Speicherdatei gefunden - Verwende Standardwerte")
return
var file = FileAccess.open(SAVE_FILE_PATH, FileAccess.READ)
if file:
var save_data = file.get_var()
file.close()
if save_data is Dictionary:
high_score = save_data.get("high_score", 0)
total_score = save_data.get("total_score", 0)
completed_levels = save_data.get("completed_levels", [])
current_level_index = save_data.get("current_level_index", 0)
player_preferences = save_data.get("player_preferences", {})
print("[GameManager] Spiel geladen - High Score: ", high_score)
else:
push_error("[GameManager] Ungültiges Speicherformat")
else:
push_error("[GameManager] Fehler beim Laden: ", FileAccess.get_open_error())
func delete_save() -> void:
"""Löscht die Speicherdatei"""
if FileAccess.file_exists(SAVE_FILE_PATH):
DirAccess.remove_absolute(SAVE_FILE_PATH)
print("[GameManager] Speicherdatei gelöscht")
# Werte zurücksetzen
high_score = 0
total_score = 0
completed_levels.clear()
current_level_index = 0
player_preferences.clear()
# === UTILITY FUNCTIONS ===
func format_time(seconds: float) -> String:
"""Formatiert Zeit in MM:SS Format"""
var minutes = int(seconds) / 60
var secs = int(seconds) % 60
return "%02d:%02d" % [minutes, secs]
func get_level_name(level_path: String) -> String:
"""Extrahiert den Level-Namen aus dem Pfad"""
return level_path.get_file().get_basename()
# === DEBUG FUNCTIONS ===
func print_stats() -> void:
"""Gibt Spielstatistiken aus"""
print("=== GAME STATS ===")
print("Total Score: ", total_score)
print("High Score: ", high_score)
print("Current Level: ", get_level_name(current_level))
print("State: ", GameState.keys()[current_state])
print("Completed Levels: ", completed_levels.size())
print("==================")