extends Control ## Einstieg: hält den Spielstand und wechselt zwischen den Bildschirmen. var profile: Profile var screen: Control var save_path: String = Profile.SAVE_PATH var sfx: Sfx var net: Net func _ready() -> void: _map_gamepad() theme = Style.make_theme() var bg := Style.Backdrop.new() bg.set_anchors_preset(Control.PRESET_FULL_RECT) bg.mouse_filter = Control.MOUSE_FILTER_IGNORE add_child(bg) sfx = Sfx.new() add_child(sfx) # Fester Pfad /root/Net: Netzwerkaufrufe werden über den Knotenpfad zugestellt, # der bei Host und Mitspielern gleich sein muss. net = Net.new() net.name = "Net" get_tree().root.add_child.call_deferred(net) profile = Profile.load_or_new(save_path) apply_settings() show_screen(MenuScreen.new()) func apply_settings() -> void: sfx.set_volume(profile.settings.volume) sfx.set_music_volume(profile.settings.music) set_language(profile.settings.language) Style.font_scale = 1.2 if profile.settings.get("big_font", false) else 1.0 theme = Style.make_theme() ## Neues Profil: Sammlung und Fortschritt werden verworfen. func reset_profile() -> void: profile = Profile.starter() clear_battle_save() save() apply_settings() func set_language(code: String) -> void: TranslationServer.set_locale(code) func show_screen(s: Control) -> void: if screen != null: screen.queue_free() screen = s s.app = self s.set_anchors_preset(Control.PRESET_FULL_RECT) add_child(s) if pad_mode: focus_first_button.call_deferred() var pad_mode := false # zuletzt Gamepad benutzt: Fokusrahmen sichtbar, Steuerkreuz wechselt Knöpfe ## Gamepad in Menüs: erster Tastendruck setzt den Fokus, Maus nimmt ihn wieder weg. func _input(event: InputEvent) -> void: if event is InputEventJoypadButton or (event is InputEventJoypadMotion and absf(event.axis_value) > 0.5): if not pad_mode: pad_mode = true if get_viewport().gui_get_focus_owner() == null: focus_first_button() elif event is InputEventMouseMotion and pad_mode: pad_mode = false get_viewport().gui_release_focus() ## Gamepad-Tasten für die Menünavigation: A bestätigt, B bricht ab (falls nicht schon zugeordnet). func _map_gamepad() -> void: for pair in [["ui_accept", JOY_BUTTON_A], ["ui_cancel", JOY_BUTTON_B]]: var action: String = pair[0] if not InputMap.has_action(action): InputMap.add_action(action) if not InputMap.action_get_events(action).any(func(e): return e is InputEventJoypadButton): var ev := InputEventJoypadButton.new() ev.button_index = pair[1] InputMap.action_add_event(action, ev) func focus_first_button() -> void: if screen == null or screen is BattleScreen: return var b := _first_button(screen) if b != null: b.grab_focus() func _first_button(node: Node) -> Button: for c in node.get_children(): if c is Button and not c.disabled and c.is_visible_in_tree(): return c var found := _first_button(c) if found != null: return found return null func save() -> void: profile.save(save_path) ## Datei für einen unterbrochenen Kampf (neben dem Spielstand). func battle_save_path() -> String: return save_path.get_basename() + "_kampf.json" func clear_battle_save() -> void: if FileAccess.file_exists(battle_save_path()): DirAccess.remove_absolute(ProjectSettings.globalize_path(battle_save_path())) func _exit_tree() -> void: if net != null and net.is_inside_tree(): net.leave() net.queue_free()