# LoadingScene.gd # 负责驱动加载流程,更新UI,并在完成后切换到游戏主场景。 extends Control # --- 节点引用 --- @onready var progress_bar: ProgressBar = $MainContainer/LoadingProgressBar @onready var loading_label: Label = $MainContainer/LoadingLabel # --- 常量 --- const GAME_SCENE_PATH = "res://Entity/Level/GameScene.tscn" # 请确保这个路径是正确的! # --- 内部状态变量 --- var _current_action: String = "" var _save_data_to_process: Dictionary = {} var _target_animation_progress: float = 0.0 # 进度条动画的目标值 (用于20%-80%的平滑过渡) var _current_animation_progress: float = 0.0 # 进度条动画的当前值 var _animation_speed: float = 30.0 # 进度条动画速度 (百分比/秒),可以根据需要调整 var _initialization_started: bool = false # 标记核心初始化流程是否已开始 var _initialization_complete: bool = false # 标记核心初始化流程是否已完成 func _ready(): print("LoadingScene: Scene Ready.") # 1. 初始化UI _update_progress(0.0, "准备加载...") # 2. 从 LoadingContext 获取参数 if not ProjectSettings.has_setting("autoload/LoadingContext"): _handle_critical_error("LoadingContext Autoload 未配置!") return _current_action = LoadingContext.action_to_perform # 对存档数据进行深拷贝,以防万一LoadingContext中的原始数据被意外修改 _save_data_to_process = LoadingContext.save_data_for_loading.duplicate(true) # 3. 清空 LoadingContext (这是一个好习惯) LoadingContext.clear_context() # 验证获取到的action是否有效 if _current_action != "new_game" and _current_action != "load_game": _handle_critical_error("无效的加载指令: " + _current_action) return print("LoadingScene: Action to perform - ", _current_action) if _current_action == "load_game": print("LoadingScene: Save data keys to process - ", _save_data_to_process.keys()) # 4. 更新进度到阶段1 (10%) _update_progress(10.0, "加载参数读取完毕...") # 5. 连接 InitializationManager 的信号 # 使用 CONNECT_ONE_SHOT 确保信号只触发一次,处理后自动断开,避免重复处理或内存泄漏 if not ProjectSettings.has_setting("autoload/InitializationManager"): _handle_critical_error("InitializationManager Autoload 未配置!") return if _current_action == "new_game": if InitializationManager.is_connected("new_game_initialized", Callable(self, "_on_initialization_manager_finished")): printerr("LoadingScene: Warning - new_game_initialized signal already connected by this instance. This might indicate a logic error if _ready is called multiple times unexpectedly.") else: InitializationManager.new_game_initialized.connect(self._on_initialization_manager_finished, CONNECT_ONE_SHOT) print("LoadingScene: Connected to InitializationManager.new_game_initialized.") elif _current_action == "load_game": if InitializationManager.is_connected("game_loaded", Callable(self, "_on_initialization_manager_finished")): printerr("LoadingScene: Warning - game_loaded signal already connected by this instance.") else: InitializationManager.game_loaded.connect(self._on_initialization_manager_finished, CONNECT_ONE_SHOT) print("LoadingScene: Connected to InitializationManager.game_loaded.") # 6. 使用 call_deferred 延迟调用实际的初始化启动函数 # 这可以确保当前 _ready() 函数中的UI更新等操作完成后再开始耗时操作。 call_deferred("_start_actual_initialization") func _start_actual_initialization() -> void: print("LoadingScene: Starting actual initialization...") # 更新进度到阶段2 (20%) _update_progress(20.0, "开始初始化核心数据...") _initialization_started = true _current_animation_progress = 20.0 # 动画从20%开始 _target_animation_progress = 80.0 # 动画目标到80% var success: bool = false if _current_action == "new_game": success = InitializationManager.start_new_game_process() if not success: _handle_initialization_failure("新游戏流程启动失败 (InitializationManager.start_new_game_process 返回 false)。") elif _current_action == "load_game": if _save_data_to_process.is_empty() and _current_action == "load_game": # 这是一个潜在问题,如果我们要加载游戏,但没有存档数据 _handle_initialization_failure("加载游戏失败:没有提供有效的存档数据。") return success = InitializationManager.load_game_process(_save_data_to_process) if not success: _handle_initialization_failure("加载游戏流程启动失败 (InitializationManager.load_game_process 返回 false)。") if success: print("LoadingScene: Initialization process started via InitializationManager.") # 如果 success 为 false,_handle_initialization_failure 已经被调用 func _process(delta: float) -> void: # 如果核心初始化已开始且未完成,则驱动进度条动画 if _initialization_started and not _initialization_complete: if _current_animation_progress < _target_animation_progress: _current_animation_progress = move_toward(_current_animation_progress, _target_animation_progress, _animation_speed * delta) # 只更新进度条的值,不频繁更新文本,避免性能开销和视觉跳动 progress_bar.value = _current_animation_progress # (可选) 如果动画已达到80%但仍在等待信号,可以添加一个小的等待动画或文本提示 # else: # loading_label.text = "正在等待核心数据处理完成..." (确保只设置一次) # 当 InitializationManager 完成新游戏或加载游戏流程后,此函数被调用 func _on_initialization_manager_finished() -> void: # success 参数已移除,因为信号发出即代表成功 print("LoadingScene: Received signal from InitializationManager (initialization finished).") _initialization_complete = true # 确保动画进度至少达到目标,或者直接跳到90% _current_animation_progress = max(_current_animation_progress, _target_animation_progress) # 更新进度到阶段3 (90%) _update_progress(90.0, "核心数据准备完毕!") # 【增加延时】在切换到游戏场景之前 #print("LoadingScene: Adding a DEBUG delay before transitioning to GameScene...") #await get_tree().create_timer(3.0).timeout # <--- 增加3秒延时 (用于调试) #print("LoadingScene: DEBUG delay finished.") # 延迟切换到游戏场景 call_deferred("_transition_to_game_scene") func _transition_to_game_scene() -> void: print("LoadingScene: Preparing to transition to GameScene...") # 更新进度到阶段4 (100%) _update_progress(100.0, "正在进入游戏...") # (可选) 给用户一个非常短暂的时间看到100% # await get_tree().create_timer(0.1).timeout # 注意: 上面的 await 会使函数变成异步,如果后续有更多同步代码,需要注意。 # 对于简单的场景切换,直接调用通常没问题。 var err = get_tree().change_scene_to_file(GAME_SCENE_PATH) if err != OK: _handle_critical_error("切换到 GameScene 失败! 错误码: " + str(err) + "路径: " + GAME_SCENE_PATH) # 此时游戏可能处于一个无法恢复的状态,可以考虑显示一个永久的错误信息 # --- 辅助函数 --- func _update_progress(value: float, message: String = "") -> void: progress_bar.value = value if not message.is_empty(): # 为了避免过于频繁地更新Label内容导致潜在的性能问题或闪烁, # 我们可以只在关键阶段更新文本,或者确保文本内容确实改变了再更新。 # 这里我们假设在关键阶段更新文本是可以接受的。 loading_label.text = message # +" " + str(int(value)) + "%" # ProgressBar的show_percentage=true会自动显示百分比 print("LoadingScene: Progress updated - ", int(value), "% - ", message) func _handle_initialization_failure(error_message: String) -> void: printerr("LoadingScene: Initialization Failed - ", error_message) _initialization_started = false # 停止任何进行中的动画逻辑 _initialization_complete = true # 标记流程结束(虽然是失败的结束) # 更新UI以反映错误状态 progress_bar.value = progress_bar.min_value # 或者一个特定的错误值/样式 # 可以考虑给ProgressBar添加一个自定义主题,当发生错误时改变其颜色 # progress_bar.add_theme_stylebox_override("fill", preload("res://error_progress_bar_fill_style.tres")) loading_label.text = "错误: " + error_message + "\n请尝试返回主菜单或重启游戏。" # 在这里,可以考虑启用一个“返回主菜单”的按钮,或者其他用户可进行的操作。 # 例如: get_node("Path/To/RetryButton").disabled = false func _handle_critical_error(error_message: String) -> void: printerr("LoadingScene: CRITICAL ERROR - ", error_message) _initialization_started = false _initialization_complete = true # 阻止进一步操作 if progress_bar: progress_bar.value = 0 if loading_label: loading_label.text = "严重错误: " + error_message + "\n游戏可能无法继续。" # 对于严重错误,可能除了显示信息外做不了太多 # 可以禁用所有交互,或者尝试安全退出游戏 # get_tree().quit() # 如果错误非常严重