WIP: refactor boot order, re-introduce menu animations

This commit is contained in:
betalars 2026-06-03 14:40:20 +02:00
parent 8bdd48a365
commit b2fd6af9f4
4 changed files with 113 additions and 59 deletions

View File

@ -1,5 +1,4 @@
extends Node
func _ready() -> void:
func _enter_tree() -> void:
Main.normal_boot = true # Tell the system this is a normal game start

View File

@ -3,9 +3,24 @@ class_name GlobalState
#region configuration
signal settings_changed
var _settings_initialized
signal savegame_changed
var _settings_initialized: bool = false
var _savegame_initialized: bool = false
var all_ready: bool:
get():
return _settings_initialized and _savegame_initialized
func saves_loaded(save: SaveGame):
save_game = save
_savegame_initialized = true
var active_room: Room
var save_game: SaveGame:
set(save):
save_game = save
savegame_changed.emit()
signal environment_settings_changed
# FIXME find a better way to switch fonts and maybe emit the theme_changed signal!
@ -167,10 +182,10 @@ func load_user_settings():
file.close()
var parsed: Dictionary = JSON.parse_string(raw_json)
for kategory in parsed.values():
for key in kategory.keys():
for kategory in parsed.keys():
for key in parsed[kategory].keys():
if key in self:
set(key, parsed[key])
set(key, parsed[kategory][key])
else:
if OS.has_feature("macos"):
@ -224,15 +239,14 @@ func save_settings():
var file := FileAccess.open(user_settings_path, FileAccess.WRITE)
file.store_string(JSON.stringify(out_dict))
file.close()
_settings_initialized = true
settings_changed.emit()
func _ready():
load_user_settings()
await get_tree().process_frame
music_volume = music_volume
#region focus handling (called staging to avoid name colisions)
# CAUTION: scene_reference directly accesses stage list to play sequences.

View File

@ -1,50 +1,49 @@
extends Node
extends Control
var normal_boot : bool = false
@onready var menu_animation: AnimationNodeStateMachinePlayback = %MenuAnimationTree.get("parameters/playback")
@export_file(".tscn") var youth_room_path: String
@export_file(".tscn") var transition_room_path: String
@export_file(".tscn") var adulthood_room_path: String
@export_file(".tscn") var ending_path: String
@onready var curtain: Curtain = %Curtain
@onready var curtain: Panel = %Curtain
@onready var credits_roll: Control = %CreditsRoll
@onready var main_menu: MainMenu = %MainMenu
@onready var pause_menu: PauseMenu = %PauseMenu
@onready var room_paths := {
State.rooms.NULL: youth_room_path, # Maybe Draven story?
State.rooms.YOUTH: youth_room_path,
State.rooms.TRANSITION: transition_room_path,
State.rooms.ADULTHOOD: adulthood_room_path,
State.rooms.ENDING: ending_path
Room.ids.NULL: youth_room_path, # Maybe Draven story?
Room.ids.YOUTH: youth_room_path,
Room.ids.TRANSITION: transition_room_path,
Room.ids.ADULTHOOD: adulthood_room_path,
Room.ids.ENDING: ending_path
}
enum AppState {BOOT, MENU, PLAY, PAUSE, CREDITS}
enum AppState {INIT, LOADING, MENU, PLAY, PAUSE, CREDITS}
var state: AppState = AppState.BOOT:
var state: AppState = AppState.INIT:
set(value):
state = value
print("main.gd: app_state changing to: %s" % str(state))
match state:
AppState.BOOT:
credits_roll.hide()
main_menu.hide()
pause_menu.hide()
match value:
AppState.INIT:
pass
AppState.LOADING:
%MenuAnimationTree["parameters/conditions/loading_done"] = false
AppState.MENU:
credits_roll.hide()
pause_menu.hide()
menu_animation.travel("loading_menu")
await main_menu.execute()
AppState.PLAY:
pass
menu_animation.travel("start_game")
await_ui_clear()
hide()
AppState.PAUSE:
credits_roll.hide()
main_menu.hide()
pause_menu.appear()
menu_animation.travel("reveal_pause_menu")
AppState.CREDITS:
main_menu.hide()
pause_menu.hide()
credits_roll.play()
menu_animation.travel("credits_roll")
state = value
func _enter_tree() -> void:
print("main.gd: _enter_tree()")
@ -53,51 +52,80 @@ func _ready() -> void:
print("main.gd: _ready()")
main_menu.continue_button.pressed.connect(func(): state = AppState.PLAY)
main_menu.credits_button.pressed.connect(func(): state = AppState.CREDITS)
#TODO: Load the last savegame(?)
await %Loading.stop()
#await get_tree().process_frame
await await_boot_completed()
if normal_boot:
print("main.gd: normal boot (loading last save and showing main menu)")
state = AppState.MENU
call_deferred("start_menu")
else:
print("main.gd: direct boot (hiding menus and entering main loop)")
state = AppState.PLAY
func start_menu():
if Steam.resume_from_steamdeck():
start_game()
initialise_room(State.save_game.current_room)
state = AppState.MENU
func start_game(save: SaveGame) -> void:
func await_boot_completed():
print("main.gd: Awaiting Boot Completion ...")
while not State.all_ready:
await get_tree().process_frame
print("main.gd: Boot Completed.")
func await_ui_clear():
print("main.gd: Awaiting Menu Clear ...")
while not menu_animation.get_current_node() == "start_game":
await get_tree().process_frame
print("main.gd: Menu Cleared.")
func start_game(save: SaveGame = State.save_game) -> void:
print("main.gd: play_game()")
var room_path := room_paths.get(save.current_room, youth_room_path) as String
initialise_room(save.current_room)
State.active_room.play()
state = AppState.PLAY
while room_path:
await _load_room(room_path)
room_path = await State.room.play()
# Ending? Roll credits?
func is_game_active() -> bool:
return state == AppState.PLAY or state == AppState.PAUSE
func initialise_room(room_id: Room.ids):
if State.active_room:
if State.active_room.id == room_id:
return
else:
menu_animation.travel("change_savegame")
_load_room(room_paths.get(room_id, youth_room_path) as String)
func _load_room(scene_path: String) -> void:
await curtain.close()
%Loading.play()
if State.room:
State.room.unload()
State.room.queue_free()
State.room = null
ResourceLoader.load_threaded_request(scene_path, "PackedScene", true)
await get_tree().create_timer(0.1).timeout
if State.active_room:
State.active_room.unload()
State.active_room.queue_free()
State.active_room = null
while true:
await get_tree().process_frame
var load_state := ResourceLoader.load_threaded_get_status(scene_path)
match load_state:
ResourceLoader.THREAD_LOAD_LOADED:
var next_scene := ResourceLoader.load_threaded_get(scene_path) as PackedScene
State.room = next_scene.instantiate() as Room
%Stage.add_child(State.room)
State.active_room = next_scene.instantiate() as Room
%Stage.add_child(State.active_room)
await get_tree().process_frame
%Loading.stop()
%MenuAnimationTree["parameters/conditions/loading_done"] = true
return
ResourceLoader.THREAD_LOAD_FAILED:
push_error("Failed to load room.")
@ -109,7 +137,10 @@ func _load_room(scene_path: String) -> void:
var last_mode := DisplayServer.WINDOW_MODE_WINDOWED
func _unhandled_input(event: InputEvent) -> void:
#if event.is_action_type(): print_debug("Unhandled Input", event)
#if event.is_actionxxx_type(): print_debug("Unhandled Input", event)
if event.is_action_pressed("ui_pause") and state == AppState.PLAY:
state = AppState.PAUSE
if not Engine.is_editor_hint():
if event.is_action_pressed("toggle_fullscreen"):

