226 lines
10 KiB
GDScript
226 lines
10 KiB
GDScript
# GameState.gd
|
||
# Autoload Singleton
|
||
# 负责存储和管理核心游戏状态。
|
||
# 使用一个中央字典 (_state_data) 来存储所有状态,提高灵活性和可维护性。
|
||
# 状态的键名直接来源于初始化数据 (Init_Base.json) 或后续动态添加。
|
||
|
||
extends Node
|
||
|
||
# --- 状态信号 ---
|
||
|
||
# 当游戏状态通过 initialize_for_new_game 初始化完成时发出
|
||
signal state_initialized(initial_state: Dictionary)
|
||
|
||
# 当游戏状态通过 restore_state 从存档恢复完成时发出
|
||
signal state_restored(restored_state: Dictionary)
|
||
|
||
# 当任何状态值通过 set_value 发生改变时发出
|
||
signal state_value_changed(key: String, new_value)
|
||
|
||
# [兼容性信号] 当 "time" 状态值被设置或更新时发出 (保持与旧代码或特定UI的兼容)
|
||
signal date_changed(new_date: Dictionary)
|
||
|
||
# --- 内部状态变量 ---
|
||
# 核心状态字典,存储所有动态游戏数据
|
||
var _state_data: Dictionary = {}
|
||
# 注意:内部的 game_pause 和 is_on_task 变量已被移除,
|
||
# 相关状态现在存储在 _state_data["system_status"] 中。
|
||
|
||
# --- 状态初始化与恢复 ---
|
||
|
||
# 为新游戏初始化状态。
|
||
# 直接使用传入的 initial_settings 字典填充状态。
|
||
func initialize_for_new_game(initial_settings: Dictionary) -> void:
|
||
print("GameState: Initializing state directly from initial settings...")
|
||
|
||
# 使用深拷贝 (duplicate(true)),确保 GameState 拥有独立的数据副本
|
||
_state_data = initial_settings.duplicate(true)
|
||
|
||
# 在 _state_data 初始化后,调用 add_init_data 来填充 "task_info"
|
||
add_init_data() # 调用修改后的函数
|
||
print("GameState: State initialized. Data:", _state_data)
|
||
|
||
# 发出通用初始化完成信号,传递状态副本
|
||
emit_signal("state_initialized", _state_data.duplicate(true))
|
||
|
||
# [兼容性] 如果存在 "time" 键,则发出 date_changed 信号
|
||
if _state_data.has("time") and typeof(_state_data["time"]) == TYPE_DICTIONARY:
|
||
emit_signal("date_changed", _state_data["time"].duplicate(true))
|
||
|
||
# 从加载的数据恢复状态。
|
||
# 直接使用 loaded_data 覆盖当前状态。
|
||
func restore_state(loaded_data: Dictionary) -> void:
|
||
print("GameState: Restoring state from loaded data...")
|
||
|
||
# 同样建议使用深拷贝,虽然从存档加载的数据理论上已经是独立的
|
||
_state_data = loaded_data.duplicate(true)
|
||
|
||
print("GameState: State restored. Data:", _state_data)
|
||
|
||
# 发出通用恢复完成信号,传递状态副本
|
||
emit_signal("state_restored", _state_data.duplicate(true))
|
||
|
||
# [兼容性] 如果存在 "time" 键,则发出 date_changed 信号
|
||
if _state_data.has("time") and typeof(_state_data["time"]) == TYPE_DICTIONARY:
|
||
emit_signal("date_changed", _state_data["time"].duplicate(true))
|
||
|
||
# 获取需要保存到存档的状态。
|
||
# 直接返回核心状态字典的副本。
|
||
func get_savable_state() -> Dictionary:
|
||
print("GameState: Gathering savable state...")
|
||
# 返回深拷贝,确保存档系统拿到的是快照,不会意外修改当前状态
|
||
return _state_data.duplicate(true)
|
||
|
||
# --- 状态访问 (通用 Getter) ---
|
||
|
||
# 获取指定键 (key) 的状态值。
|
||
# 如果键不存在,返回提供的默认值 (default)。
|
||
func get_value(key: String, default = null):
|
||
# 使用字典的 get 方法,它能优雅地处理键不存在的情况
|
||
return _state_data.get(key, default)
|
||
|
||
# --- 状态修改 (通用 Setter) ---
|
||
|
||
# 设置指定键 (key) 的状态值。
|
||
# 如果值发生变化,会发出 state_value_changed 信号。
|
||
# 如果键是 "time",还会额外发出 date_changed 信号。
|
||
func set_value(key: String, value) -> void:
|
||
var old_value = _state_data.get(key)
|
||
# 只有当值确实发生改变时才执行更新和发信号,提高效率
|
||
# 注意:对于字典或数组等引用类型,这个比较是浅比较。
|
||
if old_value != value:
|
||
_state_data[key] = value
|
||
#print("GameState: Value changed - ", key, ": ", value)
|
||
|
||
# 发出通用值变化信号
|
||
emit_signal("state_value_changed", key, value)
|
||
|
||
# [兼容性] 如果更新的是 "time" 键,且值是字典,则发出 date_changed 信号
|
||
if key == "time" and typeof(value) == TYPE_DICTIONARY:
|
||
emit_signal("date_changed", value.duplicate(true)) # 发送新日期的副本
|
||
|
||
# --- 系统状态访问辅助函数 (新添加) ---
|
||
|
||
# 内部辅助函数:安全地获取 "system_status" 字典
|
||
# 返回一个字典的副本,如果原始数据无效或不存在,则返回包含默认值的字典
|
||
func _get_system_status_dict() -> Dictionary:
|
||
var status = get_value("system_status")
|
||
# 验证获取到的值是否为字典,如果不是或为 null,则返回默认结构
|
||
if typeof(status) != TYPE_DICTIONARY:
|
||
printerr("GameState: 'system_status' key missing or not a Dictionary in _state_data. Returning default.")
|
||
return {"game_pause": false, "is_on_task": false}
|
||
# 返回深拷贝以防止外部意外修改原始字典的引用(虽然 get_value 返回的通常是副本或基础类型)
|
||
return status.duplicate(true)
|
||
|
||
# 设置 "system_status" 中的特定键值 (game_pause 或 is_on_task)
|
||
# key: 要设置的键名 ("game_pause" 或 "is_on_task")
|
||
# value: 要设置的布尔值 (true 或 false)
|
||
func set_system_status_value(key: String, value: bool) -> void:
|
||
# 获取当前的 system_status 字典的副本
|
||
var current_status = _get_system_status_dict()
|
||
|
||
# 检查键是否是预期的 "game_pause" 或 "is_on_task"
|
||
if key == "game_pause" or key == "is_on_task":
|
||
# 只有当值实际改变时才更新,以避免不必要的 set_value 调用和信号发射
|
||
if current_status.get(key) != value:
|
||
current_status[key] = value
|
||
# 使用通用的 set_value 来更新整个 system_status 字典
|
||
# 这将触发 state_value_changed("system_status", new_dictionary) 信号
|
||
set_value("system_status", current_status)
|
||
print("GameState: Updated system_status -> ", key, " set to ", value)
|
||
# else: # 值未改变,无需操作
|
||
# print("GameState: system_status -> ", key, " already set to ", value)
|
||
else:
|
||
printerr("GameState: Invalid key '", key, "' provided to set_system_status_value. Expected 'game_pause' or 'is_on_task'.")
|
||
|
||
# 检查游戏是否暂停
|
||
# 返回: bool - true 如果游戏已暂停, false 否则
|
||
func is_game_paused() -> bool:
|
||
return _get_system_status_dict().get("game_pause", false)
|
||
|
||
# 检查是否处于任务中状态
|
||
# 返回: bool - true 如果正在进行任务, false 否则
|
||
func is_on_task_status() -> bool:
|
||
return _get_system_status_dict().get("is_on_task", false)
|
||
|
||
# 暂停游戏
|
||
func pause_game():
|
||
set_system_status_value("game_pause", true)
|
||
|
||
# 恢复游戏
|
||
func resume_game():
|
||
set_system_status_value("game_pause", false)
|
||
|
||
# --- 辅助函数:查找字典中第一个 enabled:true 的条目的键 ---
|
||
# data_dict: 期望是一个结构为 { "key1": {"enabled": bool, ...}, "key2": {...} } 的字典
|
||
# 返回: 第一个找到的 enabled 为 true 的条目的键名 (String),如果未找到则返回空字符串
|
||
func _find_first_enabled_key(data_dict: Dictionary) -> String:
|
||
if typeof(data_dict) != TYPE_DICTIONARY:
|
||
printerr("GameState (_find_first_enabled_key): Expected a Dictionary, got ", typeof(data_dict))
|
||
return ""
|
||
# GDScript 字典从 Godot 3.1 开始保持插入顺序,
|
||
# 因此迭代将遵循 JSON 中定义的顺序或它们被添加到字典中的顺序。
|
||
for key in data_dict:
|
||
var item = data_dict[key]
|
||
if typeof(item) == TYPE_DICTIONARY and item.has("enabled") and item["enabled"] == true:
|
||
return key # 返回第一个找到的键名
|
||
# print("GameState (_find_first_enabled_key): No enabled item found in dictionary with keys: ", data_dict.keys()) # 可选的调试信息
|
||
return "" # 如果没有找到 enabled:true 的条目
|
||
|
||
# --- 初始化 task_info ---
|
||
# MODIFIED: 此函数现在会从 _state_data["task_development"] 获取初始值
|
||
func add_init_data() -> void:
|
||
var initial_platform: String = ""
|
||
var initial_gameplay: String = ""
|
||
var initial_theme: String = ""
|
||
var initial_strategy: String = ""
|
||
var initial_product_focus_points: Dictionary = {}
|
||
|
||
# 确保 _state_data["task_development"] 存在并且是字典类型
|
||
if _state_data.has("task_development") and typeof(_state_data["task_development"]) == TYPE_DICTIONARY:
|
||
var task_dev_data = _state_data["task_development"]
|
||
|
||
# 获取平台初始值
|
||
if task_dev_data.has("platforms") and typeof(task_dev_data["platforms"]) == TYPE_DICTIONARY:
|
||
initial_platform = _find_first_enabled_key(task_dev_data["platforms"])
|
||
else:
|
||
printerr("GameState (add_init_data): 'task_development.platforms' is missing or not a Dictionary.")
|
||
|
||
# 获取玩法初始值
|
||
if task_dev_data.has("gameplays") and typeof(task_dev_data["gameplays"]) == TYPE_DICTIONARY:
|
||
initial_gameplay = _find_first_enabled_key(task_dev_data["gameplays"])
|
||
else:
|
||
printerr("GameState (add_init_data): 'task_development.gameplays' is missing or not a Dictionary.")
|
||
|
||
# 获取题材初始值
|
||
if task_dev_data.has("themes") and typeof(task_dev_data["themes"]) == TYPE_DICTIONARY:
|
||
initial_theme = _find_first_enabled_key(task_dev_data["themes"])
|
||
else:
|
||
printerr("GameState (add_init_data): 'task_development.themes' is missing or not a Dictionary.")
|
||
|
||
# 获取开发策略初始值
|
||
if task_dev_data.has("strategies") and typeof(task_dev_data["strategies"]) == TYPE_DICTIONARY:
|
||
initial_strategy = _find_first_enabled_key(task_dev_data["strategies"])
|
||
else:
|
||
printerr("GameState (add_init_data): 'task_development.strategies' is missing or not a Dictionary.")
|
||
|
||
# 获取产品侧重点初始值
|
||
if task_dev_data.has("product_focus_points") and typeof(task_dev_data["product_focus_points"]) == TYPE_DICTIONARY:
|
||
initial_product_focus_points = task_dev_data["product_focus_points"]
|
||
else:
|
||
printerr("GameState (add_init_data): 'task_development.product_focus_points' is missing or not a Dictionary.")
|
||
|
||
else:
|
||
printerr("GameState (add_init_data): 'task_development' key is missing in _state_data or is not a Dictionary.")
|
||
|
||
# 初始化 _state_data["task_info"]
|
||
_state_data["task_development_info"] = {
|
||
"平台": initial_platform,
|
||
"玩法": initial_gameplay,
|
||
"题材": initial_theme,
|
||
"开发策略": initial_strategy,
|
||
"预算": 0, # 保持原有的默认值
|
||
"产品侧重点": initial_product_focus_points,
|
||
#"关键环节负责人": [] # 保持原有的默认值
|
||
}
|