View File

@ -19,12 +19,14 @@ func _validate_property(property: Dictionary) -> void:
var _tween: Tween = null
func _ready() -> void:
_load_games()
hide()
set_process_input(false)
back_button.pressed.connect(cancel)
func _ensure_directory() -> void:
var dir := DirAccess.open(State.user_saves_path)
@ -49,8 +51,7 @@ func _load_games():
# Skip invalid/empty saves
if save != null and not save.is_empty:
saves.append(save)
_sort_saves()
State.saves_loaded(get_most_recent_save())
_rebuild_buttons()
@ -69,6 +70,7 @@ func _get_slot_number(save: SaveGame) -> int:
# Find this save's position in the creation-order list
return saves_by_creation.find(save) + 1
func _rebuild_buttons() -> void:
save_buttons = []
for child in list_container.get_children():
@ -93,6 +95,7 @@ func _rebuild_buttons() -> void:
func _on_game_picked(id: int) -> void:
_picked.emit(saves[id])
func _on_delete_requested(id: int) -> void:
var save_to_delete := saves[id]
var save_path := save_to_delete.file_name
@ -116,23 +119,28 @@ func _on_delete_requested(id: int) -> void:
var focus_index := mini(id, save_buttons.size() - 1)
save_buttons[focus_index].grab_focus()
func get_most_recent_save() -> SaveGame:
_sort_saves()
return saves[0] if saves.size() > 0 else SaveGame.new()
func has_more_saves() -> bool:
for save in saves:
if save != State.save_game:
return true
return false
func _gui_input(event: InputEvent) -> void:
if event.is_action_pressed("ui_cancel"):
cancel()
func cancel()->void:
_picked.emit(State.save_game)
# This function is called when the user us supposed to choose a slot to load or create a new game.
func pick_save_slot() -> SaveGame:
await open()
@ -140,6 +148,7 @@ func pick_save_slot() -> SaveGame:
await close()
return result
# TODO: ugh, godot tweens are the wurst
func open() -> void:
show()
@ -156,6 +165,7 @@ func open() -> void:
_tween.tween_property(self, "modulate", Color.WHITE, 0.5)
await _tween.finished
func close() -> void:
if _tween != null:
_tween.kill()