Compare commits
2 Commits
60b415039c
...
c58b1f8ed8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c58b1f8ed8 | ||
|
|
3bb02fcde6 |
@ -30,13 +30,14 @@ var _state_data: Dictionary = {}
|
||||
|
||||
# 为新游戏初始化状态。
|
||||
# 直接使用传入的 initial_settings 字典填充状态。
|
||||
# 这个函数无需修改,因为它已经正确处理了包含 "system_status" 的 _state_data。
|
||||
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)
|
||||
|
||||
# 发出通用初始化完成信号,传递状态副本
|
||||
@ -48,7 +49,6 @@ func initialize_for_new_game(initial_settings: Dictionary) -> void:
|
||||
|
||||
# 从加载的数据恢复状态。
|
||||
# 直接使用 loaded_data 覆盖当前状态。
|
||||
# 这个函数无需修改,因为它已经正确处理了包含 "system_status" 的 _state_data。
|
||||
func restore_state(loaded_data: Dictionary) -> void:
|
||||
print("GameState: Restoring state from loaded data...")
|
||||
|
||||
@ -66,7 +66,6 @@ func restore_state(loaded_data: Dictionary) -> void:
|
||||
|
||||
# 获取需要保存到存档的状态。
|
||||
# 直接返回核心状态字典的副本。
|
||||
# 这个函数无需修改,因为它返回的是完整的 _state_data。
|
||||
func get_savable_state() -> Dictionary:
|
||||
print("GameState: Gathering savable state...")
|
||||
# 返回深拷贝,确保存档系统拿到的是快照,不会意外修改当前状态
|
||||
@ -138,23 +137,90 @@ func set_system_status_value(key: String, value: bool) -> void:
|
||||
# 检查游戏是否暂停
|
||||
# 返回: bool - true 如果游戏已暂停, false 否则
|
||||
func is_game_paused() -> bool:
|
||||
# 直接从 _state_data 中读取,通过辅助函数获取字典并访问键值
|
||||
# 使用 .get() 并提供默认值 false,增加健壮性
|
||||
return _get_system_status_dict().get("game_pause", false)
|
||||
|
||||
# 检查是否处于任务中状态
|
||||
# 返回: bool - true 如果正在进行任务, false 否则
|
||||
func is_on_task_status() -> bool:
|
||||
# 直接从 _state_data 中读取
|
||||
# 使用 .get() 并提供默认值 false,增加健壮性
|
||||
return _get_system_status_dict().get("is_on_task", false)
|
||||
|
||||
# 暂停游戏
|
||||
func pause_game():
|
||||
# 调用新的辅助函数来修改 _state_data 中的 "game_pause" 值
|
||||
set_system_status_value("game_pause", true)
|
||||
|
||||
# 恢复游戏
|
||||
func resume_game():
|
||||
# 调用新的辅助函数来修改 _state_data 中的 "game_pause" 值
|
||||
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_info"] = {
|
||||
"平台": initial_platform,
|
||||
"玩法": initial_gameplay,
|
||||
"题材": initial_theme,
|
||||
"开发策略": initial_strategy,
|
||||
"预算": 0, # 保持原有的默认值
|
||||
"产品侧重点": initial_product_focus_points,
|
||||
#"关键环节负责人": [] # 保持原有的默认值
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
* **新游戏:** 确保 `InitialDataManager` 数据加载完成 -> 调用 `InitialDataManager` 获取初始数据 (`settings_data`, `task_dev_data`, `npc_initial_data`) -> **调用 `_build_initial_state` 方法,根据获取的数据构建注入 `GameState` 的初始状态字典。此方法会:**
|
||||
* **合并基础设置 (`Init_Base.json`) 到状态字典的顶层。**
|
||||
* **处理任务开发相关数据 (`task_development.json`),提取其中需要动态追踪的状态(如平台的 `enabled`, `Market_share`;玩法/主题的 `enabled`, `Experience`;策略的 `enabled`;产品侧重点的完整结构),并将这些动态状态组织在一个名为 `"task_development"` 的子字典内,再将该子字典存入主状态字典。**
|
||||
* **处理 NPC 数据 (`npc.json`),将从 `npc_initial_data` 中获取的 NPC 定义(通常是 `npc_defs["npc"]` 部分)存入主状态字典的 `"npcs"` 键下。**
|
||||
* **处理 NPC 数据 (`npc.json`),将从 `npc_initial_data` 中获取的 NPC 定义(通常是 `npc_defs["npc"]` 部分,即 `npc.json` 文件中 "npc" 键对应的值)存入主状态字典的 `"npcs"` 键下。**
|
||||
* **载入存档:** **接收**由外部(例如存档选择 UI,它会调用 `SaveLoadManager.load_game`)加载并传入的存档数据字典。
|
||||
* **数据注入:**
|
||||
* **新游戏:** 将构建好的初始状态字典传递给 `GameState.initialize_for_new_game()`。
|
||||
@ -113,14 +113,14 @@
|
||||
### 核心职责 (Responsibilities)
|
||||
* **状态存储:** 内部维护一个核心字典 (`_state_data`),用于存储所有动态游戏状态的 Key-Value 对。
|
||||
* **通用状态访问:** 提供通用的 `set_value`, `get_value` 接口。
|
||||
* **状态初始化:** 提供 `initialize_for_new_game` 方法,使用初始设置数据填充状态字典,完成后发出 `state_initialized` 信号。
|
||||
* **状态初始化:** 提供 `initialize_for_new_game` 方法,使用初始设置数据填充状态字典,**并在此过程中调用内部方法(如 `add_init_data`)根据已填充的 `_state_data` 的一部分(例如 `"task_development"`)来进一步初始化其他状态数据(例如 `"task_info"`),** 完成后发出 `state_initialized` 信号。
|
||||
* **状态恢复与通知:** 提供 `restore_state` 方法用于接收并覆盖整个状态字典,完成后发出 `state_restored` 信号。
|
||||
* **存档数据提供:** 提供 `get_savable_state` 方法,返回内部状态字典的**深拷贝**副本,供 `SaveLoadManager` 使用。
|
||||
* **系统状态管理:** 通过内部的 `"system_status"` 字典(存储在 `_state_data["system_status"]`)管理如游戏暂停 (`game_pause`)、是否在任务中 (`is_on_task`) 等状态。提供方法来修改和查询这些特定状态。
|
||||
|
||||
### **对外接口 (Public API / Generic State Access)**
|
||||
|
||||
* `initialize_for_new_game(initial_settings: Dictionary) -> void`: **(供 InitializationManager 调用)** 使用 `initial_settings` 字典(进行深拷贝)来初始化内部的 `_state_data`。完成后发出 `state_initialized` 信号。
|
||||
* `initialize_for_new_game(initial_settings: Dictionary) -> void`: **(供 InitializationManager 调用)** 使用 `initial_settings` 字典(进行深拷贝)来初始化内部的 `_state_data`。**随后,会调用一个内部函数 (`add_init_data`),该函数读取 `_state_data` 中已存在的 `"task_development"` 数据,并用其来填充 `_state_data` 中的 `"task_info"` 键。** 完成后发出 `state_initialized` 信号。
|
||||
* `restore_state(loaded_data: Dictionary) -> void`: **(供 InitializationManager 调用)** 用 `loaded_data` 字典(进行深拷贝)**完全替换**内部的 `_state_data` 字典,然后发出 `state_restored` 信号。
|
||||
* `get_savable_state() -> Dictionary`: **(供 SaveLoadManager 调用)** 返回内部 `_state_data` 字典的**深拷贝** (`duplicate(true)`),用于存档,确保返回的是当前状态的一个独立快照。
|
||||
* `get_value(key: String, default = null) -> Variant`: 根据 `key` 从内部字典检索 `value`。如果 `key` 不存在,返回 `default` 值。
|
||||
@ -177,7 +177,4 @@
|
||||
* **输入 (Load):** `user://` 目录下的 JSON 文件。
|
||||
* **输出 (Load):** 解析后的 `game_state` 字典 (返回给调用者) 或 `null`。
|
||||
|
||||
### 配置 (Configuration)
|
||||
* 必须配置为 Godot 的 Autoload (单例)。
|
||||
|
||||
---
|
||||
|
||||
235
UI/[文档]UI开发框架说明.md
Normal file
235
UI/[文档]UI开发框架说明.md
Normal file
@ -0,0 +1,235 @@
|
||||
# UI 框架开发指南
|
||||
|
||||
**1. 简介**
|
||||
|
||||
本文档旨在为使用本 UI 框架的开发人员提供指导,帮助大家快速、规范地创建和管理游戏中的 UI 页面及工作流。本框架的核心是通过一个中央控制器 (`MainController`) 来管理各个 UI 页面 (`UIPage` 的派生类) 的显示、隐藏、导航以及数据共享。
|
||||
|
||||
核心组件:
|
||||
* **`main_controller.gd` (`MainController`)**: 全局 UI 工作流管理器。负责页面切换、维护工作流共享数据、处理工作流的开始与结束。
|
||||
* **`ui_base.gd` (`UIPage`)**: 所有具体 UI 页面的基类。提供了基础的导航逻辑、与 `MainController` 的通信接口以及页面生命周期管理。
|
||||
* **具体页面脚本 **: 继承自 `UIPage`,实现特定页面的内容展示和交互逻辑。
|
||||
|
||||
**2. 核心概念**
|
||||
|
||||
* **MainController (`main_controller.gd`)**
|
||||
* **职责**:
|
||||
* 管理当前激活的 UI 页面。
|
||||
* 根据 `UIPage` 发出的请求进行页面切换,并处理页面间的过渡逻辑(如隐藏旧页面、显示新页面及其父页面)。
|
||||
* 持有一个 `shared_workflow_data` 字典,用于在工作流中的不同页面间共享数据。此数据可在启动时从全局状态管理(例如 `GameState`)初始化。
|
||||
* 定义工作流的起点 (`initial_page_path`)。
|
||||
* 发出工作流结束信号 (`workflow_confirmed`, `workflow_cancelled`)。
|
||||
* **导出变量**:
|
||||
* `initial_page_path: NodePath`: 指向工作流初始页面的节点路径。
|
||||
* `gamestate_data_key: String`: 用于从全局状态管理(如 `GameState`)中读取/初始化 `shared_workflow_data` 的键名。
|
||||
* **启动与显示工作流**:
|
||||
* `_ready()`: 控制器准备就绪时,会尝试从 `GameState` 使用 `gamestate_data_key` 加载共享数据 (如果 `gamestate_data_key` 已配置)。然后,它会遍历其直接子节点:如果是 `UIPage` 类型,则隐藏它们并连接必要的信号。接着,对于每个作为 `UIPage` 的直接子节点,它还会遍历该 `UIPage` 的直接子节点(即 `MainController` 的孙子节点):如果这些孙子节点也是 `UIPage` 类型,则同样会隐藏它们并连接信号。**注意**:`show_up()` 方法需要被外部调用以启动工作流,它不会在 `_ready()` 中自动调用。
|
||||
* `show_up()`: 此方法用于显示和启动 UI 工作流。它首先会调用 `GameState.pause_game()` 来暂停游戏,然后重新从 `GameState` 使用 `gamestate_data_key` 获取最新的共享数据,并根据 `initial_page_path` 找到初始页面,然后调用 `start_new_workflow` 并将获取的数据传递给新工作流。如果初始页面路径无效或未找到对应节点,则控制器自身将保持不可见。
|
||||
* `start_new_workflow(start_page: UIPage, initial_data: Dictionary = {})` 方法启动一个新的 UI 工作流。它会复制 `initial_data` (通常是从 `GameState` 或 `show_up()` 传递的) 到 `shared_workflow_data`,隐藏所有非起始的顶级页面及其子 `UIPage`(具体来说,它遍历 `MainController` 的直接子节点,如果子节点是 `UIPage` 且不是 `start_page`,则隐藏它;然后遍历该子节点的子节点,如果是 `UIPage`,也隐藏它),然后调用 `_switch_to_page` 切换到指定的 `start_page` 并使控制器可见。
|
||||
* **共享数据**:
|
||||
* `get_shared_data(key: String, default = null)`: 从共享数据字典中获取值。
|
||||
* `set_shared_data(key: String, value)`: 设置共享数据字典中的值。
|
||||
* **页面切换逻辑 (`_switch_to_page`)**:
|
||||
* **处理前一页面**:
|
||||
* 如果存在前一个活动页面 (`previous_page`),控制器会决定是否隐藏它。默认行为是隐藏 (`should_hide_previous_page = true`)。控制器会按以下顺序检查 `previous_page` 的 `hide_on_next` 行为:
|
||||
1. 尝试通过元数据 `previous_page.get_meta("hide_on_next")` 获取布尔值。
|
||||
2. 如果元数据不存在,并且 `previous_page` 具有名为 "about_to_show" 的信号 (这是一个特定条件,可能用于特定页面类型),则会尝试直接访问 `previous_page.hide_on_next` 脚本变量(`UIPage` 基类将 `hide_on_next` 定义为一个导出变量,默认为 `true`)。如果此时 `hide_on_next` 属性未找到,会打印错误并默认隐藏。
|
||||
3. 如果上述条件都不满足,则使用默认行为(隐藏)。
|
||||
* 如果最终决定需要隐藏前一页面,则调用 `previous_page.hide_page()`。
|
||||
* **父页面清理**: 如果前一页面 (`previous_page`) 是一个子页面(即其 `parent_page_node_path` 已配置),并且导航的目标页面 (`target_page`) 满足以下两个条件:1) `target_page` 不是 `previous_page` 的逻辑父页面 (`old_page_parent_node`),并且 2) `target_page` 的场景树父节点不是 `old_page_parent_node`(即 `target_page` 不是 `old_page_parent_node` 的直接子节点,意味着它不是 `previous_page` 在该逻辑父页面下的兄弟页面),则前一子页面的逻辑父页面 (`old_page_parent_node`) 将被隐藏,以清理不再相关的上下文。
|
||||
* **激活新页面**: 将 `current_active_page` 更新为目标页面。调用 `current_active_page.show_page()`(此方法在 `UIPage` 中仅负责设置 `visible = true`),然后关键地,`MainController` 直接调用 `current_active_page._on_page_activated()` 来确保页面的激活逻辑被执行。
|
||||
* **确保新子页面的父页面可见并已激活**: 如果新的当前活动页面 (`current_active_page`) 是一个子页面(配置了 `parent_page_node_path`),控制器会确保其在 `parent_page_node_path` 中指定的父 `UIPage` 节点 (`new_page_parent_node`) 也是可见且(如果需要)已激活的。
|
||||
* 如果该父页面 (`new_page_parent_node`) 之前不可见,则会调用其 `show_page()` 方法(使其可见),然后调用其 `_on_page_activated()` 方法(激活它)。
|
||||
* 如果父页面已经可见,则仍会调用其 `show_page()` 方法(尽管它可能仅确认可见性)。
|
||||
* **信号处理器**:
|
||||
* `_on_page_navigate_requested(target_page_node: Control)`: 当 `UIPage` 发出 `navigate_requested` 信号时调用。如果 `target_page_node` 是 `UIPage` 的实例,则负责执行到目标页面的切换(通过 `_switch_to_page`)。否则会打印错误。
|
||||
* `_on_page_workflow_end_requested(is_confirm_and_trigger_action: bool)`: 当 `UIPage` 发出 `workflow_end_requested` 信号时调用。
|
||||
* 如果 `is_confirm_and_trigger_action` 为 `true`,则发出 `workflow_confirmed` 信号并携带最终的 `shared_workflow_data`。
|
||||
* 否则,发出 `workflow_cancelled` 信号。
|
||||
* 之后,如果存在当前活动页面 (`current_active_page`),则调用其 `hide_page()`。如果当前活动页面配置了 `parent_page_node_path`,其对应的父页面也会被调用 `hide_page()`。
|
||||
* `current_active_page` 被设为 `null`。
|
||||
* 当前的 `shared_workflow_data` 会使用 `GameState.set_value(gamestate_data_key, shared_workflow_data)` 保存到全局状态。注意:`MainController` 内部的 `shared_workflow_data` 不会被清空。随后调用 `GameState.resume_game()` 来恢复游戏。
|
||||
* 最后,`MainController` 自身设置为不可见。
|
||||
|
||||
* **UIPage (`ui_base.gd`)**
|
||||
* **页面基类**: 所有具体的 UI 页面场景的根节点所附加的脚本都应继承自此类。
|
||||
* **初始化 (`_ready`)**:
|
||||
* `UIPage` 在其 `_ready` 方法中会尝试获取 `MainController` 的引用。它会检查其 `owner` 节点是否为 `MainController`。这是通过判断 `owner` 是否存在并且是否拥有一个名为 `get_shared_data` 的方法来实现的。如果条件满足,则将 `owner` 赋值给 `main_controller` 变量。
|
||||
* **输入处理 (`_input`)**:
|
||||
* 如果页面可见,它会监听鼠标右键点击事件 (`MOUSE_BUTTON_RIGHT`)。当右键被按下时,会尝试执行 `go_back()` 操作,并调用 `get_viewport().set_input_as_handled()` 来消费该输入事件。
|
||||
* **导航功能**:
|
||||
* `go_next()`: 尝试导航到 `next_ui_node_path` 配置的页面。若路径有效且目标节点是 `Control` 类型,则发出 `navigate_requested` 信号。若路径为空或目标节点无效(或不是 `Control`),则打印错误并发出 `workflow_end_requested` 信号并传递 `true` (表示确认结束)。
|
||||
* `go_back()`: 优先尝试导航到 `back_ui_node_path` 配置的页面。如果 `back_ui_node_path` 为空,则尝试导航到 `parent_page_node_path` 配置的父页面。若选中的路径有效且目标节点是 `Control` 类型,则发出 `navigate_requested` 信号。若两个路径均为空或目标节点无效(或不是 `Control`),则打印错误并发出 `workflow_end_requested` 信号并传递 `false` (表示取消结束)。
|
||||
* `go_to_child_page(child_page_node: Control)`: 导航到指定的子页面。此方法会进行检查:
|
||||
* 确保 `child_page_node` 不为 null。
|
||||
* 确保 `child_page_node` 不是当前页面的祖先节点 (使用 `_is_ancestor_of` 辅助函数判断,以防止循环导航到父级)。
|
||||
* 确保 `child_page_node` 是一个 `Control` 节点。
|
||||
如果检查通过,则发出 `navigate_requested` 信号。否则打印错误。
|
||||
* **Inspector 配置项**:
|
||||
* `next_ui_node_path: NodePath`: “下一个”页面节点的路径。
|
||||
* `back_ui_node_path: NodePath`: “上一个”页面节点的路径。
|
||||
* `parent_page_node_path: NodePath`: (主要用于子页面)父页面节点的路径,当 `back_ui_node_path` 为空时,子页面会尝试通过 `go_back()` 返回此父页面。
|
||||
* `hide_on_next: bool`: (默认值: `true`) 如果此属性为 `true`,当通过 `go_next()` 方法成功导航到 `next_ui_node_path` 所配置的页面时,`MainController` 在处理前一页面(即当前页面)时,会倾向于隐藏当前页面(具体逻辑见 `MainController._switch_to_page` 中对 `hide_on_next` 的处理)。如果设置为 `false`,当前页面在导航后有更大可能性保持可见。
|
||||
* **生命周期方法 (可覆写)**:
|
||||
* `show_page()`: 公开方法,用于显示页面。它**仅**负责将节点的 `visible` 属性设为 `true` (如果之前是 `false`)。**此方法本身不调用 `_on_page_activated()`**。
|
||||
* `hide_page()`: 公开方法,用于隐藏页面。**仅当页面之前是可见状态时**,此方法会先调用 `_on_page_deactivated()`,然后再将节点的 `visible` 属性设为 `false`。
|
||||
* `_on_page_activated()`: 当页面被 `MainController` 激活时调用(通常在 `_switch_to_page` 期间)。用于加载数据、更新UI、启动动画等。基类实现会打印一条日志,如 `UIPage activated: [PageName]`。
|
||||
* `_on_page_deactivated()`: 当页面通过 `hide_page()` **即将变为不可见** (即其 `visible` 属性从 `true` 变为 `false`) 之前调用。用于保存临时状态、清理资源或停止动画等。如果页面已不可见,再次调用 `hide_page()` 不会重复触发此方法。基类实现会打印一条日志,如 `UIPage deactivated: [PageName]`。
|
||||
* **与 MainController 通信**:
|
||||
* 信号 `navigate_requested(target_page_node: Control)`: 请求 `MainController` 切换到目标页面。
|
||||
* 信号 `workflow_end_requested(is_confirm_and_trigger_action: bool)`: 请求 `MainController` 结束当前工作流。
|
||||
* 方法 `get_main_data(key: String, default = null)` 和 `set_main_data(key: String, value)`: 分别用于从 `main_controller` 获取和设置共享数据。如果 `main_controller` 未被正确引用,会发出警告并返回 `default` 值 (对于 `get_main_data`) 或不设置数据 (对于 `set_main_data`)。
|
||||
|
||||
**3. 创建新的 UI 页面**
|
||||
|
||||
以下步骤详细说明了如何创建一个新的 UI 页面并将其集成到框架中。
|
||||
|
||||
**3.1. 创建场景文件 (.tscn)**
|
||||
|
||||
1. 在 Godot 编辑器的文件系统中,右键点击目标文件夹,选择“新建” -> “场景”。
|
||||
2. **根节点类型**: 选择 `Control` 作为根节点类型。你也可以根据需要选择 `PanelContainer` 等 `Control` 的派生类。
|
||||
3. **命名规范**: 场景文件建议使用清晰的命名,例如 `staff_management_screen.tscn` 或 `project_details_dialog.tscn`。
|
||||
4. 保存场景。
|
||||
|
||||
**3.2. 场景节点结构与命名规范**
|
||||
|
||||
* **页面根节点 (即场景的根 Control 节点)**:
|
||||
* 此节点将附加一个继承自 `UIPage` 的特定页面脚本 (见 3.3)。
|
||||
* 在 `Main.tscn` 场景中(或包含 `MainController` 的场景),此页面场景的实例将作为 `MainController` 节点的直接子节点(如果是顶级页面)或另一个 `UIPage` 实例的子节点(如果是子页面)。
|
||||
|
||||
* **内部 UI 控件**:
|
||||
* 在页面根节点下,根据需求添加各种 Godot UI 控件,如 `Label`, `Button`, `LineEdit`, `TextureRect`, `ProgressBar`, `ItemList`, `HBoxContainer`, `VBoxContainer`, `GridContainer` 等。
|
||||
* **命名规范**:
|
||||
* 为重要的、需要在脚本中引用的控件赋予清晰、一致的名称。
|
||||
* 建议使用驼峰式命名或下划线命名,并能体现控件类型和功能,例如:
|
||||
* `PlayerNameLabel`
|
||||
* `ConfirmButton` 或 `confirm_button`
|
||||
* `ProjectListVBoxContainer`
|
||||
* `CancelChangesButton`
|
||||
* **布局**: 强烈建议使用 Godot 的容器节点 (`HBoxContainer`, `VBoxContainer`, `GridContainer`, `MarginContainer`, `PanelContainer`, `ScrollContainer` 等) 来组织和布局内部 UI 控件,以实现响应式和易于维护的界面。
|
||||
|
||||
**3.3. 创建页面脚本 (.gd)**
|
||||
|
||||
1. 在 Godot 编辑器的文件系统中,右键点击目标文件夹,选择“新建” -> “脚本”。
|
||||
2. **命名规范**: 脚本名称应与其管理的页面场景相对应,例如 `staff_management_page.gd`。
|
||||
3. **继承 `UIPage`**:
|
||||
```gdscript
|
||||
# staff_management_page.gd
|
||||
class_name StaffManagementPage # 使用 class_name 方便类型提示
|
||||
extends UIPage
|
||||
```
|
||||
4. **`@onready` 变量获取控件引用**:
|
||||
在脚本顶部,使用 `@onready` 关键字获取场景中需要交互的 UI 控件的引用。
|
||||
```gdscript
|
||||
@onready var employee_list: ItemList = $ScrollContainer/VBoxContainer/EmployeeList
|
||||
@onready var hire_button: Button = $ControlsHBox/HireButton
|
||||
@onready var details_panel: PanelContainer = $DetailsPanel/ContentPanel
|
||||
@onready var employee_name_label: Label = $DetailsPanel/ContentPanel/NameLabel
|
||||
```
|
||||
5. **实现 `_ready()` 方法**:
|
||||
* **必须调用 `super._ready()`**: 确保基类 `UIPage` 的 `_ready()` 逻辑(如查找 `main_controller`)被执行。
|
||||
* **连接页面内部控件的信号**: 将按钮的 `pressed` 信号、`LineEdit` 的 `text_changed` 信号等连接到此脚本中的处理函数。
|
||||
```gdscript
|
||||
func _ready():
|
||||
super._ready() # !! 非常重要 !!确保 main_controller 被初始化
|
||||
|
||||
if hire_button: # 良好的习惯是检查节点是否存在
|
||||
hire_button.pressed.connect(_on_hire_button_pressed)
|
||||
if employee_list:
|
||||
employee_list.item_selected.connect(_on_employee_list_item_selected)
|
||||
# ... 其他信号连接
|
||||
```
|
||||
6. **覆写 `_on_page_activated()` 方法**:
|
||||
此方法在页面被 `MainController` 激活时调用。
|
||||
* **建议调用 `super._on_page_activated()`**: 基类实现会打印日志 (`UIPage activated: [PageName]`), 方便调试。
|
||||
* **加载数据**: 使用 `get_main_data("data_key", default_value)` 从 `MainController` 的共享数据中获取当前工作流所需的数据。
|
||||
* **更新 UI**: 根据获取的数据,更新页面上的 `Label.text`, `LineEdit.text`, `ProgressBar.value`,填充列表,设置按钮的 `disabled` 状态等。
|
||||
```gdscript
|
||||
func _on_page_activated():
|
||||
super._on_page_activated() # 基类打印日志
|
||||
|
||||
var current_staff = get_main_data("company_staff", [])
|
||||
_populate_employee_list(current_staff)
|
||||
|
||||
var can_hire = get_main_data("can_afford_new_hire", true)
|
||||
if hire_button:
|
||||
hire_button.disabled = not can_hire
|
||||
```
|
||||
7. **覆写 `_on_page_deactivated()` 方法 (可选)**:
|
||||
此方法在页面每次通过 `hide_page()` 即将变为非活动状态(隐藏)之前调用。
|
||||
* **建议调用 `super._on_page_deactivated()`**: 基类实现会打印日志 (`UIPage deactivated: [PageName]`)。
|
||||
* 用于执行页面隐藏前的清理工作,例如保存未提交的临时输入到 `shared_workflow_data`,或者重置页面状态以便下次激活时重新初始化。
|
||||
```gdscript
|
||||
func _on_page_deactivated():
|
||||
super._on_page_deactivated() # 基类打印日志
|
||||
# 如果有临时输入未保存,可以在这里处理
|
||||
# if name_input_field.text != get_main_data("current_editing_name"):
|
||||
# set_main_data("temp_unsaved_name", name_input_field.text)
|
||||
```
|
||||
8. **实现自定义方法**:
|
||||
编写处理页面特定交互逻辑的函数(例如上面 `_ready` 中连接的 `_on_hire_button_pressed`)。
|
||||
* 这些方法可能会读取页面输入、执行计算、调用 `set_main_data(key, value)` 来更新 `MainController` 中的共享数据。
|
||||
```gdscript
|
||||
func _on_hire_button_pressed():
|
||||
print("Hire button pressed on " + name)
|
||||
# 可能需要更新一些共享数据,表明要进入雇佣流程
|
||||
set_main_data("entering_hire_mode", true)
|
||||
# 然后导航到下一个页面(例如一个详细的雇佣信息填写页面)
|
||||
go_next() # go_next() 是从 UIPage 继承的方法
|
||||
|
||||
func _populate_employee_list(staff_data: Array):
|
||||
if employee_list:
|
||||
employee_list.clear()
|
||||
for employee_info in staff_data:
|
||||
employee_list.add_item(employee_info.get("name", "Unknown"))
|
||||
# 可以存储更复杂的数据
|
||||
# employee_list.set_item_metadata(employee_list.get_item_count() - 1, employee_info)
|
||||
```
|
||||
9. **调用导航方法**:
|
||||
在适当的时候(例如,用户点击确认按钮后),调用从 `UIPage` 继承的导航方法:
|
||||
* `go_next()`: 前往流程中的下一个页面或确认结束工作流。
|
||||
* `go_back()`: 返回上一个页面、父页面或取消结束工作流。
|
||||
* `go_to_child_page(child_node)`: 打开当前页面的一个子页面。
|
||||
|
||||
10. **附加脚本**: 将创建好的页面脚本附加到对应 UI 场景的根节点上。
|
||||
|
||||
**3.4. 配置页面导航 (Inspector)**
|
||||
|
||||
1. 打开包含 `MainController` 和 UI 页面实例的场景(例如 `Main.tscn`)。
|
||||
2. 确保你的新 UI 页面场景已经被实例化并添加为 `MainController` 节点的子节点(或相应父页面的子节点)。
|
||||
3. 选中新页面实例。
|
||||
4. 在 Godot 编辑器的 **Inspector** 面板中,找到并配置从 `UIPage` 继承来的导出变量:
|
||||
* **Next Ui Node Path**: 拖拽流程中的下一个页面节点到此属性。如果这是流程的最后一步(确认并结束),则留空 (使其 `NodePath` 为空)。
|
||||
* **Back Ui Node Path**: 拖拽流程中的上一个页面节点到此属性。如果这是流程的起点或返回即取消工作流,则留空。
|
||||
* **Parent Page Node Path**: **仅当此页面是作为另一个页面的子页面时配置**。拖拽其直接的父 `UIPage` 节点到此属性。这用于子页面在没有特定 `Back Ui Node Path` 时,通过 `go_back()` 返回其父级。
|
||||
* **Hide On Next**: (布尔值,默认为 `true`) 勾选此项(或设置为 `true`)表示当通过 `go_next()` 导航到下一个页面时,`MainController` 更倾向于隐藏此页面。取消勾选(或设置为 `false`)则此页面在导航后有更大可能性保持可见(具体行为取决于 `MainController` 中 `_switch_to_page` 的逻辑)。
|
||||
|
||||
**4. 将新页面集成到工作流**
|
||||
|
||||
* **4.1. 作为顶级页面 (例如 A, B, C)**:
|
||||
1. 将新创建的 UI 页面场景实例化,并使其成为 `MainController` 节点的直接子节点。
|
||||
2. `MainController` 的 `_ready()` 函数会自动查找并处理其场景树下两层内的 UI 页面(即 `MainController` 的直接子 `UIPage`,以及这些 `UIPage` 的直接子 `UIPage`)。它会隐藏这些页面并连接它们的信号。确保你的新页面是 `UIPage` 类型(即附加了继承自 `UIPage` 的脚本)。
|
||||
3. 根据工作流逻辑,配置 `MainController` 的 `Initial Page Path` 指向此新页面(如果它是起始页),或者修改其他页面的 `Next Ui Node Path` 或 `Back Ui Node Path` 以包含此新页面。
|
||||
|
||||
* **4.2. 作为子页面 (例如 A_1 是 A 的子页面)**:
|
||||
1. 将新创建的 UI 页面场景实例化,并使其成为其父 `UIPage` 节点的子节点。例如,`PageA1.tscn` 的实例是 `PageA` 节点的子节点。
|
||||
2. 在父页面 (例如 `PageA.gd`) 的脚本中,你需要:
|
||||
* 添加一个按钮或交互元素来触发打开此子页面。
|
||||
* 在该按钮的响应函数中,获取子页面节点的引用,并调用 `go_to_child_page(get_node("Path/To/YourChildPageNode"))`。
|
||||
3. 配置新子页面的 `Parent Page Node Path` (在 Inspector 中) 指向其父 `UIPage` 节点。
|
||||
4. `MainController` 的 `_ready()` 中的信号连接和初始隐藏逻辑会处理 `MainController` 的直接子 `UIPage` 以及这些 `UIPage` 的直接子 `UIPage`。如果你的子页面嵌套更深(例如,一个 `UIPage` 的孙子节点也是 `UIPage`,即相对于 `MainController` 三层或更深),则需要调整 `main_controller.gd` 中的 `_ready()` 循环以遍历更深层级,或者手动为更深层级的 `UIPage` 调用 `hide_page()` 并使用 `_connect_page_signals()` 连接其信号到 `MainController` 的相应处理方法。
|
||||
|
||||
**5. 注意事项与最佳实践**
|
||||
|
||||
* **单一职责**: 保持 `UIPage` 基类脚本的通用性。特定于某个页面的复杂逻辑应该放在该页面的派生脚本中。
|
||||
* **命名一致性**: 对场景、节点和脚本使用清晰、一致的命名约定。
|
||||
* **响应式布局**: 优先使用 Godot 的容器节点进行布局,以适应不同的屏幕尺寸和分辨率。
|
||||
* **数据流**: 所有跨页面的工作流数据都应通过 `MainController` 的 `shared_workflow_data` 进行管理。避免页面脚本之间直接相互引用以获取或修改状态。
|
||||
* **`_ready()` vs `_on_page_activated()`**:
|
||||
* `_ready()`: 用于一次性的初始化设置,如信号连接、节点引用获取、`main_controller` 的查找。它在节点进入场景树时调用一次。
|
||||
* `_on_page_activated()`: 由 `MainController` 在页面成为当前活动页面时调用。用于执行每次页面激活时需要执行的逻辑,如从 `MainController` 拉取最新数据并刷新 UI 显示。
|
||||
* **错误处理与健壮性**: 在获取节点引用 (`get_node_or_null`) 或处理路径时,考虑添加空检查,以避免运行时错误。`UIPage` 和 `MainController` 中的导航方法已经包含了一些基本的错误打印。
|
||||
* **测试**: 彻底测试所有导航路径,包括前进、后退、进入/退出子页面以及各种工作流结束条件(确认或取消)。
|
||||
* **处理多页面同时可见的情况**:
|
||||
* 当使用 `hide_on_next = false` 使得多个页面同时显示时,需要特别注意UI布局,确保它们不会相互不当重叠或干扰用户操作。
|
||||
* 考虑输入焦点管理。Godot的事件系统通常会将输入传递给最上层(渲染顺序)且可见的控件。如果多个可见页面都有可交互元素,请仔细规划和测试以确保行为符合预期。
|
||||
* 请记住,`MainController` 中的 `current_active_page` 始终指向最新导航到的(即“最活动的”)页面。其他因 `hide_on_next = false` (或类似逻辑)而保持可见的页面虽然显示在屏幕上,但它们不是 `MainController` 当前主要管理的页面。**重要:当从一个设置了 `hide_on_next = false` 的页面导航离开时,如果 `MainController` 决定不隐藏该页面,那么该页面的 `hide_page()` 方法将不会被调用,因此其 `_on_page_deactivated()` 方法也不会被调用。**
|
||||
@ -4,7 +4,7 @@
|
||||
[ext_resource type="Script" uid="uid://b5m1sxtrk04ut" path="res://UI/main/ui_main.gd" id="1_memhs"]
|
||||
[ext_resource type="PackedScene" uid="uid://bsmybl7xmr85u" path="res://UI/main/ui_bottom_info.tscn" id="2_q6yvl"]
|
||||
[ext_resource type="PackedScene" uid="uid://dlwl5hk5oadpj" path="res://UI/popup/play_menu/play_menu.tscn" id="9_6fpfi"]
|
||||
[ext_resource type="PackedScene" uid="uid://b4ll7wwg1s0qc" path="res://UI/popup/task_development/task_development.tscn" id="11_ae6v5"]
|
||||
[ext_resource type="PackedScene" uid="uid://b5npsmec2fo2w" path="res://UI/popup/task_development/task_development_start.tscn" id="11_ae6v5"]
|
||||
[ext_resource type="PackedScene" uid="uid://dtywh0m5odikx" path="res://UI/popup/dialogue.tscn" id="12_t4kna"]
|
||||
[ext_resource type="PackedScene" uid="uid://b70jleefiaiwi" path="res://UI/popup/notice.tscn" id="15_xupgg"]
|
||||
|
||||
@ -29,7 +29,6 @@ visible = false
|
||||
layout_mode = 1
|
||||
|
||||
[node name="task_development" parent="Pop_Up" instance=ExtResource("11_ae6v5")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
|
||||
[node name="notice" parent="Pop_Up" instance=ExtResource("15_xupgg")]
|
||||
|
||||
@ -1,28 +1,27 @@
|
||||
extends Control
|
||||
extends UIPage
|
||||
|
||||
# 1. 预加载 TypewriterLogic 类 (请替换为你的实际路径!)
|
||||
const TypewriterLogic = preload("res://UI/class/TypewriterLogic.gd")
|
||||
# 预加载 TypewriterLogic 类 (请替换为你的实际路径!)
|
||||
const _TypewriterLogic = preload("res://UI/class/TypewriterLogic.gd")
|
||||
|
||||
# 导出变量保持不变
|
||||
@export var typing_speed: float = 20.0 # 每秒显示的字符数
|
||||
@export var label_node_path: NodePath = "Part_2/Part_3/Label" # Label节点的路径
|
||||
@export var dialogues: Array
|
||||
|
||||
var typing_speed: float = 20.0 # 每秒显示的字符数
|
||||
var label_node_path: NodePath = "Part_2/Part_3/Label" # Label节点的路径
|
||||
|
||||
# --- 基础变量 ---
|
||||
var node_name: String
|
||||
var next_ui_node = null
|
||||
# var next_ui_node = null # next_ui_node_path 从 UIPage 继承,这里不需要重复定义
|
||||
var dialogue_queue = []
|
||||
var current_dialogue_index = 0
|
||||
var is_active: bool = false
|
||||
|
||||
# --- 节点和模块引用 ---
|
||||
var label: Label = null # 缓存Label节点引用
|
||||
var typewriter: TypewriterLogic = null # 用于存储 TypewriterLogic 实例
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready() # 确保调用父类的 _ready 方法
|
||||
node_name = str(self.name)
|
||||
visible = false
|
||||
set_process_input(false)
|
||||
print(node_name + ": _ready executed, visibility set to false.")
|
||||
print(node_name + ": _ready executed.")
|
||||
|
||||
# 尝试获取 Label 节点引用
|
||||
label = get_node_or_null(label_node_path)
|
||||
@ -31,137 +30,113 @@ func _ready() -> void:
|
||||
else:
|
||||
# 2. 创建 TypewriterLogic 实例
|
||||
print(node_name + ": Label found. Creating TypewriterLogic instance.")
|
||||
typewriter = TypewriterLogic.new(label, typing_speed)
|
||||
typewriter = _TypewriterLogic.new(label, typing_speed)
|
||||
# 检查实例是否成功创建 (TypewriterLogic 内部会检查 Label 有效性)
|
||||
if typewriter != null:
|
||||
# 3. 连接 TypewriterLogic 的 finished 信号 (如果需要响应)
|
||||
if not typewriter.is_connected("finished", Callable(self, "_on_dialogue_typing_finished")):
|
||||
typewriter.finished.connect(_on_dialogue_typing_finished)
|
||||
print(node_name + ": TypewriterLogic instance created and signal connected.")
|
||||
else:
|
||||
printerr(node_name + ": Failed to create TypewriterLogic instance.")
|
||||
|
||||
func _on_page_activated():
|
||||
super._on_page_activated() # 调用父类的方法
|
||||
print(node_name + ": Page activated.")
|
||||
_start(dialogues)
|
||||
|
||||
# 启动对话框显示 (逻辑基本不变)
|
||||
func _start(dialogues, next_node = null) -> void:
|
||||
print(node_name + ": _start function called. Making visible.")
|
||||
if dialogues is String:
|
||||
dialogue_queue = [dialogues]
|
||||
func _on_page_deactivated():
|
||||
super._on_page_deactivated() # 调用父类的方法
|
||||
print(node_name + ": Page deactivated.")
|
||||
# 确保在页面停用时也停止输入处理和可能的游戏暂停状态
|
||||
if typewriter != null:
|
||||
typewriter.stop_typing()
|
||||
|
||||
set_process_input(false)
|
||||
|
||||
|
||||
# 启动对话框显示
|
||||
func _start(p_dialogues) -> void: # Renamed parameter to avoid conflict
|
||||
print(node_name + ": _start function called.")
|
||||
if p_dialogues is String:
|
||||
dialogue_queue = [p_dialogues]
|
||||
elif p_dialogues is Array:
|
||||
dialogue_queue = p_dialogues.duplicate() # 使用 duplicate 以免修改原始导出数组
|
||||
else:
|
||||
dialogue_queue = dialogues
|
||||
printerr(node_name + ": Invalid dialogues data type.")
|
||||
dialogue_queue = [] # 置空以避免后续错误
|
||||
|
||||
current_dialogue_index = 0
|
||||
next_ui_node = next_node
|
||||
|
||||
# 显示第一段对话 (现在会调用 typewriter)
|
||||
_show_current_dialogue()
|
||||
|
||||
self.visible = true
|
||||
is_active = true
|
||||
if GameState: GameState.pause_game()
|
||||
set_process_input(true)
|
||||
set_process_input(true) # 在页面激活时启用输入处理
|
||||
|
||||
|
||||
# 4. 使用 TypewriterLogic 显示当前对话
|
||||
# 使用 TypewriterLogic 显示当前对话
|
||||
func _show_current_dialogue() -> void:
|
||||
if current_dialogue_index < dialogue_queue.size():
|
||||
# 检查 typewriter 实例是否有效
|
||||
if typewriter == null:
|
||||
printerr(node_name + ": TypewriterLogic instance is null. Cannot display text with effect.")
|
||||
# 提供后备:如果 typewriter 无效,直接设置文本
|
||||
if label != null:
|
||||
label.text = dialogue_queue[current_dialogue_index]
|
||||
label.visible_characters = label.text.length() # 确保完全可见
|
||||
label.visible_characters = label.text.length()
|
||||
return
|
||||
|
||||
var full_text = dialogue_queue[current_dialogue_index]
|
||||
print(node_name + ": Requesting typewriter to start typing.")
|
||||
# 调用 TypewriterLogic 的方法来开始打字
|
||||
print(node_name + ": Requesting typewriter to start typing: '", full_text, "'")
|
||||
typewriter.start_typing(full_text)
|
||||
|
||||
else:
|
||||
# 对话队列结束
|
||||
print(node_name + ": Dialogue queue finished.")
|
||||
_close_dialogue()
|
||||
|
||||
|
||||
# 5. 修改:使用 TypewriterLogic 处理输入事件
|
||||
func _input(event):
|
||||
if not is_active: return
|
||||
|
||||
# 检测鼠标左键点击事件
|
||||
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.is_pressed():
|
||||
# 检查 typewriter 是否有效并且正在打字
|
||||
if typewriter != null and typewriter.is_typing():
|
||||
print(node_name + ": Input detected while typing. Skipping.")
|
||||
# 调用 TypewriterLogic 的方法来跳过
|
||||
typewriter.skip_typing()
|
||||
get_viewport().set_input_as_handled()
|
||||
# 如果没有在打字,则进入下一段对话或关闭
|
||||
else:
|
||||
print(node_name + ": Input detected. Advancing dialogue.")
|
||||
current_dialogue_index += 1
|
||||
if current_dialogue_index < dialogue_queue.size():
|
||||
_show_current_dialogue() # 显示下一段对话
|
||||
else:
|
||||
_close_dialogue() # 所有对话结束,关闭
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
# 检测鼠标右键点击事件 - 直接关闭对话框
|
||||
elif event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT and event.is_pressed():
|
||||
print(node_name + ": Right-click detected. Closing dialogue.")
|
||||
_close_dialogue() # 关闭会调用 typewriter.stop_typing()
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
|
||||
# 6. 修改:关闭对话框时,调用 TypewriterLogic 的停止方法
|
||||
# 关闭对话框
|
||||
func _close_dialogue():
|
||||
if not is_active: return
|
||||
|
||||
print(node_name + ": Closing dialogue. Stopping typewriter if active.")
|
||||
# --- 修改:调用 TypewriterLogic 的停止方法 ---
|
||||
if typewriter != null:
|
||||
typewriter.stop_typing()
|
||||
# --- 修改结束 ---
|
||||
|
||||
self.visible = false
|
||||
print(node_name + ": Dialogue UI hidden.")
|
||||
|
||||
# 恢复游戏并停止输入处理
|
||||
if GameState:
|
||||
print(node_name + ": Resuming game.")
|
||||
GameState.resume_game()
|
||||
set_process_input(false)
|
||||
is_active = false # 确保在处理后续逻辑前标记为非活动
|
||||
|
||||
var parent = get_parent() # 获取父节点
|
||||
|
||||
# 检查是否有下一个UI需要显示 (逻辑保持不变)
|
||||
if next_ui_node != null and is_instance_valid(next_ui_node):
|
||||
print(node_name + ": Showing next UI: ", next_ui_node.name)
|
||||
next_ui_node.visible = true
|
||||
if next_ui_node.has_method("show_up"):
|
||||
next_ui_node.show_up()
|
||||
next_ui_node = null # 重置引用
|
||||
else:
|
||||
# 没有下一个UI节点 (逻辑保持不变)
|
||||
if parent != null and parent.has_method("close_all_popups"):
|
||||
print(node_name + ": No next UI node, calling parent's close_all_popups.")
|
||||
parent.close_all_popups()
|
||||
# ... (其他父节点检查逻辑) ...
|
||||
next_ui_node = null
|
||||
set_process_input(false) # 在关闭时禁用输入处理
|
||||
print(node_name + ": Dialogue UI processing stopped.")
|
||||
|
||||
|
||||
# 7. 添加:处理 TypewriterLogic 发出的 finished 信号的回调函数
|
||||
# 处理 TypewriterLogic 发出的 finished 信号的回调函数
|
||||
func _on_dialogue_typing_finished():
|
||||
# 这个函数会在 TypewriterLogic 自然完成一次打字动画时被调用
|
||||
print(node_name + ": Received 'finished' signal from TypewriterLogic.")
|
||||
# 你可以在这里添加任何需要在文本 *自然* 显示完毕后执行的逻辑
|
||||
# 例如:显示一个 "继续" 图标,或者允许玩家在不点击的情况下自动前进等。
|
||||
# 对于当前的点击继续逻辑,这个函数可能不需要做太多事情。
|
||||
pass # 暂时留空
|
||||
# 文本自然显示完毕后的逻辑。
|
||||
# 例如,可以显示一个“点击继续”的提示图标。
|
||||
# 对于当前的“点击任意处继续”逻辑,此函数可能不需要执行太多操作,
|
||||
# 因为 _input 函数会处理点击事件。
|
||||
pass
|
||||
|
||||
|
||||
# 8. 移除旧的 _on_typing_finished 函数 (如果它只用于处理旧的 Tween)
|
||||
# func _on_typing_finished(): # 这个函数不再需要了
|
||||
# is_typing = false
|
||||
# current_tween = null
|
||||
# print(node_name + ": Typing finished.")
|
||||
# --- 输入处理 ---
|
||||
# 新增/修改: 处理输入事件,特别是鼠标左键点击
|
||||
func _input(event: InputEvent) -> void:
|
||||
# 只有当页面可见且输入处理已启用时才处理输入
|
||||
# (set_process_input(true) 会在 _start 中调用)
|
||||
# (visible 状态由 MainController 和 UIPage 的 show_page/hide_page 管理)
|
||||
if not visible:
|
||||
return
|
||||
|
||||
if event is InputEventMouseButton:
|
||||
if event.button_index == MOUSE_BUTTON_LEFT and event.is_pressed():
|
||||
print(node_name + ": Left-click detected.")
|
||||
|
||||
# 行为1: 如果打字机正在打字,则立即完成当前行打字 (如果TypewriterLogic支持)
|
||||
# 行为2: 如果打字机已完成或未激活,则调用 go_next()
|
||||
# 当前的 TypewriterLogic 没有明确的 is_typing 或 skip_to_end 方法,
|
||||
# 所以我们直接调用 go_next()。
|
||||
# go_next() -> _close_dialogue() -> typewriter.stop_typing() 会停止打字。
|
||||
|
||||
print(node_name + ": Calling go_next() due to left-click.")
|
||||
go_next()
|
||||
get_viewport().set_input_as_handled() # 消费事件,防止其他节点处理
|
||||
return # 事件已处理
|
||||
|
||||
# 调用父类 (UIPage) 的 _input 方法,以保留其功能 (例如右键返回)
|
||||
# 如果此处的左键点击事件被处理并返回,则父类的 _input 不会再收到此特定事件。
|
||||
super._input(event)
|
||||
|
||||
387
UI/popup/task_development/main_plan/gameplay/gameplay.gd
Normal file
387
UI/popup/task_development/main_plan/gameplay/gameplay.gd
Normal file
@ -0,0 +1,387 @@
|
||||
extends UIPage
|
||||
|
||||
# UI Node References
|
||||
@onready var list_container = $BG/Option/Info
|
||||
@onready var previous_button = $BG/Title/previous/Button
|
||||
@onready var next_button = $BG/Title/next/Button
|
||||
@onready var title_label = $BG/Title/Title
|
||||
|
||||
# Configuration
|
||||
var items_per_page: int = 7 # 每页显示的选项数量
|
||||
|
||||
# Data Storage
|
||||
var gameplay_list_nodes: Array[VBoxContainer] = [] # 存储 List_1, List_2 等节点
|
||||
var option_nodes_per_list: Array = [] # 存储每个 List 对应的 option_X 按钮数组
|
||||
var all_enabled_gameplays: Array = [] # 存储筛选后的玩法数据 { "name": String, "data": Dictionary }
|
||||
|
||||
# State
|
||||
var total_pages: int = 0
|
||||
var current_page_index: int = 0
|
||||
var selected_gameplay_key: String = "" # 当前逻辑上选中的项的 Key (用于确认)
|
||||
var currently_selected_button: Button = null # 当前高亮/聚焦的按钮节点引用
|
||||
var initial_key_to_highlight: String = "" # 弹窗打开时需要高亮的 Key (由父节点设置)
|
||||
|
||||
func _ready():
|
||||
super._ready() # 调用父类的 _ready() (如果 UIPage 中有 _ready() 逻辑)
|
||||
# 1. 获取 List 节点 (与原版一致)
|
||||
for i in range(1, 4): # 检查 List_1, List_2, List_3
|
||||
var list_node = list_container.get_node_or_null("List_" + str(i))
|
||||
if list_node:
|
||||
gameplay_list_nodes.append(list_node)
|
||||
else:
|
||||
break
|
||||
|
||||
if gameplay_list_nodes.is_empty():
|
||||
printerr("错误:在 gameplay.tscn 中未找到 List 节点!无法显示选项。")
|
||||
set_process(false)
|
||||
return
|
||||
|
||||
# 2. 获取每个 List 内的 Option 节点 (与原版一致)
|
||||
for list_node in gameplay_list_nodes:
|
||||
var current_list_options: Array = []
|
||||
for i in range(1, items_per_page + 1):
|
||||
var option_node = list_node.get_node_or_null("option_" + str(i))
|
||||
if option_node and option_node is Button:
|
||||
current_list_options.append(option_node)
|
||||
else:
|
||||
push_warning("警告:在 %s 中未能找到 option_%d 按钮" % [list_node.name, i])
|
||||
option_nodes_per_list.append(current_list_options)
|
||||
|
||||
# 3. 连接按钮信号 (与原版一致)
|
||||
if previous_button:
|
||||
if not previous_button.pressed.is_connected(_on_previous_pressed):
|
||||
previous_button.pressed.connect(_on_previous_pressed)
|
||||
else: printerr("错误:在 gameplay.tscn 中未找到 Previous 按钮")
|
||||
|
||||
if next_button:
|
||||
if not next_button.pressed.is_connected(_on_next_pressed):
|
||||
next_button.pressed.connect(_on_next_pressed)
|
||||
else: printerr("错误:在 gameplay.tscn 中未找到 Next 按钮")
|
||||
|
||||
# 4. 连接 visibility_changed 信号 (与原版一致)
|
||||
if not is_connected("visibility_changed", _on_visibility_changed):
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
|
||||
# 5. 移除 _ready 中的初始数据加载和显示更新
|
||||
# 这些逻辑现在完全由 _on_visibility_changed -> reset_display 处理
|
||||
|
||||
# --- Visibility Change Handler ---
|
||||
func _on_visibility_changed():
|
||||
if is_visible_in_tree():
|
||||
print("Gameplay: 弹窗变为可见,调用 reset_display()")
|
||||
reset_display() # 当变为可见时调用 reset
|
||||
# else: # 可选:隐藏时的清理逻辑
|
||||
# print("Gameplay: 弹窗变为隐藏。")
|
||||
|
||||
# --- 新增:用于父节点设置初始选中项 ---
|
||||
func set_initial_selection(key: String):
|
||||
"""
|
||||
由父节点 (task_development) 在显示此弹窗前调用,
|
||||
传递当前在 task_info 中选中的玩法 Key。
|
||||
"""
|
||||
initial_key_to_highlight = key
|
||||
print("Gameplay: 父节点设置初始高亮 Key 为: '%s'" % initial_key_to_highlight)
|
||||
|
||||
|
||||
# --- Data Processing and Display Logic ---
|
||||
|
||||
func _process_gameplay_data(all_gameplays_data: Dictionary):
|
||||
"""【修改】根据从 GameState 获取的玩法数据,筛选出启用的玩法,并计算总页数。"""
|
||||
all_enabled_gameplays.clear()
|
||||
if all_gameplays_data.is_empty():
|
||||
push_warning("警告:接收到的玩法数据为空。")
|
||||
total_pages = 0
|
||||
return
|
||||
|
||||
# 遍历从 GameState 获取的玩法字典
|
||||
for gameplay_name in all_gameplays_data:
|
||||
var gameplay_info = all_gameplays_data[gameplay_name]
|
||||
# 检查是否为字典且 "enabled" 字段为 true
|
||||
if typeof(gameplay_info) == TYPE_DICTIONARY and gameplay_info.get("enabled", false) == true:
|
||||
all_enabled_gameplays.append({"name": gameplay_name, "data": gameplay_info})
|
||||
# else: # Debugging: 可以取消注释来看哪些被过滤了
|
||||
# print("Gameplay: 过滤掉未启用或格式错误的玩法: ", gameplay_name)
|
||||
|
||||
# 根据筛选结果计算总页数
|
||||
if items_per_page > 0:
|
||||
total_pages = ceil(float(all_enabled_gameplays.size()) / items_per_page)
|
||||
else:
|
||||
total_pages = 0
|
||||
printerr("错误:items_per_page 为零,无法计算页数。")
|
||||
|
||||
print("Gameplay: 处理完成,找到 %d 个启用的玩法,共 %d 页。" % [all_enabled_gameplays.size(), total_pages])
|
||||
|
||||
func reset_display():
|
||||
# 1. 重置本地状态变量
|
||||
currently_selected_button = null
|
||||
selected_gameplay_key = ""
|
||||
|
||||
# 1b. 【修改】从 MainController 的共享数据中获取初始应选中的玩法 Key
|
||||
# 这个值将覆盖之前可能通过 set_initial_selection 设置的值(如果该方法在 reset_display 前被调用)。
|
||||
# 请确保 "initial_selected_gameplay" 是您在 shared_workflow_data 中用于此目的的正确键名。
|
||||
initial_key_to_highlight = get_main_data("玩法", "")
|
||||
if not initial_key_to_highlight.is_empty():
|
||||
print("Gameplay (reset_display): 从 get_main_data 获取到初始高亮 Key: '%s'" % initial_key_to_highlight)
|
||||
else:
|
||||
# 如果 get_main_data 没有提供有效的 Key (返回空字符串或默认值),
|
||||
# initial_key_to_highlight 将是空字符串。
|
||||
# 如果之前 set_initial_selection 被调用并设置了一个非空值,该值已被这里的空字符串覆盖。
|
||||
# 如果希望保留 set_initial_selection 的值作为后备,逻辑需要调整,
|
||||
# 但根据“来自get_main_data”的表述,这里直接取用 get_main_data 的结果。
|
||||
print("Gameplay (reset_display): 未从 get_main_data 获取到初始高亮 Key,或 Key 为空。")
|
||||
|
||||
|
||||
# 2. 【保持不变】从 GameState 加载并处理所有可显示的玩法数据
|
||||
if not GameState:
|
||||
printerr("错误:GameState 在 reset_display 期间不可用。")
|
||||
total_pages = 0
|
||||
all_enabled_gameplays.clear()
|
||||
_update_display() # 即使没有数据也要更新显示(显示空状态)
|
||||
return
|
||||
|
||||
var task_dev_data = GameState.get_value("task_development", {})
|
||||
if task_dev_data.is_empty():
|
||||
printerr("错误:从 GameState 获取 'task_development' 数据失败。")
|
||||
total_pages = 0
|
||||
all_enabled_gameplays.clear()
|
||||
else:
|
||||
var all_gameplays_data = task_dev_data.get("gameplays", {})
|
||||
_process_gameplay_data(all_gameplays_data) # 重新处理数据,计算 total_pages
|
||||
|
||||
# 3. 【逻辑不变,但使用来自 get_main_data 的 initial_key_to_highlight】
|
||||
# 根据 initial_key_to_highlight 确定初始页面
|
||||
current_page_index = 0 # 默认为第一页
|
||||
var found_initial_key = false
|
||||
if total_pages > 0 and not initial_key_to_highlight.is_empty():
|
||||
# 查找 initial_key_to_highlight 所在的索引和页面
|
||||
for i in range(all_enabled_gameplays.size()):
|
||||
if all_enabled_gameplays[i].name == initial_key_to_highlight:
|
||||
current_page_index = int(floor(float(i) / items_per_page))
|
||||
found_initial_key = true
|
||||
print("Gameplay: 找到需要初始高亮的 Key '%s' (来自 get_main_data 或后续处理) 在索引 %d, 目标页面 %d" % [initial_key_to_highlight, i, current_page_index])
|
||||
break # 找到了,停止循环
|
||||
if not found_initial_key:
|
||||
print("Gameplay: 需要初始高亮的 Key '%s' (来自 get_main_data) 未在启用的玩法中找到,将显示第一页。" % initial_key_to_highlight)
|
||||
# 保持 current_page_index 为 0
|
||||
initial_key_to_highlight = "" # 清空,避免后续 _update_display 尝试高亮不存在的项
|
||||
|
||||
# 确保页面索引有效
|
||||
if total_pages == 0:
|
||||
current_page_index = 0
|
||||
elif current_page_index >= total_pages:
|
||||
current_page_index = total_pages - 1
|
||||
elif current_page_index < 0:
|
||||
current_page_index = 0
|
||||
|
||||
# 4. 触发显示更新
|
||||
_update_display()
|
||||
|
||||
func _update_display():
|
||||
"""【更新版】更新列表的可见性并填充当前页面的内容。
|
||||
现在将“经验”和“成本”显示为整数。
|
||||
"""
|
||||
# --- 处理无数据情况 ---
|
||||
if gameplay_list_nodes.is_empty():
|
||||
print("Gameplay: 无可用的 List 节点。")
|
||||
if title_label: title_label.text = "玩法选择"
|
||||
return
|
||||
|
||||
if total_pages == 0:
|
||||
for list_node in gameplay_list_nodes: list_node.visible = false
|
||||
print("Gameplay: 没有启用的玩法选项可供显示。")
|
||||
if title_label: title_label.text = "玩法选择 (无可用)"
|
||||
# 确保按钮也禁用或隐藏
|
||||
if previous_button: previous_button.disabled = true
|
||||
if next_button: next_button.disabled = true
|
||||
return
|
||||
else:
|
||||
# 确保按钮状态正确 (启用/禁用基于页数)
|
||||
if previous_button: previous_button.disabled = (total_pages <= 1)
|
||||
if next_button: next_button.disabled = (total_pages <= 1)
|
||||
|
||||
|
||||
# --- 更新页面索引 (循环) ---
|
||||
# 注意: reset_display 设置了初始页, 取模主要用于翻页
|
||||
if total_pages > 0 : # 避免除以零
|
||||
current_page_index = current_page_index % total_pages
|
||||
if current_page_index < 0:
|
||||
current_page_index += total_pages
|
||||
else:
|
||||
current_page_index = 0
|
||||
|
||||
|
||||
# --- 更新标题 ---
|
||||
if title_label:
|
||||
var display_page_number = current_page_index + 1 # 显示给用户的页码从1开始
|
||||
title_label.text = "玩法选择 %d/%d" % [display_page_number, total_pages]
|
||||
|
||||
# --- 更新 List 可见性 ---
|
||||
# 确保只有一个 List 节点是可见的,即当前页对应的 List
|
||||
for i in range(gameplay_list_nodes.size()):
|
||||
gameplay_list_nodes[i].visible = (i == current_page_index)
|
||||
|
||||
# --- 填充可见列表并查找要高亮的按钮 ---
|
||||
var button_to_highlight: Button = null
|
||||
var first_enabled_button_on_page: Button = null # 如果 initial_key 不在本页,则使用此按钮
|
||||
|
||||
# 检查当前页索引是否在有效范围内
|
||||
if current_page_index < option_nodes_per_list.size():
|
||||
var current_options = option_nodes_per_list[current_page_index] # 获取当前页的所有按钮节点
|
||||
var start_index = current_page_index * items_per_page # 计算当前页数据在 all_enabled_gameplays 中的起始索引
|
||||
|
||||
# 遍历当前页的按钮槽位
|
||||
for i in range(current_options.size()):
|
||||
var option_button = current_options[i] # 获取具体的按钮节点
|
||||
var item_index = start_index + i # 计算此按钮对应的数据索引
|
||||
|
||||
# --- 断开旧信号 ---
|
||||
# 确保在连接新信号前断开旧的,防止重复连接
|
||||
if option_button.pressed.is_connected(_on_option_selected):
|
||||
option_button.pressed.disconnect(_on_option_selected)
|
||||
|
||||
# 检查数据索引是否在有效范围内
|
||||
if item_index < all_enabled_gameplays.size():
|
||||
# 获取对应的玩法数据
|
||||
var gameplay_entry = all_enabled_gameplays[item_index]
|
||||
var gameplay_name = gameplay_entry.name
|
||||
var gameplay_data = gameplay_entry.data # 这是包含 Cost, Experience, Popularity 等信息的字典
|
||||
|
||||
# 获取按钮内部用于显示信息的 Row 节点
|
||||
var row = option_button.get_node_or_null("Row")
|
||||
if row:
|
||||
# 填充标签文本
|
||||
var title_label_in_row = row.get_node_or_null("Title")
|
||||
var exp_label = row.get_node_or_null("Experience")
|
||||
var pop_label = row.get_node_or_null("Popularity")
|
||||
# 查找成本标签,兼容 "Cost" 和 "cost" 两种可能的节点名
|
||||
var cost_label = row.get_node_or_null("Cost") if row.has_node("Cost") else row.get_node_or_null("cost")
|
||||
|
||||
# 设置标题
|
||||
if title_label_in_row: title_label_in_row.text = gameplay_name
|
||||
|
||||
# 【修改】设置经验值,显示为整数
|
||||
if exp_label:
|
||||
var experience_value = gameplay_data.get("Experience", 0.0) # 获取原始值
|
||||
exp_label.text = str(int(experience_value)) # 转为整数再转为字符串
|
||||
|
||||
# 【保持】设置流行度,保持原始字符串显示
|
||||
if pop_label:
|
||||
var popularity_value = gameplay_data.get("Popularity", "未知") # 获取原始值
|
||||
pop_label.text = str(popularity_value) # 直接转为字符串
|
||||
|
||||
# 【修改】设置成本,显示为整数
|
||||
if cost_label:
|
||||
var cost_value = gameplay_data.get("Cost", 0.0) # 获取原始值
|
||||
cost_label.text = str(int(cost_value)) # 转为整数再转为字符串
|
||||
|
||||
# 设置按钮可见、可用,并存储玩法名称到元数据
|
||||
option_button.visible = true
|
||||
option_button.disabled = false
|
||||
option_button.set_meta("gameplay_name", gameplay_name)
|
||||
|
||||
# --- 连接新信号 (使用 bind) ---
|
||||
# 传递玩法名称和按钮节点本身给处理函数
|
||||
option_button.pressed.connect(_on_option_selected.bind(gameplay_name, option_button))
|
||||
|
||||
# 记录本页第一个可用的按钮,作为备选高亮目标
|
||||
if first_enabled_button_on_page == null:
|
||||
first_enabled_button_on_page = option_button
|
||||
|
||||
# 检查此按钮是否是需要初始高亮的按钮
|
||||
if not initial_key_to_highlight.is_empty() and gameplay_name == initial_key_to_highlight:
|
||||
button_to_highlight = option_button
|
||||
# print("Gameplay: 找到需要初始高亮的按钮: ", button_to_highlight.name) # Debug
|
||||
|
||||
else: # 未找到 Row 节点
|
||||
push_warning("警告:在按钮 %s 中未找到 Row 节点" % option_button.get_path())
|
||||
option_button.visible = false # 隐藏按钮以避免显示不完整
|
||||
option_button.disabled = true
|
||||
else: # 此槽位没有对应的启用玩法数据 (例如最后一页不满)
|
||||
option_button.visible = false # 隐藏按钮
|
||||
option_button.disabled = true
|
||||
else:
|
||||
# 这种情况理论上不应发生,除非页面计算或节点结构有问题
|
||||
printerr("错误:当前页面索引 %d 超出 option_nodes_per_list 的范围 (大小 %d)" % [current_page_index, option_nodes_per_list.size()])
|
||||
|
||||
# --- 设置初始高亮和焦点 ---
|
||||
# 优先高亮 initial_key_to_highlight 对应的按钮
|
||||
if button_to_highlight:
|
||||
# print("Gameplay: 尝试高亮指定按钮: ", button_to_highlight.name) # Debug
|
||||
_set_initial_highlight(button_to_highlight)
|
||||
# 如果没有指定按钮或指定按钮不在当前页,则高亮当前页的第一个可用按钮
|
||||
elif first_enabled_button_on_page:
|
||||
print("Gameplay: 初始 Key '%s' 不在本页或为空。高亮本页第一个按钮: %s" % [initial_key_to_highlight, first_enabled_button_on_page.name])
|
||||
_set_initial_highlight(first_enabled_button_on_page)
|
||||
# 如果当前页没有任何可用按钮
|
||||
else:
|
||||
print("Gameplay: 本页没有可供高亮的按钮。")
|
||||
currently_selected_button = null # 确保没有按钮被标记为选中
|
||||
selected_gameplay_key = "" # 确保没有 Key 被标记为选中
|
||||
|
||||
# (Helper) 设置初始高亮和焦点 (与原版类似,增加日志)
|
||||
func _set_initial_highlight(button_to_highlight: Button):
|
||||
if not is_instance_valid(button_to_highlight):
|
||||
printerr("错误:传递给 _set_initial_highlight 的按钮无效。")
|
||||
currently_selected_button = null
|
||||
selected_gameplay_key = ""
|
||||
return
|
||||
|
||||
# print("Gameplay: 设置高亮按钮: ", button_to_highlight.name) # Debug
|
||||
currently_selected_button = button_to_highlight
|
||||
selected_gameplay_key = button_to_highlight.get_meta("gameplay_name", "") # 同时设置 Key
|
||||
# print("Gameplay: currently_selected_button 设置为: ", currently_selected_button.name) # Debug
|
||||
# print("Gameplay: selected_gameplay_key 设置为: '", selected_gameplay_key, "'") # Debug
|
||||
|
||||
# 延迟调用 grab_focus 确保按钮已准备好接收焦点
|
||||
if currently_selected_button and currently_selected_button.is_inside_tree():
|
||||
# print("Gameplay: 尝试为按钮 call_deferred('grab_focus'): ", currently_selected_button.name) # Debug
|
||||
currently_selected_button.call_deferred("grab_focus")
|
||||
else:
|
||||
print("Gameplay: 按钮无效或不在场景树中,无法获取焦点。")
|
||||
|
||||
|
||||
# --- Signal Handlers ---
|
||||
|
||||
func _on_previous_pressed():
|
||||
if total_pages > 1: # 仅当有多页时才翻页
|
||||
current_page_index -= 1
|
||||
# 循环由 _update_display 处理
|
||||
_update_display()
|
||||
|
||||
func _on_next_pressed():
|
||||
if total_pages > 1: # 仅当有多页时才翻页
|
||||
current_page_index += 1
|
||||
# 循环由 _update_display 处理
|
||||
_update_display()
|
||||
|
||||
# 【修改】处理选项按钮按下事件 (与原版类似,增加日志)
|
||||
func _on_option_selected(gameplay_name: String, button_node: Button):
|
||||
"""当选项按钮被按下时调用。"""
|
||||
if not is_instance_valid(button_node):
|
||||
printerr("错误:在 _on_option_selected 中收到无效按钮节点,Key: " + gameplay_name)
|
||||
return
|
||||
|
||||
if button_node == currently_selected_button:
|
||||
# --- 双击 (或点击已选中的按钮) ---
|
||||
print("Gameplay: 检测到双击或确认点击: ", gameplay_name)
|
||||
_confirm_and_close(gameplay_name) # 确认此选择
|
||||
else:
|
||||
# --- 首次点击或点击不同按钮 ---
|
||||
print("Gameplay: 选中 (高亮) 玩法: ", gameplay_name)
|
||||
currently_selected_button = button_node
|
||||
selected_gameplay_key = gameplay_name # 更新 Key,以便后续可能的确认
|
||||
|
||||
# 更新视觉焦点
|
||||
button_node.grab_focus()
|
||||
|
||||
# 【修改】确认选择并关闭弹窗的逻辑
|
||||
func _confirm_and_close(key_to_confirm: String):
|
||||
"""更新父节点并关闭此弹窗。"""
|
||||
if key_to_confirm.is_empty():
|
||||
printerr("错误:尝试确认一个空的玩法 Key。")
|
||||
return
|
||||
|
||||
print("Gameplay: 确认选择: ", key_to_confirm)
|
||||
|
||||
set_main_data("玩法", key_to_confirm)
|
||||
go_next()
|
||||
@ -0,0 +1 @@
|
||||
uid://q11vjese3yt2
|
||||
1403
UI/popup/task_development/main_plan/gameplay/gameplay.tscn
Normal file
1403
UI/popup/task_development/main_plan/gameplay/gameplay.tscn
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,17 @@
|
||||
[gd_resource type="Theme" load_steps=5 format=3 uid="uid://ddq54ba6vwyn0"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_kemom"]
|
||||
bg_color = Color(0.513883, 0.609153, 0.731076, 1)
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ao15e"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_kemom"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_mp8x4"]
|
||||
bg_color = Color(0.513883, 0.609153, 0.731076, 1)
|
||||
|
||||
[resource]
|
||||
Button/styles/focus = SubResource("StyleBoxFlat_kemom")
|
||||
Button/styles/hover = SubResource("StyleBoxEmpty_ao15e")
|
||||
Button/styles/normal = SubResource("StyleBoxEmpty_kemom")
|
||||
Button/styles/pressed = SubResource("StyleBoxFlat_mp8x4")
|
||||
179
UI/popup/task_development/main_plan/main_plan.gd
Normal file
179
UI/popup/task_development/main_plan/main_plan.gd
Normal file
@ -0,0 +1,179 @@
|
||||
extends UIPage # 继承自我们之前创建的 UIPage
|
||||
|
||||
@onready var platform_page_path = $platform
|
||||
@onready var gameplay_page_path: Control = $gameplay
|
||||
@onready var theme_page_path: Control = $theme
|
||||
@onready var strategy_page_path: Control = $strategy
|
||||
|
||||
# Part_2: 预算
|
||||
@onready var budget_button: Button = $BG/Part_2/HBoxContainer/Button
|
||||
|
||||
# Part_3: 选择列表中的按钮
|
||||
@onready var platform_select_button: Button = $"BG/Part_3/Select_List/1_right/Button"
|
||||
@onready var gameplay_select_button: Button = $"BG/Part_3/Select_List/2_right/Button"
|
||||
@onready var theme_select_button: Button = $"BG/Part_3/Select_List/3_right/Button"
|
||||
@onready var strategy_select_button: Button = $"BG/Part_3/Select_List/4_right/Button"
|
||||
|
||||
# 确认按钮
|
||||
@onready var confirm_button: Button = $BG/Confirm
|
||||
|
||||
func _ready():
|
||||
super._ready() # 调用父类的 _ready() (如果 UIPage 中有 _ready() 逻辑)
|
||||
|
||||
if platform_select_button:
|
||||
platform_select_button.pressed.connect(_on_platform_select_button_pressed)
|
||||
if gameplay_select_button:
|
||||
gameplay_select_button.pressed.connect(_on_gameplay_select_button_pressed)
|
||||
if theme_select_button:
|
||||
theme_select_button.pressed.connect(_on_theme_select_button_pressed)
|
||||
if strategy_select_button:
|
||||
strategy_select_button.pressed.connect(_on_strategy_select_button_pressed)
|
||||
|
||||
if confirm_button:
|
||||
confirm_button.pressed.connect(_on_confirm_button_pressed)
|
||||
|
||||
func _on_page_activated():
|
||||
super._on_page_activated() # 调用父类的激活逻辑
|
||||
print(name + " 页面已激活")
|
||||
_calculate_and_update_budget()
|
||||
# 从 MainController 加载并显示数据
|
||||
# 例如,加载项目预算
|
||||
var current_budget = get_main_data("预算", 0) # 假设默认预算为500
|
||||
if budget_button:
|
||||
budget_button.text = str(current_budget)
|
||||
|
||||
# 加载并显示已选的平台、玩法、题材、开发策略
|
||||
# 这些值可能在其他子页面选择后被设置到 shared_workflow_data 中,
|
||||
# 或者在此页面有默认值/初始值。
|
||||
var selected_platform = get_main_data("平台", "") # 默认值来自场景
|
||||
if platform_select_button:
|
||||
platform_select_button.text = selected_platform
|
||||
|
||||
var selected_gameplay = get_main_data("玩法", "") # 默认值来自场景
|
||||
if gameplay_select_button:
|
||||
gameplay_select_button.text = selected_gameplay
|
||||
|
||||
var selected_theme = get_main_data("题材", "") # 默认值来自场景
|
||||
if theme_select_button:
|
||||
theme_select_button.text = selected_theme
|
||||
|
||||
var selected_strategy = get_main_data("开发策略", "") # 默认值来自场景
|
||||
if strategy_select_button:
|
||||
strategy_select_button.text = selected_strategy
|
||||
|
||||
# 可以在这里根据条件设置按钮是否可用等
|
||||
# 例如: if some_condition: confirm_button.disabled = true
|
||||
|
||||
func _on_page_deactivated():
|
||||
super._on_page_deactivated() # 调用父类的停用逻辑
|
||||
print(name + " 页面已停用")
|
||||
# 可以在这里保存任何未提交的临时数据
|
||||
# 例如: set_main_data("temp_project_name", project_name_line_edit.text)
|
||||
|
||||
|
||||
# 辅助函数:安全地从嵌套字典中获取值
|
||||
# source_dict: 要从中查找的源字典
|
||||
# path_keys: 一个包含路径中各个键的数组 (e.g., ["platforms", "Switch", "Cost"])
|
||||
# default_value: 如果路径无效或键未找到,则返回此值
|
||||
func _get_nested_value_from_dict(source_dict: Dictionary, path_keys: Array, default_value = null):
|
||||
var current_item = source_dict
|
||||
for key_part in path_keys:
|
||||
if not (current_item is Dictionary and current_item.has(key_part)):
|
||||
#printerr("Debug: Key '", key_part, "' not found or item not a dict at path: ", path_keys)
|
||||
return default_value
|
||||
current_item = current_item[key_part]
|
||||
return current_item
|
||||
|
||||
# 根据选择计算并更新预算的函数
|
||||
func _calculate_and_update_budget() -> void:
|
||||
# 1. 从 shared_workflow_data 获取当前的选择
|
||||
var selected_platform = get_main_data("平台", "")
|
||||
var selected_gameplay = get_main_data("玩法", "")
|
||||
var selected_theme = get_main_data("题材", "")
|
||||
var selected_strategy = get_main_data("开发策略", "")
|
||||
|
||||
var platform_cost: float = 0.0
|
||||
var gameplay_cost: float = 0.0
|
||||
var theme_cost: float = 0.0
|
||||
var strategy_cost_multiplier: float = 0.0 # 注意:策略的 "Cost" 是一个成本系数
|
||||
|
||||
# 2. 从 GameState 获取 "task_development" 数据
|
||||
# 注意:根据提供的 GameState.gd,get_value() 仅获取顶层键。
|
||||
var task_dev_data = GameState.get_value("task_development")
|
||||
|
||||
if not (task_dev_data is Dictionary):
|
||||
printerr("MainPage: 'task_development' key not found in GameState or is not a Dictionary.")
|
||||
if budget_button:
|
||||
budget_button.text = "错误: 数据缺失"
|
||||
set_main_data("预算", 0.0) # 在共享数据中将预算设为0
|
||||
return
|
||||
|
||||
# 3. 获取各项成本
|
||||
# 平台成本
|
||||
if not selected_platform.is_empty():
|
||||
var cost_val = _get_nested_value_from_dict(task_dev_data, ["platforms", selected_platform, "Cost"])
|
||||
if cost_val != null:
|
||||
platform_cost = float(cost_val)
|
||||
else:
|
||||
printerr("MainPage: 平台 '", selected_platform, "' 的成本未找到或路径无效。使用 0.0。")
|
||||
platform_cost = 0.0 # 确保为 float
|
||||
|
||||
# 玩法成本
|
||||
if not selected_gameplay.is_empty():
|
||||
var cost_val = _get_nested_value_from_dict(task_dev_data, ["gameplays", selected_gameplay, "Cost"])
|
||||
if cost_val != null:
|
||||
gameplay_cost = float(cost_val)
|
||||
else:
|
||||
printerr("MainPage: 玩法 '", selected_gameplay, "' 的成本未找到或路径无效。使用 0.0。")
|
||||
gameplay_cost = 0.0
|
||||
|
||||
# 题材成本
|
||||
if not selected_theme.is_empty():
|
||||
var cost_val = _get_nested_value_from_dict(task_dev_data, ["themes", selected_theme, "Cost"])
|
||||
if cost_val != null:
|
||||
theme_cost = float(cost_val)
|
||||
else:
|
||||
printerr("MainPage: 题材 '", selected_theme, "' 的成本未找到或路径无效。使用 0.0。")
|
||||
theme_cost = 0.0
|
||||
|
||||
# 开发策略成本系数
|
||||
if not selected_strategy.is_empty():
|
||||
var cost_val = _get_nested_value_from_dict(task_dev_data, ["strategies", selected_strategy, "Cost"])
|
||||
if cost_val != null:
|
||||
strategy_cost_multiplier = float(cost_val)
|
||||
else:
|
||||
printerr("MainPage: 开发策略 '", selected_strategy, "' 的成本系数未找到或路径无效。使用 0.0。")
|
||||
strategy_cost_multiplier = 0.0
|
||||
|
||||
# 4. 计算预算
|
||||
# 公式: (平台成本 + 玩法成本 + 题材成本) * (1 + 策略成本系数)
|
||||
var base_cost = platform_cost + gameplay_cost + theme_cost
|
||||
var calculated_budget = base_cost * (1.0 + strategy_cost_multiplier)
|
||||
|
||||
# 5. 更新预算按钮的文本和共享数据中的预算值
|
||||
if budget_button:
|
||||
budget_button.text = "¥" + str(snapped(calculated_budget, 0.01)) # 显示为货币格式,保留两位小数
|
||||
|
||||
set_main_data("预算", int(calculated_budget)) # 将计算得到的预算存回 shared_workflow_data
|
||||
|
||||
print("MainPage: 计算得到的预算: ", calculated_budget,
|
||||
" (平台:", platform_cost, " 玩法:", gameplay_cost, " 题材:", theme_cost, " 策略系数:", strategy_cost_multiplier, ")")
|
||||
|
||||
# --- 信号处理函数 ---
|
||||
func _on_platform_select_button_pressed():
|
||||
go_to_child_page(platform_page_path)
|
||||
|
||||
func _on_gameplay_select_button_pressed():
|
||||
go_to_child_page(gameplay_page_path)
|
||||
|
||||
func _on_theme_select_button_pressed():
|
||||
go_to_child_page(theme_page_path)
|
||||
|
||||
func _on_strategy_select_button_pressed():
|
||||
go_to_child_page(strategy_page_path)
|
||||
|
||||
func _on_confirm_button_pressed():
|
||||
# 导航到下一个页面或结束工作流
|
||||
# 由于 main_page 在 task_development.tscn 中配置的 next_ui_node_path 为空,
|
||||
# 调用 go_next() 将触发 workflow_end_requested(true) 信号。
|
||||
go_next()
|
||||
1
UI/popup/task_development/main_plan/main_plan.gd.uid
Normal file
1
UI/popup/task_development/main_plan/main_plan.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://c5ee63mwjjx7
|
||||
501
UI/popup/task_development/main_plan/main_plan.tscn
Normal file
501
UI/popup/task_development/main_plan/main_plan.tscn
Normal file
@ -0,0 +1,501 @@
|
||||
[gd_scene load_steps=26 format=3 uid="uid://bfmnpiqcyi83h"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://c5ee63mwjjx7" path="res://UI/popup/task_development/main_plan/main_plan.gd" id="1_1p8wx"]
|
||||
[ext_resource type="Texture2D" uid="uid://pucudatqrcrq" path="res://UI/popup/popup_bg_1.png" id="1_fdlfp"]
|
||||
[ext_resource type="Texture2D" uid="uid://bk8155f5le6k4" path="res://UI/main/icon_money.png" id="2_1p8wx"]
|
||||
[ext_resource type="LabelSettings" uid="uid://cvwpqds25xnfs" path="res://UI/tres/ui_main_label_number.tres" id="3_n0vbh"]
|
||||
[ext_resource type="FontFile" uid="uid://egugs822n8gr" path="res://UI/font/AlimamaFangYuanTiVF-Thin.ttf" id="4_fdt2j"]
|
||||
[ext_resource type="Theme" uid="uid://bau80ps6kx783" path="res://UI/tres/Bottom_Info_button_theme.tres" id="5_edtgu"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_xfbvu"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_nckjb"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_6r1e0"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_at31c"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_qrj6y"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_v0qi7"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_kctqw"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ibc02"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_bd6ki"]
|
||||
bg_color = Color(0.639216, 0.639216, 0.639216, 1)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_vhs2i"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_uiuum"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_bq7yg"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ej27o"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_qo358"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_6xfhm"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_k3c3w"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3etuv"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_e0qho"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_qljg5"]
|
||||
|
||||
[node name="main_plan" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_1p8wx")
|
||||
|
||||
[node name="BG" type="NinePatchRect" parent="."]
|
||||
custom_minimum_size = Vector2(500, 350)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -250.0
|
||||
offset_top = -200.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 150.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("1_fdlfp")
|
||||
region_rect = Rect2(1, 35, 86, 53)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 35
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 32
|
||||
|
||||
[node name="Part_1" type="NinePatchRect" parent="BG"]
|
||||
custom_minimum_size = Vector2(500, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -250.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 44.0
|
||||
grow_horizontal = 2
|
||||
texture = ExtResource("1_fdlfp")
|
||||
region_rect = Rect2(1, 27, 86, 8)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 7
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Title" type="Label" parent="BG/Part_1"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -34.5
|
||||
offset_top = -18.0
|
||||
offset_right = 34.5
|
||||
offset_bottom = 18.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 27
|
||||
text = "新项目"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="Part_2" type="Control" parent="BG"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -20.0
|
||||
offset_top = 34.0
|
||||
offset_right = 20.0
|
||||
offset_bottom = 53.0
|
||||
grow_horizontal = 2
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="BG/Part_2"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -24.0
|
||||
offset_top = 5.0
|
||||
offset_right = 208.0
|
||||
offset_bottom = 39.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="Label" type="Label" parent="BG/Part_2/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 24
|
||||
text = "预算"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Button" type="Button" parent="BG/Part_2/HBoxContainer"]
|
||||
custom_minimum_size = Vector2(180, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_disabled_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_hover_pressed_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_hover_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_focus_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_pressed_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_xfbvu")
|
||||
theme_override_styles/disabled = SubResource("StyleBoxEmpty_nckjb")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxEmpty_6r1e0")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_at31c")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_qrj6y")
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_v0qi7")
|
||||
text = "500"
|
||||
icon = ExtResource("2_1p8wx")
|
||||
flat = true
|
||||
alignment = 2
|
||||
icon_alignment = 2
|
||||
|
||||
[node name="Part_3" type="NinePatchRect" parent="BG"]
|
||||
custom_minimum_size = Vector2(440, 200)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -220.0
|
||||
offset_top = -91.0
|
||||
offset_right = 220.0
|
||||
offset_bottom = 131.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("1_fdlfp")
|
||||
region_rect = Rect2(92, 38, 76, 34)
|
||||
patch_margin_left = 2
|
||||
patch_margin_top = 33
|
||||
patch_margin_right = 2
|
||||
patch_margin_bottom = 33
|
||||
|
||||
[node name="BG" type="NinePatchRect" parent="BG/Part_3"]
|
||||
custom_minimum_size = Vector2(440, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 7
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -220.0
|
||||
offset_top = -127.0
|
||||
offset_right = 220.0
|
||||
offset_bottom = 2.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
texture = ExtResource("1_fdlfp")
|
||||
region_rect = Rect2(100, 95, 240, 75)
|
||||
|
||||
[node name="Select_List" type="GridContainer" parent="BG/Part_3"]
|
||||
custom_minimum_size = Vector2(320, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -180.0
|
||||
offset_top = 7.0
|
||||
offset_right = 180.0
|
||||
offset_bottom = 179.0
|
||||
grow_horizontal = 2
|
||||
size_flags_horizontal = 4
|
||||
theme_override_constants/h_separation = 0
|
||||
columns = 2
|
||||
|
||||
[node name="1_left" type="NinePatchRect" parent="BG/Part_3/Select_List"]
|
||||
custom_minimum_size = Vector2(140, 40)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
texture = ExtResource("1_fdlfp")
|
||||
region_rect = Rect2(1, 95, 36, 24)
|
||||
patch_margin_left = 7
|
||||
patch_margin_top = 6
|
||||
patch_margin_right = 2
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Label" type="Label" parent="BG/Part_3/Select_List/1_left"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -60.0
|
||||
offset_top = -12.0
|
||||
offset_right = 60.0
|
||||
offset_bottom = 24.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
text = "平台"
|
||||
label_settings = ExtResource("3_n0vbh")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="1_right" type="NinePatchRect" parent="BG/Part_3/Select_List"]
|
||||
custom_minimum_size = Vector2(220, 40)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
texture = ExtResource("1_fdlfp")
|
||||
region_rect = Rect2(38, 95, 50, 24)
|
||||
patch_margin_top = 6
|
||||
patch_margin_right = 6
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Button" type="Button" parent="BG/Part_3/Select_List/1_right"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -70.0
|
||||
offset_top = -17.5
|
||||
offset_right = 70.0
|
||||
offset_bottom = 17.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_focus_color = Color(0, 0, 0, 1)
|
||||
theme_override_fonts/font = ExtResource("4_fdt2j")
|
||||
theme_override_font_sizes/font_size = 18
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_kctqw")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxFlat_ibc02")
|
||||
theme_override_styles/hover = SubResource("StyleBoxFlat_bd6ki")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxFlat_vhs2i")
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_uiuum")
|
||||
text = "Steam & Epic"
|
||||
|
||||
[node name="2_left" type="NinePatchRect" parent="BG/Part_3/Select_List"]
|
||||
custom_minimum_size = Vector2(140, 40)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
texture = ExtResource("1_fdlfp")
|
||||
region_rect = Rect2(1, 95, 36, 24)
|
||||
patch_margin_left = 7
|
||||
patch_margin_top = 6
|
||||
patch_margin_right = 2
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Label" type="Label" parent="BG/Part_3/Select_List/2_left"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -60.0
|
||||
offset_top = -12.0
|
||||
offset_right = 60.0
|
||||
offset_bottom = 24.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
text = "玩法"
|
||||
label_settings = ExtResource("3_n0vbh")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="2_right" type="NinePatchRect" parent="BG/Part_3/Select_List"]
|
||||
custom_minimum_size = Vector2(220, 40)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
texture = ExtResource("1_fdlfp")
|
||||
region_rect = Rect2(38, 95, 50, 24)
|
||||
patch_margin_top = 6
|
||||
patch_margin_right = 6
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Button" type="Button" parent="BG/Part_3/Select_List/2_right"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -70.0
|
||||
offset_top = -17.5
|
||||
offset_right = 70.0
|
||||
offset_bottom = 17.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_focus_color = Color(0, 0, 0, 1)
|
||||
theme_override_fonts/font = ExtResource("4_fdt2j")
|
||||
theme_override_font_sizes/font_size = 18
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_bq7yg")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxFlat_ibc02")
|
||||
theme_override_styles/hover = SubResource("StyleBoxFlat_bd6ki")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxFlat_vhs2i")
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_uiuum")
|
||||
text = "休闲放置"
|
||||
|
||||
[node name="3_left" type="NinePatchRect" parent="BG/Part_3/Select_List"]
|
||||
custom_minimum_size = Vector2(140, 40)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
texture = ExtResource("1_fdlfp")
|
||||
region_rect = Rect2(1, 95, 36, 24)
|
||||
patch_margin_left = 7
|
||||
patch_margin_top = 6
|
||||
patch_margin_right = 2
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Label" type="Label" parent="BG/Part_3/Select_List/3_left"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -60.0
|
||||
offset_top = -12.0
|
||||
offset_right = 60.0
|
||||
offset_bottom = 24.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
text = "题材"
|
||||
label_settings = ExtResource("3_n0vbh")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="3_right" type="NinePatchRect" parent="BG/Part_3/Select_List"]
|
||||
custom_minimum_size = Vector2(220, 40)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
texture = ExtResource("1_fdlfp")
|
||||
region_rect = Rect2(38, 95, 50, 24)
|
||||
patch_margin_top = 6
|
||||
patch_margin_right = 6
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Button" type="Button" parent="BG/Part_3/Select_List/3_right"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -70.0
|
||||
offset_top = -17.5
|
||||
offset_right = 70.0
|
||||
offset_bottom = 17.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_focus_color = Color(0, 0, 0, 1)
|
||||
theme_override_fonts/font = ExtResource("4_fdt2j")
|
||||
theme_override_font_sizes/font_size = 18
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_ej27o")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxFlat_ibc02")
|
||||
theme_override_styles/hover = SubResource("StyleBoxFlat_bd6ki")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxFlat_vhs2i")
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_uiuum")
|
||||
text = "古装仙侠"
|
||||
|
||||
[node name="4_left" type="NinePatchRect" parent="BG/Part_3/Select_List"]
|
||||
custom_minimum_size = Vector2(140, 40)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
texture = ExtResource("1_fdlfp")
|
||||
region_rect = Rect2(1, 95, 36, 24)
|
||||
patch_margin_left = 7
|
||||
patch_margin_top = 6
|
||||
patch_margin_right = 2
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Label" type="Label" parent="BG/Part_3/Select_List/4_left"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -60.0
|
||||
offset_top = -12.0
|
||||
offset_right = 60.0
|
||||
offset_bottom = 24.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
text = "开发策略"
|
||||
label_settings = ExtResource("3_n0vbh")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="4_right" type="NinePatchRect" parent="BG/Part_3/Select_List"]
|
||||
custom_minimum_size = Vector2(220, 40)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
texture = ExtResource("1_fdlfp")
|
||||
region_rect = Rect2(38, 95, 50, 24)
|
||||
patch_margin_top = 6
|
||||
patch_margin_right = 6
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Button" type="Button" parent="BG/Part_3/Select_List/4_right"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -70.0
|
||||
offset_top = -17.5
|
||||
offset_right = 70.0
|
||||
offset_bottom = 17.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_focus_color = Color(0, 0, 0, 1)
|
||||
theme_override_fonts/font = ExtResource("4_fdt2j")
|
||||
theme_override_font_sizes/font_size = 18
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_qo358")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxFlat_ibc02")
|
||||
theme_override_styles/hover = SubResource("StyleBoxFlat_bd6ki")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxFlat_vhs2i")
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_uiuum")
|
||||
text = "普通开发"
|
||||
|
||||
[node name="Confirm" type="Button" parent="BG"]
|
||||
custom_minimum_size = Vector2(70, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -25.0
|
||||
offset_top = 131.0
|
||||
offset_right = 25.0
|
||||
offset_bottom = 174.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme = ExtResource("5_edtgu")
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_focus_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 23
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_6xfhm")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxFlat_k3c3w")
|
||||
theme_override_styles/hover = SubResource("StyleBoxFlat_3etuv")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_e0qho")
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_qljg5")
|
||||
text = "确定"
|
||||
256
UI/popup/task_development/main_plan/platform/platform.gd
Normal file
256
UI/popup/task_development/main_plan/platform/platform.gd
Normal file
@ -0,0 +1,256 @@
|
||||
extends UIPage
|
||||
|
||||
# References to UI elements
|
||||
@onready var title_label = $BG/Title/Title
|
||||
@onready var name_label = $BG/Option/Name
|
||||
@onready var icon_rect = $BG/Option/Info/Icon
|
||||
@onready var info1_label = $BG/Option/Info/Info_List_1/Info_1/info # 制造商 (Maker)
|
||||
@onready var info2_label = $BG/Option/Info/Info_List_1/Info_2/info # 发售 (Sales)
|
||||
@onready var info3_label = $BG/Option/Info/Info_List_1/Info_3/info # 市场占比 (Market_share)
|
||||
@onready var info4_label = $BG/Option/Info/Info_List_2/info_4/info # 开发费用 (Cost)
|
||||
# @onready var info5_label = $BG/Option/Info/Info_List_2/info_5/info # 开发次数 - 暂不处理,数据源未知
|
||||
|
||||
@onready var prev_button = $BG/Title/previous/Button
|
||||
@onready var next_button = $BG/Title/next/Button
|
||||
@onready var confirm_button = $BG/Confirm
|
||||
|
||||
# Internal state
|
||||
var enabled_platform_keys: Array[String] = [] # Store keys (names) of enabled platforms
|
||||
var current_platform_index: int = -1 # Index in the enabled_platform_keys array
|
||||
|
||||
const PLATFORM_ICON_PATH = "res://UI/popup/task_development/main_plan/platform/"
|
||||
# --- 新增:用于存储从 GameState 获取的平台数据 ---
|
||||
var _platforms_data: Dictionary = {}
|
||||
|
||||
func _ready():
|
||||
super._ready() # 调用父类的 _ready() (如果 UIPage 中有 _ready() 逻辑)
|
||||
add_to_group(str(name)) # 保持不变
|
||||
|
||||
# Connect button signals (保持不变)
|
||||
if prev_button:
|
||||
if not prev_button.pressed.is_connected(_on_previous_pressed):
|
||||
prev_button.pressed.connect(_on_previous_pressed)
|
||||
if next_button:
|
||||
if not next_button.pressed.is_connected(_on_next_pressed):
|
||||
next_button.pressed.connect(_on_next_pressed)
|
||||
if confirm_button:
|
||||
if not confirm_button.pressed.is_connected(_on_confirm_pressed):
|
||||
confirm_button.pressed.connect(_on_confirm_pressed)
|
||||
|
||||
# Connect visibility changed signal (保持不变)
|
||||
if not is_connected("visibility_changed", _on_visibility_changed):
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
|
||||
# Initial call if already visible on ready (保持不变)
|
||||
if is_visible_in_tree():
|
||||
reset_display()
|
||||
|
||||
|
||||
# Visibility Change Handler (保持不变)
|
||||
func _on_visibility_changed():
|
||||
if is_visible_in_tree():
|
||||
reset_display()
|
||||
|
||||
# 重置显示状态,在窗口可见时调用
|
||||
func reset_display():
|
||||
print("Platform: Resetting display state.")
|
||||
# 1. 加载并过滤平台数据
|
||||
_load_and_filter_platforms() # 这会更新 _platforms_data 和 enabled_platform_keys
|
||||
|
||||
# 2. 检查是否有可用的平台
|
||||
if enabled_platform_keys.is_empty():
|
||||
print("Platform: No enabled platforms found during reset.")
|
||||
current_platform_index = -1
|
||||
_display_current_platform() # 显示 "无可用平台" 状态
|
||||
return
|
||||
|
||||
# 3. 获取主任务数据中当前已选择的平台 Key
|
||||
# 假设 get_main_data("键名", "默认值") 是 UIPage 基类或全局提供的方法,
|
||||
# 用于获取与 task_development.gd 中 task_info["平台"] 对应的值。
|
||||
var current_main_task_platform = ""
|
||||
if has_method("get_main_data"): # 检查方法是否存在以避免错误
|
||||
current_main_task_platform = get_main_data("平台", "")
|
||||
else:
|
||||
push_error("Platform: 'get_main_data' method not found. Cannot retrieve current platform from main task data.")
|
||||
# 作为后备,可以尝试默认第一个,或者保持之前的 GameState 逻辑(如果还需要)
|
||||
# 这里我们假设如果 get_main_data 不可用,则无法确定上次选择,行为类似首次打开
|
||||
current_main_task_platform = "" # 明确设置为空,将导致默认选中第一个
|
||||
|
||||
# 4. 查找主任务数据中的平台 Key 在当前可用列表中的索引
|
||||
if not current_main_task_platform.is_empty():
|
||||
var found_index = enabled_platform_keys.find(current_main_task_platform)
|
||||
if found_index != -1:
|
||||
# 5. 如果找到,并且该平台仍然可用,则更新当前索引
|
||||
current_platform_index = found_index
|
||||
print("Platform: Defaulting to platform '%s' from main task data (found at index %d)." % [current_main_task_platform, found_index])
|
||||
else:
|
||||
# 6. 如果在主任务数据中记录的平台 Key 在当前启用的平台列表中找不到
|
||||
# (例如,该平台可能已被禁用或数据不一致),则默认使用第一个可用的平台。
|
||||
print("Platform: Platform '%s' (from main task data) not found in current enabled list. Defaulting to index 0." % current_main_task_platform)
|
||||
current_platform_index = 0 # 确保至少有一个有效索引,如果 enabled_platform_keys 不为空
|
||||
else:
|
||||
# 7. 如果主任务数据中没有记录平台选择 (例如首次配置),则默认使用第一个可用的平台。
|
||||
print("Platform: No platform selection found in main task data for key '平台'. Defaulting to index 0.")
|
||||
current_platform_index = 0 # 确保至少有一个有效索引,如果 enabled_platform_keys 不为空
|
||||
|
||||
# 8. 更新显示
|
||||
# (在步骤 2 中,如果 enabled_platform_keys 为空,current_platform_index 会是 -1,_display_current_platform 会处理这种情况)
|
||||
_display_current_platform()
|
||||
|
||||
# 从 GameState 获取平台数据并筛选出启用的平台
|
||||
func _load_and_filter_platforms():
|
||||
enabled_platform_keys.clear()
|
||||
_platforms_data = {} # 清空旧数据
|
||||
|
||||
if not GameState:
|
||||
push_error("GameState not available in _load_and_filter_platforms.")
|
||||
return
|
||||
|
||||
# --- 修改:从 GameState 获取 task_development 数据 ---
|
||||
var task_dev_data = GameState.get_value("task_development", {})
|
||||
if task_dev_data.is_empty():
|
||||
printerr("Platform: Failed to get 'task_development' data from GameState.")
|
||||
return
|
||||
|
||||
# --- 修改:获取 platforms 字典 ---
|
||||
var all_platforms = task_dev_data.get("platforms", {})
|
||||
if all_platforms.is_empty():
|
||||
print("Platform: 'platforms' data in GameState is empty.")
|
||||
return
|
||||
|
||||
# --- 修改:将获取到的平台数据存储到内部变量 ---
|
||||
_platforms_data = all_platforms
|
||||
|
||||
# 遍历平台数据,筛选出启用的平台 Key
|
||||
for platform_key in _platforms_data:
|
||||
var platform_info = _platforms_data[platform_key]
|
||||
# 确保 platform_info 是字典并且 'enabled' 键存在且为 true
|
||||
if typeof(platform_info) == TYPE_DICTIONARY and platform_info.get("enabled", false) == true:
|
||||
enabled_platform_keys.append(platform_key)
|
||||
|
||||
# 可选:按键名排序,保持一致性
|
||||
#if not enabled_platform_keys.is_empty():
|
||||
#enabled_platform_keys.sort() # 简单字符串排序
|
||||
## current_platform_index 会在 reset_display 中设置
|
||||
#else:
|
||||
#print("Platform: No enabled platforms found.")
|
||||
#current_platform_index = -1 # 明确设置无可用平台
|
||||
|
||||
# 根据 current_platform_index 更新 UI 显示
|
||||
func _display_current_platform():
|
||||
# 处理无可用平台或索引无效的情况
|
||||
if current_platform_index < 0 or current_platform_index >= enabled_platform_keys.size():
|
||||
title_label.text = "游戏平台"
|
||||
name_label.text = "无可用平台"
|
||||
if icon_rect: icon_rect.texture = null
|
||||
if info1_label: info1_label.text = "-" # Maker
|
||||
if info2_label: info2_label.text = "-" # Sales
|
||||
if info3_label: info3_label.text = "-" # Market_share
|
||||
if info4_label: info4_label.text = "-" # Cost
|
||||
if prev_button: prev_button.disabled = true
|
||||
if next_button: next_button.disabled = true
|
||||
if confirm_button: confirm_button.disabled = true
|
||||
return
|
||||
|
||||
# --- 如果有有效平台 ---
|
||||
if confirm_button: confirm_button.disabled = false # 启用确认按钮
|
||||
|
||||
# 更新标题
|
||||
var display_index = current_platform_index + 1
|
||||
var total_count = enabled_platform_keys.size()
|
||||
title_label.text = "游戏平台 %d/%d" % [display_index, total_count]
|
||||
|
||||
# 获取当前平台的 Key 和数据
|
||||
var platform_key = enabled_platform_keys[current_platform_index]
|
||||
|
||||
# --- 从内部缓存 _platforms_data 获取平台信息 ---
|
||||
if not _platforms_data.has(platform_key):
|
||||
push_error("Current platform key '%s' not found in cached _platforms_data!" % platform_key)
|
||||
name_label.text = "错误:数据丢失"
|
||||
# ... 清空其他信息 ...
|
||||
return
|
||||
|
||||
var platform_info = _platforms_data[platform_key]
|
||||
|
||||
# 更新平台名称
|
||||
name_label.text = platform_key
|
||||
|
||||
# --- 修改:从 platform_info 读取所有需要的信息,数值转为整数显示 ---
|
||||
# 使用 .get(key, default) 确保安全访问
|
||||
|
||||
# 制造商 (Maker) - 通常是字符串,保持不变
|
||||
info1_label.text = platform_info.get("Maker", "-")
|
||||
|
||||
# 发售 (Sales) - 转换为整数显示
|
||||
var sales_value = platform_info.get("Sales", null)
|
||||
if typeof(sales_value) == TYPE_INT or typeof(sales_value) == TYPE_FLOAT:
|
||||
info2_label.text = str(int(sales_value)) # 转换为整数再转字符串
|
||||
else:
|
||||
info2_label.text = "-" # 如果不是数字或不存在,显示 "-"
|
||||
|
||||
# 市场占比 (Market_share) - 转换为整数显示
|
||||
var market_share_value = platform_info.get("Market_share", null)
|
||||
if typeof(market_share_value) == TYPE_INT or typeof(market_share_value) == TYPE_FLOAT:
|
||||
info3_label.text = str(int(market_share_value)) # 转换为整数再转字符串
|
||||
else:
|
||||
info3_label.text = "-"
|
||||
|
||||
# 开发费用 (Cost) - 转换为整数显示
|
||||
var cost_value = platform_info.get("Cost", null)
|
||||
if typeof(cost_value) == TYPE_INT or typeof(cost_value) == TYPE_FLOAT:
|
||||
info4_label.text = str(int(cost_value)) # 转换为整数再转字符串
|
||||
else:
|
||||
info4_label.text = "-"
|
||||
|
||||
# info5 (开发次数) 暂不处理
|
||||
|
||||
# 更新图标 (逻辑不变)
|
||||
var icon_name = platform_info.get("Icon", "")
|
||||
if not icon_name.is_empty():
|
||||
var icon_path = PLATFORM_ICON_PATH + icon_name + ".png"
|
||||
if ResourceLoader.exists(icon_path):
|
||||
icon_rect.texture = ResourceLoader.load(icon_path)
|
||||
else:
|
||||
push_error("Failed to load platform icon: " + icon_path)
|
||||
icon_rect.texture = null
|
||||
else:
|
||||
print("Platform icon name is empty for key: ", platform_key)
|
||||
icon_rect.texture = null
|
||||
|
||||
# 更新导航按钮状态 (逻辑不变)
|
||||
var can_navigate = enabled_platform_keys.size() > 1
|
||||
if prev_button: prev_button.disabled = not can_navigate
|
||||
if next_button: next_button.disabled = not can_navigate
|
||||
|
||||
|
||||
# --- _on_previous_pressed (逻辑不变) ---
|
||||
func _on_previous_pressed():
|
||||
if enabled_platform_keys.size() > 1:
|
||||
current_platform_index -= 1
|
||||
if current_platform_index < 0:
|
||||
current_platform_index = enabled_platform_keys.size() - 1
|
||||
_display_current_platform()
|
||||
|
||||
|
||||
# --- _on_next_pressed (逻辑不变) ---
|
||||
func _on_next_pressed():
|
||||
if enabled_platform_keys.size() > 1:
|
||||
current_platform_index += 1
|
||||
if current_platform_index >= enabled_platform_keys.size():
|
||||
current_platform_index = 0
|
||||
_display_current_platform()
|
||||
|
||||
|
||||
# --- _on_confirm_pressed ---
|
||||
# 处理确认选择
|
||||
func _on_confirm_pressed():
|
||||
if current_platform_index != -1 and current_platform_index < enabled_platform_keys.size():
|
||||
# 1. 获取选中的平台 Key
|
||||
var selected_platform_key = enabled_platform_keys[current_platform_index]
|
||||
|
||||
# 2. 获取父节点 (task_development)
|
||||
set_main_data("平台", selected_platform_key)
|
||||
go_next()
|
||||
else:
|
||||
# 处理没有有效平台被选中的情况
|
||||
print("Platform: No valid platform selected to confirm.")
|
||||
@ -0,0 +1 @@
|
||||
uid://4lkw1wtwbul8
|
||||
497
UI/popup/task_development/main_plan/platform/platform.tscn
Normal file
497
UI/popup/task_development/main_plan/platform/platform.tscn
Normal file
@ -0,0 +1,497 @@
|
||||
[gd_scene load_steps=29 format=3 uid="uid://hidwgnr45bw7"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://4lkw1wtwbul8" path="res://UI/popup/task_development/main_plan/platform/platform.gd" id="1_ne7vr"]
|
||||
[ext_resource type="Texture2D" uid="uid://pucudatqrcrq" path="res://UI/popup/popup_bg_1.png" id="1_uw2bc"]
|
||||
[ext_resource type="Texture2D" uid="uid://dgcugleiv7sfw" path="res://UI/popup/task_development/arrow.png" id="2_ne7vr"]
|
||||
[ext_resource type="Texture2D" uid="uid://b2n1f22bd06tc" path="res://UI/popup/task_development/main_plan/platform/platform_1.png" id="3_kmbuj"]
|
||||
[ext_resource type="LabelSettings" uid="uid://qcn0aduvrgvw" path="res://UI/tres/task_development_platform_label_settings.tres" id="4_83vap"]
|
||||
[ext_resource type="Theme" uid="uid://bau80ps6kx783" path="res://UI/tres/Bottom_Info_button_theme.tres" id="5_lyw5j"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_6a8uh"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_bu5lv"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_mue51"]
|
||||
|
||||
[sub_resource type="Animation" id="Animation_bu5lv"]
|
||||
length = 0.001
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Title/previous:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [Vector2(9, 7)]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_6a8uh"]
|
||||
resource_name = "base"
|
||||
length = 0.6
|
||||
loop_mode = 1
|
||||
step = 0.2
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Title/previous:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.2, 0.4, 0.6),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [Vector2(16, 7), Vector2(12, 7), Vector2(9, 7), Vector2(16, 7)]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_mue51"]
|
||||
_data = {
|
||||
&"RESET": SubResource("Animation_bu5lv"),
|
||||
&"base": SubResource("Animation_6a8uh")
|
||||
}
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_wpgbx"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_r6b7x"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_hsiy4"]
|
||||
|
||||
[sub_resource type="Animation" id="Animation_wpgbx"]
|
||||
length = 0.001
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath(".:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [Vector2(461, 7)]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_mue51"]
|
||||
resource_name = "base"
|
||||
length = 0.6
|
||||
loop_mode = 1
|
||||
step = 0.2
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath(".:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.2, 0.4, 0.6),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [Vector2(455, 7), Vector2(458, 7), Vector2(461, 7), Vector2(455, 7)]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_r6b7x"]
|
||||
_data = {
|
||||
&"RESET": SubResource("Animation_wpgbx"),
|
||||
&"base": SubResource("Animation_mue51")
|
||||
}
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_nckjb"]
|
||||
bg_color = Color(0.913725, 0.913725, 0.913725, 0.913725)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_6r1e0"]
|
||||
bg_color = Color(0.913725, 0.913725, 0.913725, 0.913725)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_at31c"]
|
||||
bg_color = Color(0.913725, 0.913725, 0.913725, 0.913725)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_qrj6y"]
|
||||
bg_color = Color(0.913725, 0.913725, 0.913725, 0.913725)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_v0qi7"]
|
||||
bg_color = Color(0.913725, 0.913725, 0.913725, 0.913725)
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_rl25l"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_tndxe"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_xx8ge"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ep6fu"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ci4su"]
|
||||
|
||||
[node name="platform" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_ne7vr")
|
||||
|
||||
[node name="BG" type="NinePatchRect" parent="."]
|
||||
custom_minimum_size = Vector2(500, 350)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -250.0
|
||||
offset_top = -200.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 150.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("1_uw2bc")
|
||||
region_rect = Rect2(1, 35, 86, 53)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 35
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 32
|
||||
|
||||
[node name="Title" type="NinePatchRect" parent="BG"]
|
||||
custom_minimum_size = Vector2(500, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -250.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 44.0
|
||||
grow_horizontal = 2
|
||||
texture = ExtResource("1_uw2bc")
|
||||
region_rect = Rect2(1, 27, 86, 8)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 7
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Title" type="Label" parent="BG/Title"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -34.5
|
||||
offset_top = -18.0
|
||||
offset_right = 34.5
|
||||
offset_bottom = 18.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 27
|
||||
text = "游戏平台"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="previous" type="NinePatchRect" parent="BG/Title"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 4
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 9.0
|
||||
offset_top = -15.0
|
||||
offset_right = 39.0
|
||||
offset_bottom = 15.0
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("2_ne7vr")
|
||||
region_rect = Rect2(0, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="BG/Title/previous"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_6a8uh")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_bu5lv")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_mue51")
|
||||
flat = true
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="BG/Title/previous"]
|
||||
root_node = NodePath("../../..")
|
||||
libraries = {
|
||||
&"": SubResource("AnimationLibrary_mue51")
|
||||
}
|
||||
autoplay = "base"
|
||||
|
||||
[node name="next" type="NinePatchRect" parent="BG/Title"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 6
|
||||
anchor_left = 1.0
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -39.0
|
||||
offset_top = -15.0
|
||||
offset_right = -9.0
|
||||
offset_bottom = 15.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("2_ne7vr")
|
||||
region_rect = Rect2(6, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="BG/Title/next"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_wpgbx")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_r6b7x")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_hsiy4")
|
||||
flat = true
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="BG/Title/next"]
|
||||
libraries = {
|
||||
&"": SubResource("AnimationLibrary_r6b7x")
|
||||
}
|
||||
autoplay = "base"
|
||||
|
||||
[node name="Option" type="Control" parent="BG"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="Name" type="Label" parent="BG/Option"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -75.0
|
||||
offset_top = -129.5
|
||||
offset_right = 75.0
|
||||
offset_bottom = -95.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 24
|
||||
text = "台式 & 笔记本"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Info" type="NinePatchRect" parent="BG/Option"]
|
||||
custom_minimum_size = Vector2(440, 200)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -220.0
|
||||
offset_top = -92.0
|
||||
offset_right = 220.0
|
||||
offset_bottom = 130.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("1_uw2bc")
|
||||
region_rect = Rect2(92, 38, 76, 34)
|
||||
patch_margin_left = 2
|
||||
patch_margin_top = 33
|
||||
patch_margin_right = 2
|
||||
patch_margin_bottom = 33
|
||||
|
||||
[node name="Icon" type="NinePatchRect" parent="BG/Option/Info"]
|
||||
custom_minimum_size = Vector2(144, 144)
|
||||
layout_mode = 1
|
||||
anchors_preset = 4
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_top = -108.0
|
||||
offset_right = 190.0
|
||||
offset_bottom = 82.0
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("3_kmbuj")
|
||||
|
||||
[node name="Info_List_1" type="GridContainer" parent="BG/Option/Info"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 6
|
||||
anchor_left = 1.0
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -225.0
|
||||
offset_top = -82.0
|
||||
offset_right = -9.0
|
||||
offset_bottom = 19.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 2
|
||||
theme_override_constants/v_separation = 7
|
||||
|
||||
[node name="Info_1" type="HBoxContainer" parent="BG/Option/Info/Info_List_1"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="start" type="Label" parent="BG/Option/Info/Info_List_1/Info_1"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_nckjb")
|
||||
text = " "
|
||||
label_settings = ExtResource("4_83vap")
|
||||
|
||||
[node name="title" type="Label" parent="BG/Option/Info/Info_List_1/Info_1"]
|
||||
custom_minimum_size = Vector2(90, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_nckjb")
|
||||
text = "制造商"
|
||||
label_settings = ExtResource("4_83vap")
|
||||
|
||||
[node name="info" type="Label" parent="BG/Option/Info/Info_List_1/Info_1"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 2
|
||||
text = "不定"
|
||||
label_settings = ExtResource("4_83vap")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Info_2" type="HBoxContainer" parent="BG/Option/Info/Info_List_1"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="start" type="Label" parent="BG/Option/Info/Info_List_1/Info_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_nckjb")
|
||||
text = " "
|
||||
label_settings = ExtResource("4_83vap")
|
||||
|
||||
[node name="title" type="Label" parent="BG/Option/Info/Info_List_1/Info_2"]
|
||||
custom_minimum_size = Vector2(90, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_6r1e0")
|
||||
text = "发售"
|
||||
label_settings = ExtResource("4_83vap")
|
||||
|
||||
[node name="info" type="Label" parent="BG/Option/Info/Info_List_1/Info_2"]
|
||||
custom_minimum_size = Vector2(60, 0)
|
||||
layout_mode = 2
|
||||
text = "50"
|
||||
label_settings = ExtResource("4_83vap")
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="unit" type="Label" parent="BG/Option/Info/Info_List_1/Info_2"]
|
||||
layout_mode = 2
|
||||
text = "万台"
|
||||
label_settings = ExtResource("4_83vap")
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Info_3" type="HBoxContainer" parent="BG/Option/Info/Info_List_1"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="start" type="Label" parent="BG/Option/Info/Info_List_1/Info_3"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_nckjb")
|
||||
text = " "
|
||||
label_settings = ExtResource("4_83vap")
|
||||
|
||||
[node name="title" type="Label" parent="BG/Option/Info/Info_List_1/Info_3"]
|
||||
custom_minimum_size = Vector2(90, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_at31c")
|
||||
text = "市场占比"
|
||||
label_settings = ExtResource("4_83vap")
|
||||
|
||||
[node name="info" type="Label" parent="BG/Option/Info/Info_List_1/Info_3"]
|
||||
custom_minimum_size = Vector2(60, 0)
|
||||
layout_mode = 2
|
||||
text = "38"
|
||||
label_settings = ExtResource("4_83vap")
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="unit" type="Label" parent="BG/Option/Info/Info_List_1/Info_3"]
|
||||
layout_mode = 2
|
||||
text = "%"
|
||||
label_settings = ExtResource("4_83vap")
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Info_List_2" type="HBoxContainer" parent="BG/Option/Info"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 7
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -191.5
|
||||
offset_top = -38.0
|
||||
offset_right = 191.5
|
||||
offset_bottom = -10.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
alignment = 1
|
||||
|
||||
[node name="info_4" type="HBoxContainer" parent="BG/Option/Info/Info_List_2"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="title" type="Label" parent="BG/Option/Info/Info_List_2/info_4"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_qrj6y")
|
||||
text = "开发费用"
|
||||
label_settings = ExtResource("4_83vap")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info" type="Label" parent="BG/Option/Info/Info_List_2/info_4"]
|
||||
custom_minimum_size = Vector2(70, 0)
|
||||
layout_mode = 2
|
||||
text = "500"
|
||||
label_settings = ExtResource("4_83vap")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info_5" type="HBoxContainer" parent="BG/Option/Info/Info_List_2"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="title" type="Label" parent="BG/Option/Info/Info_List_2/info_5"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_v0qi7")
|
||||
text = "开发次数"
|
||||
label_settings = ExtResource("4_83vap")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info" type="Label" parent="BG/Option/Info/Info_List_2/info_5"]
|
||||
custom_minimum_size = Vector2(30, 0)
|
||||
layout_mode = 2
|
||||
text = "0"
|
||||
label_settings = ExtResource("4_83vap")
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="unit" type="Label" parent="BG/Option/Info/Info_List_2/info_5"]
|
||||
layout_mode = 2
|
||||
text = "次"
|
||||
label_settings = ExtResource("4_83vap")
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Confirm" type="Button" parent="BG"]
|
||||
custom_minimum_size = Vector2(70, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 7
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -35.0
|
||||
offset_top = -43.0
|
||||
offset_right = 35.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
theme = ExtResource("5_lyw5j")
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_focus_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 23
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_rl25l")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxFlat_tndxe")
|
||||
theme_override_styles/hover = SubResource("StyleBoxFlat_xx8ge")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_ep6fu")
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_ci4su")
|
||||
text = "确定"
|
||||
BIN
UI/popup/task_development/main_plan/platform/platform_1.png
Normal file
BIN
UI/popup/task_development/main_plan/platform/platform_1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b2n1f22bd06tc"
|
||||
path="res://.godot/imported/platform_1.png-cfa80f103262e4341156e5985a03ca68.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://UI/popup/task_development/main_plan/platform/platform_1.png"
|
||||
dest_files=["res://.godot/imported/platform_1.png-cfa80f103262e4341156e5985a03ca68.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
BIN
UI/popup/task_development/main_plan/platform/platform_2.png
Normal file
BIN
UI/popup/task_development/main_plan/platform/platform_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://c53cngwtsi5hb"
|
||||
path="res://.godot/imported/platform_2.png-83b257c4756ce323c8ad5870c81381f7.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://UI/popup/task_development/main_plan/platform/platform_2.png"
|
||||
dest_files=["res://.godot/imported/platform_2.png-83b257c4756ce323c8ad5870c81381f7.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
268
UI/popup/task_development/main_plan/strategy/strategy.gd
Normal file
268
UI/popup/task_development/main_plan/strategy/strategy.gd
Normal file
@ -0,0 +1,268 @@
|
||||
extends UIPage
|
||||
|
||||
# --- 节点引用 ---
|
||||
@onready var options_container: VBoxContainer = $BG/Option/Options/List_1
|
||||
@onready var explanation_label: Label = $BG/Option/Explaination
|
||||
|
||||
# --- 内部状态 ---
|
||||
var option_buttons: Array[Button] = [] # 存储选项按钮节点的数组
|
||||
var highlighted_button: Button = null # 当前逻辑上选中的按钮 (用于区分首次点击和确认点击)
|
||||
var current_strategy_data: Dictionary = {} # 存储从 GameState 获取的原始策略数据
|
||||
var initial_selection_key: String = "" # 由父节点传入的初始/当前选择的策略 Key (中文名)
|
||||
|
||||
# --- 初始化 ---
|
||||
func _ready() -> void:
|
||||
super._ready() # 调用父类的 _ready() (如果 UIPage 中有 _ready() 逻辑)
|
||||
add_to_group(str(name)) # 便于父节点或其他系统查找
|
||||
|
||||
# --- 获取按钮引用 ---
|
||||
option_buttons.clear()
|
||||
for child in options_container.get_children():
|
||||
if child is Button:
|
||||
option_buttons.append(child)
|
||||
# 断开旧连接以防万一 (虽然理论上 _ready 只执行一次)
|
||||
if child.is_connected("pressed", _on_option_button_pressed):
|
||||
child.disconnect("pressed", _on_option_button_pressed)
|
||||
|
||||
# --- 连接 GameState 通用值变化信号 ---
|
||||
# 用于响应策略数据可能的动态变化 (如解锁新策略)
|
||||
if GameState and not GameState.state_value_changed.is_connected(_on_game_state_value_changed):
|
||||
GameState.state_value_changed.connect(_on_game_state_value_changed)
|
||||
|
||||
# --- 连接 visibility_changed 信号 ---
|
||||
# 确保每次界面可见时都刷新列表内容
|
||||
if not is_connected("visibility_changed", _on_visibility_changed):
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
|
||||
# _update_strategy_list() 不再在 _ready 中调用,移至 _on_visibility_changed
|
||||
|
||||
# --- 父节点调用接口 ---
|
||||
# 由父节点 (task_development.gd) 在显示此弹窗前调用,传入当前的临时选择
|
||||
func set_initial_selection(strategy_key: String) -> void:
|
||||
initial_selection_key = strategy_key
|
||||
print("Strategy: Initial selection key set by parent: '", initial_selection_key, "'")
|
||||
# 注意:这里只存储值,实际的高亮逻辑仍在 _update_strategy_list 中处理
|
||||
|
||||
# --- 信号处理 ---
|
||||
|
||||
# 处理可见性变化的函数
|
||||
func _on_visibility_changed() -> void:
|
||||
print("Strategy: _on_visibility_changed called, visible = ", is_visible_in_tree())
|
||||
# 当节点变为可见时,更新列表并设置初始焦点
|
||||
if is_visible_in_tree():
|
||||
print("Strategy popup became visible. Updating list and setting focus...")
|
||||
# 确保在更新列表前,initial_selection_key 已被父节点设置
|
||||
_update_strategy_list()
|
||||
# else: # 可选:如果需要在隐藏时做清理,可以在这里添加逻辑
|
||||
# print("Strategy popup became hidden.")
|
||||
|
||||
# 当 GameState 的任何值发生变化时调用
|
||||
func _on_game_state_value_changed(key: String, new_value) -> void:
|
||||
# 检查是否是 task_development 数据发生了变化,这可能影响可用策略
|
||||
# 注意:这是一个比较宽泛的检查。如果 task_development 下其他不相关数据变化也会触发刷新。
|
||||
if key == "task_development":
|
||||
# 并且确保当前界面是可见的,避免在后台刷新不可见的UI
|
||||
if is_visible_in_tree():
|
||||
print("Strategy: Detected change in 'task_development', refreshing list...")
|
||||
# 重新执行列表更新,它会使用最新的 GameState 数据
|
||||
# 并尝试根据 initial_selection_key (由父节点设定,理论上不变) 恢复高亮
|
||||
_update_strategy_list()
|
||||
|
||||
# --- 核心 UI 更新逻辑 ---
|
||||
|
||||
# 更新策略列表UI的函数
|
||||
func _update_strategy_list() -> void:
|
||||
# 0. 重置界面逻辑状态 (清除上次的高亮和说明)
|
||||
_reset_highlight_state()
|
||||
|
||||
# 0b. 【修改】从 MainController 的共享数据中获取初始应选中的策略 Key
|
||||
# 使用键名 "开发策略"。如果未找到该键,默认为空字符串。
|
||||
# 这将覆盖之前可能通过 set_initial_selection 设置的值。
|
||||
initial_selection_key = get_main_data("开发策略", "") # <--- 从共享数据获取初始高亮项
|
||||
|
||||
if not initial_selection_key.is_empty():
|
||||
print("Strategy (_update_strategy_list): 从 get_main_data(\"开发策略\") 获取到初始选择 Key: '%s'" % initial_selection_key)
|
||||
else:
|
||||
print("Strategy (_update_strategy_list): 未从 get_main_data(\"开发策略\") 获取到初始选择 Key,或 Key 为空。")
|
||||
|
||||
|
||||
# 1. 从 GameState 获取最新的 task_development 数据
|
||||
if not GameState:
|
||||
printerr("Strategy: GameState not available during _update_strategy_list.")
|
||||
for button in option_buttons: button.visible = false
|
||||
explanation_label.text = "错误:无法访问游戏状态。"
|
||||
return
|
||||
|
||||
var task_dev_data: Dictionary = GameState.get_value("task_development", {})
|
||||
if task_dev_data.is_empty():
|
||||
printerr("Strategy: Failed to get 'task_development' data from GameState.")
|
||||
for button in option_buttons: button.visible = false
|
||||
explanation_label.text = "错误:无法获取开发数据。"
|
||||
return
|
||||
|
||||
# 提取策略子字典
|
||||
current_strategy_data = task_dev_data.get("strategies", {})
|
||||
if current_strategy_data.is_empty():
|
||||
printerr("Strategy: 'strategies' data not found or empty in task_development.")
|
||||
for button in option_buttons: button.visible = false
|
||||
explanation_label.text = "没有可用的开发策略。"
|
||||
return
|
||||
|
||||
# 2. 筛选出已启用的策略
|
||||
var enabled_strategies = []
|
||||
for strategy_name in current_strategy_data: # 遍历字典的键 (策略中文名)
|
||||
var details: Dictionary = current_strategy_data[strategy_name]
|
||||
# 确保 details 是字典并且 'enabled' 键存在且为 true
|
||||
if typeof(details) == TYPE_DICTIONARY and details.get("enabled", false) == true:
|
||||
enabled_strategies.append({"name": strategy_name, "details": details})
|
||||
|
||||
# 如果需要固定顺序,可以排序
|
||||
# enabled_strategies.sort_custom(func(a, b): return a["name"] < b["name"])
|
||||
|
||||
# 3. 填充按钮
|
||||
var strategy_index: int = 0
|
||||
var first_enabled_button: Button = null # 用于没有初始选择时的默认高亮
|
||||
|
||||
# --- 确保每次更新时正确设置按钮状态和信号连接 ---
|
||||
for button in option_buttons:
|
||||
button.visible = false
|
||||
button.disabled = true
|
||||
if button.is_connected("pressed", _on_option_button_pressed):
|
||||
button.disconnect("pressed", _on_option_button_pressed)
|
||||
if button.has_meta("strategy_name"):
|
||||
button.remove_meta("strategy_name")
|
||||
|
||||
while strategy_index < enabled_strategies.size() and strategy_index < option_buttons.size():
|
||||
var button: Button = option_buttons[strategy_index]
|
||||
var strategy_data: Dictionary = enabled_strategies[strategy_index]
|
||||
var strategy_name: String = strategy_data["name"]
|
||||
var strategy_details: Dictionary = strategy_data["details"]
|
||||
|
||||
var title_label: Label = button.find_child("Title", true, false) as Label
|
||||
var cost_label: Label = button.find_child("Cost", true, false) as Label
|
||||
|
||||
if title_label and cost_label:
|
||||
title_label.text = strategy_name
|
||||
var cost_value = strategy_details.get("Cost", null)
|
||||
if typeof(cost_value) == TYPE_FLOAT or typeof(cost_value) == TYPE_INT:
|
||||
var percentage: int = int(cost_value * 100)
|
||||
cost_label.text = "+%d%%" % percentage
|
||||
else:
|
||||
cost_label.text = "N/A"
|
||||
|
||||
button.set_meta("strategy_name", strategy_name)
|
||||
button.visible = true
|
||||
button.disabled = false
|
||||
button.pressed.connect(_on_option_button_pressed.bind(button))
|
||||
|
||||
if first_enabled_button == null:
|
||||
first_enabled_button = button
|
||||
else:
|
||||
printerr("Strategy: 在按钮 '%s' 下未找到 Title 或 Cost 标签。" % button.name)
|
||||
strategy_index += 1
|
||||
|
||||
# 4. 设置初始逻辑选中状态和焦点
|
||||
# (此部分逻辑不变,但现在 initial_selection_key 是从 get_main_data 获取的)
|
||||
# print("--- Updating Strategy List (Post GameState Load) ---") # Debugging
|
||||
# print("Initial selection key (potentially from get_main_data): '", initial_selection_key, "'") # Debugging
|
||||
var initial_highlight_button: Button = null
|
||||
|
||||
if not initial_selection_key.is_empty():
|
||||
# print("Searching for matching button for key: '", initial_selection_key, "'") # Debugging
|
||||
for button in option_buttons:
|
||||
if button.visible and not button.disabled:
|
||||
var meta_name = button.get_meta("strategy_name", "")
|
||||
# print(" Checking button: '", button.name, "' with meta: '", meta_name, "'") # Debugging
|
||||
if meta_name == initial_selection_key:
|
||||
# print(" Match found!: ", button.name) # Debugging
|
||||
initial_highlight_button = button
|
||||
break
|
||||
|
||||
if initial_highlight_button == null:
|
||||
# print("No match found for initial key or key was empty. Trying first enabled button.") # Debugging
|
||||
initial_highlight_button = first_enabled_button
|
||||
|
||||
if initial_highlight_button:
|
||||
# print("Button to initially highlight: ", initial_highlight_button.name) # Debugging
|
||||
_set_initial_highlight(initial_highlight_button)
|
||||
else:
|
||||
# print("No button available to highlight.") # Debugging
|
||||
explanation_label.text = "没有可用的开发策略。"
|
||||
# print("--- Finished Updating Strategy List (Post GameState Load) ---") # Debugging
|
||||
|
||||
|
||||
# --- 交互处理 ---
|
||||
|
||||
# 处理选项按钮点击事件的函数
|
||||
func _on_option_button_pressed(button_node: Button) -> void:
|
||||
# 从按钮元数据获取对应的策略名称
|
||||
var strategy_name: String = button_node.get_meta("strategy_name", "")
|
||||
if strategy_name.is_empty():
|
||||
printerr("Strategy: 无法从按钮 %s 获取 strategy_name 元数据。" % button_node.name)
|
||||
return
|
||||
|
||||
# 检查点击的按钮是否就是当前已逻辑高亮的按钮
|
||||
if button_node == highlighted_button:
|
||||
# --- 第二次点击 (确认选择) ---
|
||||
print("Strategy: Confirmed selection - ", strategy_name)
|
||||
|
||||
set_main_data("开发策略", strategy_name)
|
||||
go_next()
|
||||
|
||||
else:
|
||||
# --- 第一次点击 或 点击了不同的按钮 (更新逻辑选择和说明) ---
|
||||
print("Strategy: Logically selected - ", strategy_name)
|
||||
# 更新当前逻辑高亮的按钮引用
|
||||
highlighted_button = button_node
|
||||
|
||||
# 更新底部的说明文本
|
||||
# 确保 current_strategy_data 是最新的 (理论上 _update_strategy_list 刚更新过)
|
||||
if current_strategy_data.has(strategy_name):
|
||||
var details: Dictionary = current_strategy_data[strategy_name]
|
||||
explanation_label.text = details.get("Explaination", "暂无说明。") # 使用 .get 提供默认值
|
||||
else:
|
||||
# 如果因为某些原因数据不同步,显示错误
|
||||
explanation_label.text = "错误:找不到策略详情。"
|
||||
printerr("Strategy: Could not find details for strategy '", strategy_name, "' in current_strategy_data.")
|
||||
|
||||
# 注意:此时按钮的视觉焦点可能还未改变,依赖于 Button 主题的 focus 样式
|
||||
# _set_initial_highlight 内部会处理 grab_focus
|
||||
|
||||
# --- 辅助函数 ---
|
||||
|
||||
# (辅助函数) 重置界面逻辑高亮状态
|
||||
func _reset_highlight_state() -> void:
|
||||
highlighted_button = null # 清除逻辑高亮引用
|
||||
explanation_label.text = "" # 清空说明文本
|
||||
|
||||
# (辅助函数) 设置初始逻辑选中按钮并赋予焦点
|
||||
func _set_initial_highlight(button_to_highlight: Button) -> void:
|
||||
print("--- Setting Initial Highlight ---")
|
||||
if not is_instance_valid(button_to_highlight):
|
||||
printerr("Strategy: Invalid button passed to _set_initial_highlight.")
|
||||
return
|
||||
|
||||
print("Button received: ", button_to_highlight.name)
|
||||
# 设置逻辑高亮引用
|
||||
highlighted_button = button_to_highlight
|
||||
print("highlighted_button variable set to: ", highlighted_button.name)
|
||||
|
||||
# 更新说明文本
|
||||
var strategy_name = highlighted_button.get_meta("strategy_name", "")
|
||||
if not strategy_name.is_empty() and current_strategy_data.has(strategy_name):
|
||||
var details: Dictionary = current_strategy_data[strategy_name]
|
||||
explanation_label.text = details.get("Explaination", "暂无说明。")
|
||||
elif not strategy_name.is_empty():
|
||||
explanation_label.text = "错误:找不到策略详情。"
|
||||
printerr("Strategy: Could not find details for highlighted strategy '", strategy_name, "'")
|
||||
else:
|
||||
explanation_label.text = "错误:无法获取策略名称。" # 如果连元数据都没有
|
||||
|
||||
# 尝试让按钮获得实际输入焦点 (使用 call_deferred 确保在安全的时机执行)
|
||||
# 这会让按钮应用其主题中的 "focus" 样式
|
||||
if highlighted_button.is_inside_tree() and highlighted_button.visible and not highlighted_button.disabled:
|
||||
print("Attempting call_deferred('grab_focus') for: ", highlighted_button.name)
|
||||
highlighted_button.call_deferred("grab_focus")
|
||||
else:
|
||||
print("Button '%s' not valid, not in tree, hidden, or disabled. Cannot grab focus." % highlighted_button.name)
|
||||
print("--- Finished Setting Initial Highlight ---")
|
||||
@ -0,0 +1 @@
|
||||
uid://by3rdgo6jlbff
|
||||
361
UI/popup/task_development/main_plan/strategy/strategy.tscn
Normal file
361
UI/popup/task_development/main_plan/strategy/strategy.tscn
Normal file
@ -0,0 +1,361 @@
|
||||
[gd_scene load_steps=5 format=3 uid="uid://cx5nui56begu8"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://by3rdgo6jlbff" path="res://UI/popup/task_development/main_plan/strategy/strategy.gd" id="1_pbd5q"]
|
||||
[ext_resource type="Texture2D" uid="uid://pucudatqrcrq" path="res://UI/popup/popup_bg_1.png" id="2_eh5ff"]
|
||||
[ext_resource type="Theme" uid="uid://ddq54ba6vwyn0" path="res://UI/popup/task_development/main_plan/gameplay/gameplay_option_button.tres" id="3_rq5uk"]
|
||||
[ext_resource type="Texture2D" uid="uid://bb3kyiufyyj05" path="res://Entity/NPC/NPC_1_UI.png" id="4_vx267"]
|
||||
|
||||
[node name="strategy" type="Control"]
|
||||
visible = false
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_pbd5q")
|
||||
|
||||
[node name="BG" type="NinePatchRect" parent="."]
|
||||
custom_minimum_size = Vector2(500, 350)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -250.0
|
||||
offset_top = -200.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 150.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("2_eh5ff")
|
||||
region_rect = Rect2(1, 35, 86, 53)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 35
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 32
|
||||
|
||||
[node name="Title" type="NinePatchRect" parent="BG"]
|
||||
custom_minimum_size = Vector2(500, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -250.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 44.0
|
||||
grow_horizontal = 2
|
||||
texture = ExtResource("2_eh5ff")
|
||||
region_rect = Rect2(1, 27, 86, 8)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 7
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Title" type="Label" parent="BG/Title"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -34.5
|
||||
offset_top = -18.0
|
||||
offset_right = 34.5
|
||||
offset_bottom = 18.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 27
|
||||
text = "开发策略"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="Option" type="Control" parent="BG"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="Column_Headers" type="HBoxContainer" parent="BG/Option"]
|
||||
custom_minimum_size = Vector2(420, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -210.0
|
||||
offset_top = 51.0
|
||||
offset_right = 210.0
|
||||
offset_bottom = 82.0
|
||||
grow_horizontal = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="Title" type="Label" parent="BG/Option/Column_Headers"]
|
||||
custom_minimum_size = Vector2(320, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 22
|
||||
text = "开发方针"
|
||||
|
||||
[node name="Cost" type="Label" parent="BG/Option/Column_Headers"]
|
||||
custom_minimum_size = Vector2(80, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 22
|
||||
text = "成本"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Options" type="NinePatchRect" parent="BG/Option"]
|
||||
custom_minimum_size = Vector2(440, 170)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -220.0
|
||||
offset_top = -92.0
|
||||
offset_right = 220.0
|
||||
offset_bottom = 78.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("2_eh5ff")
|
||||
region_rect = Rect2(92, 38, 76, 34)
|
||||
patch_margin_left = 2
|
||||
patch_margin_top = 33
|
||||
patch_margin_right = 2
|
||||
patch_margin_bottom = 33
|
||||
|
||||
[node name="List_1" type="VBoxContainer" parent="BG/Option/Options"]
|
||||
custom_minimum_size = Vector2(436, 160)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -210.0
|
||||
offset_top = -80.0
|
||||
offset_right = 210.0
|
||||
offset_bottom = 80.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="option_1" type="Button" parent="BG/Option/Options/List_1"]
|
||||
custom_minimum_size = Vector2(0, 32)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("3_rq5uk")
|
||||
disabled = true
|
||||
flat = true
|
||||
|
||||
[node name="Row" type="HBoxContainer" parent="BG/Option/Options/List_1/option_1"]
|
||||
custom_minimum_size = Vector2(420, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -210.0
|
||||
offset_top = -15.5
|
||||
offset_right = 210.0
|
||||
offset_bottom = 15.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="Title" type="Label" parent="BG/Option/Options/List_1/option_1/Row"]
|
||||
custom_minimum_size = Vector2(300, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
text = "正常开发"
|
||||
|
||||
[node name="Cost" type="Label" parent="BG/Option/Options/List_1/option_1/Row"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
text = "0"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="option_2" type="Button" parent="BG/Option/Options/List_1"]
|
||||
custom_minimum_size = Vector2(0, 32)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("3_rq5uk")
|
||||
disabled = true
|
||||
flat = true
|
||||
|
||||
[node name="Row" type="HBoxContainer" parent="BG/Option/Options/List_1/option_2"]
|
||||
custom_minimum_size = Vector2(420, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -210.0
|
||||
offset_top = -15.5
|
||||
offset_right = 210.0
|
||||
offset_bottom = 15.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="Title" type="Label" parent="BG/Option/Options/List_1/option_2/Row"]
|
||||
custom_minimum_size = Vector2(300, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
|
||||
[node name="Cost" type="Label" parent="BG/Option/Options/List_1/option_2/Row"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="option_3" type="Button" parent="BG/Option/Options/List_1"]
|
||||
custom_minimum_size = Vector2(0, 32)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("3_rq5uk")
|
||||
disabled = true
|
||||
flat = true
|
||||
|
||||
[node name="Row" type="HBoxContainer" parent="BG/Option/Options/List_1/option_3"]
|
||||
custom_minimum_size = Vector2(420, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -210.0
|
||||
offset_top = -15.5
|
||||
offset_right = 210.0
|
||||
offset_bottom = 15.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="Title" type="Label" parent="BG/Option/Options/List_1/option_3/Row"]
|
||||
custom_minimum_size = Vector2(300, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
|
||||
[node name="Cost" type="Label" parent="BG/Option/Options/List_1/option_3/Row"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="option_4" type="Button" parent="BG/Option/Options/List_1"]
|
||||
custom_minimum_size = Vector2(0, 32)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("3_rq5uk")
|
||||
disabled = true
|
||||
flat = true
|
||||
|
||||
[node name="Row" type="HBoxContainer" parent="BG/Option/Options/List_1/option_4"]
|
||||
custom_minimum_size = Vector2(420, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -210.0
|
||||
offset_top = -15.5
|
||||
offset_right = 210.0
|
||||
offset_bottom = 15.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="Title" type="Label" parent="BG/Option/Options/List_1/option_4/Row"]
|
||||
custom_minimum_size = Vector2(300, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
|
||||
[node name="Cost" type="Label" parent="BG/Option/Options/List_1/option_4/Row"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="option_5" type="Button" parent="BG/Option/Options/List_1"]
|
||||
custom_minimum_size = Vector2(0, 32)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("3_rq5uk")
|
||||
disabled = true
|
||||
flat = true
|
||||
|
||||
[node name="Row" type="HBoxContainer" parent="BG/Option/Options/List_1/option_5"]
|
||||
custom_minimum_size = Vector2(420, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -210.0
|
||||
offset_top = -15.5
|
||||
offset_right = 210.0
|
||||
offset_bottom = 15.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="Title" type="Label" parent="BG/Option/Options/List_1/option_5/Row"]
|
||||
custom_minimum_size = Vector2(300, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
|
||||
[node name="Cost" type="Label" parent="BG/Option/Options/List_1/option_5/Row"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Explaination" type="Label" parent="BG/Option"]
|
||||
custom_minimum_size = Vector2(200, 60)
|
||||
layout_mode = 1
|
||||
anchors_preset = 2
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 47.0
|
||||
offset_top = -83.0
|
||||
offset_right = 358.0
|
||||
offset_bottom = -23.0
|
||||
grow_vertical = 0
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
text = "说明"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
autowrap_mode = 3
|
||||
|
||||
[node name="Human" type="TextureRect" parent="BG/Option"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 3
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -128.0
|
||||
offset_top = -90.0
|
||||
offset_right = -55.0
|
||||
offset_bottom = -17.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 0
|
||||
texture = ExtResource("4_vx267")
|
||||
368
UI/popup/task_development/main_plan/theme/theme.gd
Normal file
368
UI/popup/task_development/main_plan/theme/theme.gd
Normal file
@ -0,0 +1,368 @@
|
||||
extends UIPage
|
||||
|
||||
# UI Node References
|
||||
@onready var list_container = $BG/Option/Info
|
||||
@onready var previous_button = $BG/Title/previous/Button
|
||||
@onready var next_button = $BG/Title/next/Button
|
||||
@onready var title_label = $BG/Title/Title
|
||||
|
||||
# Configuration
|
||||
var items_per_page: int = 7 # 每页显示的选项数量 (保持与原 theme.gd 一致)
|
||||
|
||||
# Data Storage
|
||||
var theme_list_nodes: Array[VBoxContainer] = [] # 存储 List_1, List_2 等节点
|
||||
var option_nodes_per_list: Array = [] # 存储每个 List 对应的 option_X 按钮数组
|
||||
var all_enabled_themes: Array = [] # 存储筛选后的题材数据 { "name": String, "data": Dictionary }
|
||||
|
||||
# State
|
||||
var total_pages: int = 0
|
||||
var current_page_index: int = 0
|
||||
var selected_theme_key: String = "" # 当前逻辑上选中的项的 Key (用于确认)
|
||||
var currently_selected_button: Button = null # 当前高亮/聚焦的按钮节点引用
|
||||
var initial_key_to_highlight: String = "" # 弹窗打开时需要高亮的 Key (由父节点设置)
|
||||
|
||||
func _ready():
|
||||
super._ready() # 调用父类的 _ready() (如果 UIPage 中有 _ready() 逻辑)
|
||||
# 1. 获取 List 节点 (与原版 theme.gd 类似,但使用 gameplay.gd 的错误处理)
|
||||
for i in range(1, 7): # 假设最多有 List_6 (与原 theme.gd 匹配)
|
||||
var list_node = list_container.get_node_or_null("List_" + str(i))
|
||||
if list_node:
|
||||
theme_list_nodes.append(list_node)
|
||||
else:
|
||||
break # 假设 List 节点是连续的
|
||||
|
||||
if theme_list_nodes.is_empty():
|
||||
printerr("错误:在 theme.tscn 中未找到 List 节点!无法显示选项。")
|
||||
set_process(false) # 禁用处理,因为没有UI元素
|
||||
return
|
||||
|
||||
# 2. 获取每个 List 内的 Option 节点 (与原版 theme.gd 类似)
|
||||
for list_node in theme_list_nodes:
|
||||
var current_list_options: Array = []
|
||||
for i in range(1, items_per_page + 1):
|
||||
var option_node = list_node.get_node_or_null("option_" + str(i))
|
||||
if option_node and option_node is Button:
|
||||
current_list_options.append(option_node)
|
||||
else:
|
||||
# 使用 gameplay.gd 的警告格式
|
||||
push_warning("警告:在 %s 中未能找到 option_%d 按钮" % [list_node.name, i])
|
||||
option_nodes_per_list.append(current_list_options)
|
||||
|
||||
# 3. 连接按钮信号 (与 gameplay.gd 一致)
|
||||
if previous_button:
|
||||
if not previous_button.pressed.is_connected(_on_previous_pressed):
|
||||
previous_button.pressed.connect(_on_previous_pressed)
|
||||
else: printerr("错误:在 theme.tscn 中未找到 Previous 按钮")
|
||||
|
||||
if next_button:
|
||||
if not next_button.pressed.is_connected(_on_next_pressed):
|
||||
next_button.pressed.connect(_on_next_pressed)
|
||||
else: printerr("错误:在 theme.tscn 中未找到 Next 按钮")
|
||||
|
||||
# 4. 连接 visibility_changed 信号 (与 gameplay.gd 一致)
|
||||
if not is_connected("visibility_changed", _on_visibility_changed):
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
|
||||
# 5. 移除 _ready 中的初始数据加载和显示更新
|
||||
# 这些逻辑现在完全由 _on_visibility_changed -> reset_display 处理
|
||||
|
||||
# --- Visibility Change Handler (与 gameplay.gd 一致) ---
|
||||
func _on_visibility_changed():
|
||||
if is_visible_in_tree():
|
||||
print("Theme: 弹窗变为可见,调用 reset_display()")
|
||||
reset_display() # 当变为可见时调用 reset
|
||||
# else: # 可选:隐藏时的清理逻辑
|
||||
# print("Theme: 弹窗变为隐藏。")
|
||||
|
||||
# --- 新增:用于父节点设置初始选中项 (与 gameplay.gd 一致) ---
|
||||
func set_initial_selection(key: String):
|
||||
"""
|
||||
由父节点 (task_development) 在显示此弹窗前调用,
|
||||
传递当前在 task_info 中选中的题材 Key。
|
||||
"""
|
||||
initial_key_to_highlight = key
|
||||
print("Theme: 父节点设置初始高亮 Key 为: '%s'" % initial_key_to_highlight)
|
||||
|
||||
|
||||
# --- Data Processing and Display Logic ---
|
||||
|
||||
func _process_theme_data(all_themes_data: Dictionary):
|
||||
"""【修改】根据从 GameState 获取的题材数据,筛选出启用的题材,并计算总页数。"""
|
||||
all_enabled_themes.clear()
|
||||
if all_themes_data.is_empty():
|
||||
push_warning("警告:接收到的题材数据为空。")
|
||||
total_pages = 0
|
||||
return
|
||||
|
||||
# 遍历从 GameState 获取的题材字典
|
||||
for theme_name in all_themes_data:
|
||||
var theme_info = all_themes_data[theme_name]
|
||||
# 检查是否为字典且 "enabled" 字段为 true
|
||||
if typeof(theme_info) == TYPE_DICTIONARY and theme_info.get("enabled", false) == true:
|
||||
all_enabled_themes.append({"name": theme_name, "data": theme_info})
|
||||
# else: # Debugging
|
||||
# print("Theme: 过滤掉未启用或格式错误的题材: ", theme_name)
|
||||
|
||||
# 根据筛选结果计算总页数
|
||||
if items_per_page > 0:
|
||||
total_pages = ceil(float(all_enabled_themes.size()) / items_per_page)
|
||||
else:
|
||||
total_pages = 0
|
||||
printerr("错误:items_per_page 为零,无法计算页数。")
|
||||
|
||||
print("Theme: 处理完成,找到 %d 个启用的题材,共 %d 页。" % [all_enabled_themes.size(), total_pages])
|
||||
|
||||
|
||||
func reset_display():
|
||||
"""【修改】重置状态,从共享数据获取初始选中项,从 GameState 加载所有可选数据,并准备更新显示。"""
|
||||
print("Theme: 重置显示状态 (reset_display)。")
|
||||
# 1. 重置本地状态变量
|
||||
currently_selected_button = null
|
||||
selected_theme_key = "" # 当前逻辑上选中的项的 Key
|
||||
|
||||
# 1b. 【修改】从 MainController 的共享数据中获取初始应选中的题材 Key
|
||||
# 使用键名 "题材"。如果未找到该键,默认为空字符串。
|
||||
initial_key_to_highlight = get_main_data("题材", "") # <--- 从共享数据获取初始高亮项
|
||||
|
||||
if not initial_key_to_highlight.is_empty():
|
||||
print("Theme (reset_display): 从 get_main_data(\"题材\") 获取到初始高亮 Key: '%s'" % initial_key_to_highlight)
|
||||
else:
|
||||
# 如果 get_main_data 没有提供有效的 Key (例如 "题材" 键不存在或其值为空字符串),
|
||||
# initial_key_to_highlight 将是空字符串。
|
||||
print("Theme (reset_display): 未从 get_main_data(\"题材\") 获取到初始高亮 Key,或 Key 为空。将尝试高亮第一页的第一个项目。")
|
||||
|
||||
# 2. 【保持不变】从 GameState 重新加载并处理所有可显示的题材数据
|
||||
if not GameState:
|
||||
printerr("错误:GameState 在 reset_display 期间不可用。")
|
||||
total_pages = 0
|
||||
all_enabled_themes.clear()
|
||||
_update_display() # 即使没有数据也要更新显示(显示空状态)
|
||||
return
|
||||
|
||||
# --- 获取题材数据 ---
|
||||
var task_dev_data = GameState.get_value("task_development", {})
|
||||
if task_dev_data.is_empty():
|
||||
printerr("错误:从 GameState 获取 'task_development' 数据失败。")
|
||||
total_pages = 0
|
||||
all_enabled_themes.clear()
|
||||
else:
|
||||
# --- 从 task_development 中获取 themes ---
|
||||
var all_themes_data = task_dev_data.get("themes", {})
|
||||
_process_theme_data(all_themes_data) # 重新处理数据,计算 total_pages
|
||||
|
||||
# 3. 【逻辑不变,但使用来自 get_main_data("题材", "") 的 initial_key_to_highlight】
|
||||
# 根据 initial_key_to_highlight 确定初始页面
|
||||
current_page_index = 0 # 默认为第一页
|
||||
var found_initial_key = false
|
||||
if total_pages > 0 and not initial_key_to_highlight.is_empty():
|
||||
# 查找 initial_key_to_highlight 所在的索引和页面
|
||||
for i in range(all_enabled_themes.size()):
|
||||
if all_enabled_themes[i].name == initial_key_to_highlight:
|
||||
current_page_index = int(floor(float(i) / items_per_page)) # 设置目标页面
|
||||
found_initial_key = true
|
||||
print("Theme: 找到需要初始高亮的 Key '%s' (来自 get_main_data(\"题材\")) 在索引 %d, 目标页面 %d" % [initial_key_to_highlight, i, current_page_index])
|
||||
break # 找到了,停止循环
|
||||
if not found_initial_key:
|
||||
print("Theme: 需要初始高亮的 Key '%s' (来自 get_main_data(\"题材\")) 未在启用的题材中找到。将显示第一页,并尝试高亮该页的第一个项目。" % initial_key_to_highlight)
|
||||
# 保持 current_page_index 为 0
|
||||
initial_key_to_highlight = "" # 清空,因为未找到,避免后续 _update_display 尝试高亮不存在的项
|
||||
# else: initial_key_to_highlight 为空, current_page_index 保持为 0 (第一页)
|
||||
|
||||
# 确保页面索引有效 (与 gameplay.gd 一致)
|
||||
if total_pages == 0:
|
||||
current_page_index = 0
|
||||
elif current_page_index >= total_pages: # 如果计算出的页面超出范围
|
||||
current_page_index = total_pages - 1 if total_pages > 0 else 0
|
||||
elif current_page_index < 0: # 理论上不应发生
|
||||
current_page_index = 0
|
||||
|
||||
# 4. 触发显示更新
|
||||
_update_display()
|
||||
|
||||
func _update_display():
|
||||
"""【更新版】更新列表的可见性并填充当前页面的内容。
|
||||
现在将“经验”和“成本”显示为整数。
|
||||
"""
|
||||
# --- 处理无数据情况 (与 gameplay.gd 一致) ---
|
||||
if theme_list_nodes.is_empty():
|
||||
print("Theme: 无可用的 List 节点。")
|
||||
if title_label: title_label.text = "题材选择"
|
||||
return
|
||||
|
||||
if total_pages == 0:
|
||||
for list_node in theme_list_nodes: list_node.visible = false
|
||||
print("Theme: 没有启用的题材选项可供显示。")
|
||||
if title_label: title_label.text = "题材选择 (无可用)"
|
||||
if previous_button: previous_button.disabled = true
|
||||
if next_button: next_button.disabled = true
|
||||
return
|
||||
else:
|
||||
if previous_button: previous_button.disabled = (total_pages <= 1)
|
||||
if next_button: next_button.disabled = (total_pages <= 1)
|
||||
|
||||
# --- 更新页面索引 (循环) (与 gameplay.gd 一致) ---
|
||||
if total_pages > 0 :
|
||||
current_page_index = current_page_index % total_pages
|
||||
if current_page_index < 0:
|
||||
current_page_index += total_pages
|
||||
else:
|
||||
current_page_index = 0
|
||||
|
||||
# --- 更新标题 (与 gameplay.gd 一致) ---
|
||||
if title_label:
|
||||
var display_page_number = current_page_index + 1
|
||||
title_label.text = "题材选择 %d/%d" % [display_page_number, total_pages]
|
||||
|
||||
# --- 更新 List 可见性 (与 gameplay.gd 一致) ---
|
||||
for i in range(theme_list_nodes.size()):
|
||||
theme_list_nodes[i].visible = (i == current_page_index)
|
||||
|
||||
# --- 填充可见列表并查找要高亮的按钮 (与 gameplay.gd 类似) ---
|
||||
var button_to_highlight: Button = null
|
||||
var first_enabled_button_on_page: Button = null
|
||||
|
||||
if current_page_index < option_nodes_per_list.size():
|
||||
var current_options = option_nodes_per_list[current_page_index]
|
||||
var start_index = current_page_index * items_per_page
|
||||
|
||||
for i in range(current_options.size()):
|
||||
var option_button = current_options[i]
|
||||
var item_index = start_index + i
|
||||
|
||||
# --- 断开旧信号 ---
|
||||
if option_button.pressed.is_connected(_on_option_selected):
|
||||
option_button.pressed.disconnect(_on_option_selected)
|
||||
|
||||
if item_index < all_enabled_themes.size():
|
||||
var theme_entry = all_enabled_themes[item_index]
|
||||
var theme_name = theme_entry.name
|
||||
var theme_data = theme_entry.data # 包含 Cost, Experience, Popularity 等
|
||||
|
||||
var row = option_button.get_node_or_null("Row")
|
||||
if row:
|
||||
# 填充标签文本
|
||||
var title_label_in_row = row.get_node_or_null("Title")
|
||||
var exp_label = row.get_node_or_null("Experience")
|
||||
var pop_label = row.get_node_or_null("Popularity")
|
||||
var cost_label = row.get_node_or_null("Cost") if row.has_node("Cost") else row.get_node_or_null("cost")
|
||||
|
||||
if title_label_in_row: title_label_in_row.text = theme_name
|
||||
|
||||
# 【修改】设置经验值,显示为整数
|
||||
if exp_label:
|
||||
var experience_value = theme_data.get("Experience", 0.0)
|
||||
exp_label.text = str(int(experience_value))
|
||||
|
||||
# 【保持】设置流行度,保持原始字符串显示
|
||||
if pop_label:
|
||||
var popularity_value = theme_data.get("Popularity", "未知")
|
||||
pop_label.text = str(popularity_value)
|
||||
|
||||
# 【修改】设置成本,显示为整数
|
||||
if cost_label:
|
||||
var cost_value = theme_data.get("Cost", 0.0)
|
||||
cost_label.text = str(int(cost_value))
|
||||
|
||||
option_button.visible = true
|
||||
option_button.disabled = false
|
||||
option_button.set_meta("theme_name", theme_name) # 存储题材名称
|
||||
|
||||
# --- 连接新信号 (使用 bind) ---
|
||||
option_button.pressed.connect(_on_option_selected.bind(theme_name, option_button))
|
||||
|
||||
if first_enabled_button_on_page == null:
|
||||
first_enabled_button_on_page = option_button
|
||||
|
||||
if not initial_key_to_highlight.is_empty() and theme_name == initial_key_to_highlight:
|
||||
button_to_highlight = option_button
|
||||
# print("Theme: 找到需要初始高亮的按钮: ", button_to_highlight.name) # Debug
|
||||
|
||||
else: # 未找到 Row 节点
|
||||
push_warning("警告:在按钮 %s 中未找到 Row 节点" % option_button.get_path())
|
||||
option_button.visible = false
|
||||
option_button.disabled = true
|
||||
else: # 此槽位没有对应的启用题材数据
|
||||
option_button.visible = false
|
||||
option_button.disabled = true
|
||||
else:
|
||||
printerr("错误:当前页面索引 %d 超出 option_nodes_per_list 的范围 (大小 %d)" % [current_page_index, option_nodes_per_list.size()])
|
||||
|
||||
# --- 设置初始高亮和焦点 (与 gameplay.gd 一致) ---
|
||||
if button_to_highlight:
|
||||
_set_initial_highlight(button_to_highlight)
|
||||
elif first_enabled_button_on_page:
|
||||
print("Theme: 初始 Key '%s' 不在本页或为空。高亮本页第一个按钮: %s" % [initial_key_to_highlight, first_enabled_button_on_page.name])
|
||||
_set_initial_highlight(first_enabled_button_on_page)
|
||||
else:
|
||||
print("Theme: 本页没有可供高亮的按钮。")
|
||||
currently_selected_button = null
|
||||
selected_theme_key = ""
|
||||
|
||||
# (Helper) 设置初始高亮和焦点 (与 gameplay.gd 一致)
|
||||
func _set_initial_highlight(button_to_highlight: Button):
|
||||
if not is_instance_valid(button_to_highlight):
|
||||
printerr("错误:传递给 _set_initial_highlight 的按钮无效。")
|
||||
currently_selected_button = null
|
||||
selected_theme_key = ""
|
||||
return
|
||||
|
||||
# print("Theme: 设置高亮按钮: ", button_to_highlight.name) # Debug
|
||||
currently_selected_button = button_to_highlight
|
||||
# --- 修改元数据键名 ---
|
||||
selected_theme_key = button_to_highlight.get_meta("theme_name", "") # 同时设置 Key
|
||||
# print("Theme: currently_selected_button 设置为: ", currently_selected_button.name) # Debug
|
||||
# print("Theme: selected_theme_key 设置为: '", selected_theme_key, "'") # Debug
|
||||
|
||||
if currently_selected_button and currently_selected_button.is_inside_tree():
|
||||
# print("Theme: 尝试为按钮 call_deferred('grab_focus'): ", currently_selected_button.name) # Debug
|
||||
currently_selected_button.call_deferred("grab_focus")
|
||||
else:
|
||||
print("Theme: 按钮无效或不在场景树中,无法获取焦点。")
|
||||
|
||||
|
||||
# --- Signal Handlers ---
|
||||
|
||||
# (与 gameplay.gd 一致)
|
||||
func _on_previous_pressed():
|
||||
if total_pages > 1:
|
||||
current_page_index -= 1
|
||||
_update_display()
|
||||
|
||||
# (与 gameplay.gd 一致)
|
||||
func _on_next_pressed():
|
||||
if total_pages > 1:
|
||||
current_page_index += 1
|
||||
_update_display()
|
||||
|
||||
# 【修改】处理选项按钮按下事件 (与 gameplay.gd 一致)
|
||||
func _on_option_selected(theme_name: String, button_node: Button):
|
||||
"""当选项按钮被按下时调用。"""
|
||||
if not is_instance_valid(button_node):
|
||||
# --- 修改错误信息中的 Key 类型 ---
|
||||
printerr("错误:在 _on_option_selected 中收到无效按钮节点,Key: " + theme_name)
|
||||
return
|
||||
|
||||
if button_node == currently_selected_button:
|
||||
# --- 双击 (或点击已选中的按钮) ---
|
||||
print("Theme: 检测到双击或确认点击: ", theme_name)
|
||||
_confirm_and_close(theme_name) # 确认此选择
|
||||
else:
|
||||
# --- 首次点击或点击不同按钮 ---
|
||||
print("Theme: 选中 (高亮) 题材: ", theme_name)
|
||||
currently_selected_button = button_node
|
||||
selected_theme_key = theme_name # 更新 Key
|
||||
|
||||
# 更新视觉焦点
|
||||
button_node.grab_focus()
|
||||
|
||||
# 【修改】确认选择并关闭弹窗的逻辑 (与 gameplay.gd 一致)
|
||||
func _confirm_and_close(key_to_confirm: String):
|
||||
"""更新父节点并关闭此弹窗。"""
|
||||
if key_to_confirm.is_empty():
|
||||
printerr("错误:尝试确认一个空的题材 Key。")
|
||||
return
|
||||
|
||||
print("Theme: 确认选择: ", key_to_confirm)
|
||||
|
||||
set_main_data("题材", key_to_confirm)
|
||||
go_next()
|
||||
1
UI/popup/task_development/main_plan/theme/theme.gd.uid
Normal file
1
UI/popup/task_development/main_plan/theme/theme.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://vu7r5wd0amxb
|
||||
2501
UI/popup/task_development/main_plan/theme/theme.tscn
Normal file
2501
UI/popup/task_development/main_plan/theme/theme.tscn
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,17 @@
|
||||
[gd_resource type="Theme" load_steps=5 format=3 uid="uid://r5e0kacnb3xf"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_kemom"]
|
||||
bg_color = Color(0.513883, 0.609153, 0.731076, 1)
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ao15e"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_kemom"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_mp8x4"]
|
||||
bg_color = Color(0.513883, 0.609153, 0.731076, 1)
|
||||
|
||||
[resource]
|
||||
Button/styles/focus = SubResource("StyleBoxFlat_kemom")
|
||||
Button/styles/hover = SubResource("StyleBoxEmpty_ao15e")
|
||||
Button/styles/normal = SubResource("StyleBoxEmpty_kemom")
|
||||
Button/styles/pressed = SubResource("StyleBoxFlat_mp8x4")
|
||||
232
UI/popup/task_development/npc_select_1/npc_select_1.gd
Normal file
232
UI/popup/task_development/npc_select_1/npc_select_1.gd
Normal file
@ -0,0 +1,232 @@
|
||||
extends UIPage
|
||||
|
||||
# --- UI 节点引用 ---
|
||||
@onready var title_label: Label = $BG/Title/Title
|
||||
@onready var npc_name_label: Label = $BG/Option/NPC_Info_1/Name
|
||||
@onready var npc_staff_type_label: Label = $BG/Option/NPC_Info_1/Staff # 通常显示 "员工"
|
||||
@onready var npc_job_label: Label = $BG/Option/NPC_Info_2/Info_List_0/Job/Title
|
||||
@onready var npc_level_label: Label = $BG/Option/NPC_Info_2/Info_List_0/Job/Level
|
||||
@onready var npc_icon_rect: TextureRect = $BG/Option/NPC_Info_2/Info_List_0/Icon
|
||||
|
||||
@onready var stat_design_label: Label = $BG/Option/NPC_Info_2/Info_List_1/Info_1/info
|
||||
@onready var stat_code_label: Label = $BG/Option/NPC_Info_2/Info_List_1/Info_2/info
|
||||
@onready var stat_art_label: Label = $BG/Option/NPC_Info_2/Info_List_1/Info_3/info
|
||||
@onready var stat_audio_label: Label = $BG/Option/NPC_Info_2/Info_List_1/Info_4/info
|
||||
|
||||
@onready var cost_label: Label = $BG/Option/NPC_Info_2/Info_List_3/info_4/info
|
||||
|
||||
@onready var power_bar_segments_container: HBoxContainer = $BG/Option/NPC_Info_2/Info_List_2
|
||||
var _power_bar_segments: Array[ColorRect] = [] # 用于存储体力条的各个片段
|
||||
|
||||
@onready var prev_button: Button = $BG/Title/previous/Button
|
||||
@onready var next_button: Button = $BG/Title/next/Button
|
||||
@onready var confirm_button: Button = $BG/Confirm
|
||||
|
||||
# --- 内部状态 ---
|
||||
var _all_npcs_data: Dictionary = {} # 存储从 GameState 加载的所有NPC原始数据
|
||||
var enabled_npc_keys: Array[String] = [] # 存储所有当前可选的NPC的键 (名字)
|
||||
var current_npc_index: int = -1 # 当前在 enabled_npc_keys 数组中选中的NPC的索引
|
||||
|
||||
# --- 常量 ---
|
||||
const NPC_ICON_BASE_PATH = "res://Entity/NPC/" # NPC 图标的基础路径 (如果后续有 Icon 字段)
|
||||
const DEFAULT_NPC_ICON_PATH = "res://Entity/NPC/NPC_1_UI.png" # 默认/占位NPC图标
|
||||
|
||||
const POWER_CURRENT_COLOR = Color.GREEN_YELLOW # 当前体力颜色
|
||||
const POWER_MAX_POTENTIAL_COLOR = Color(0.2, 0.4, 0.2, 0.8) # 最大潜力槽颜色 (稍暗的绿色)
|
||||
const POWER_DISABLED_COLOR = Color(0.1, 0.1, 0.1, 0.3) # 体力条禁用/未达到部分的颜色
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
var node_name = str(self.name)
|
||||
add_to_group(node_name) # 方便父节点或其他系统查找
|
||||
|
||||
# 收集体力条的片段
|
||||
for child in power_bar_segments_container.get_children():
|
||||
if child is ColorRect:
|
||||
_power_bar_segments.append(child)
|
||||
if _power_bar_segments.size() != 20:
|
||||
printerr(node_name + ": Expected 20 power bar segments, found " + str(_power_bar_segments.size()))
|
||||
|
||||
|
||||
# 连接信号
|
||||
if prev_button and not prev_button.pressed.is_connected(_on_previous_pressed):
|
||||
prev_button.pressed.connect(_on_previous_pressed)
|
||||
if next_button and not next_button.pressed.is_connected(_on_next_pressed):
|
||||
next_button.pressed.connect(_on_next_pressed)
|
||||
if confirm_button and not confirm_button.pressed.is_connected(_on_confirm_pressed):
|
||||
confirm_button.pressed.connect(_on_confirm_pressed)
|
||||
|
||||
if not is_connected("visibility_changed",Callable(self,"_on_visibility_changed")):
|
||||
visibility_changed.connect(Callable(self,"_on_visibility_changed"))
|
||||
|
||||
# 如果节点在 _ready 时就可见,则立即刷新显示
|
||||
if is_visible_in_tree():
|
||||
reset_display()
|
||||
|
||||
|
||||
func _on_visibility_changed() -> void:
|
||||
if is_visible_in_tree():
|
||||
reset_display()
|
||||
|
||||
|
||||
# 重置显示状态,在窗口可见时调用
|
||||
func reset_display() -> void:
|
||||
print(str(self.name) + ": Resetting display state.")
|
||||
_load_and_filter_npcs()
|
||||
|
||||
if enabled_npc_keys.is_empty():
|
||||
current_npc_index = -1
|
||||
print(str(self.name) + ": No enabled NPCs found.")
|
||||
else:
|
||||
current_npc_index = 0 # 默认显示第一个可用的NPC
|
||||
print(str(self.name) + ": Found %d enabled NPCs. Defaulting to index 0." % enabled_npc_keys.size())
|
||||
|
||||
_display_current_npc()
|
||||
|
||||
# 从 GameState 加载NPC数据并筛选出可用的负责人
|
||||
func _load_and_filter_npcs() -> void:
|
||||
_all_npcs_data.clear()
|
||||
enabled_npc_keys.clear()
|
||||
|
||||
if not GameState:
|
||||
printerr(str(self.name) + ": GameState not available in _load_and_filter_npcs.")
|
||||
return
|
||||
|
||||
var raw_npcs_data = GameState.get_value("npcs", {})
|
||||
if raw_npcs_data.is_empty():
|
||||
print(str(self.name) + ": 'npcs' data in GameState is empty or not found.")
|
||||
return
|
||||
|
||||
_all_npcs_data = raw_npcs_data.duplicate(true)
|
||||
|
||||
for npc_key in _all_npcs_data:
|
||||
var npc_info = _all_npcs_data[npc_key]
|
||||
if typeof(npc_info) == TYPE_DICTIONARY and npc_info.get("type") == "员工":
|
||||
enabled_npc_keys.append(npc_key)
|
||||
|
||||
# 可选:对 enabled_npc_keys进行排序,以确保显示顺序一致
|
||||
# enabled_npc_keys.sort()
|
||||
print(str(self.name) + ": Loaded and filtered NPCs. Enabled count: " + str(enabled_npc_keys.size()))
|
||||
|
||||
# 根据 current_npc_index 更新UI显示
|
||||
func _display_current_npc() -> void:
|
||||
if current_npc_index < 0 or current_npc_index >= enabled_npc_keys.size():
|
||||
# --- 处理没有可用NPC或索引无效的情况 ---
|
||||
title_label.text = "策划案负责人"
|
||||
npc_name_label.text = "无可用负责人"
|
||||
npc_staff_type_label.text = "-" # 通常显示 "员工"
|
||||
npc_job_label.text = "-"
|
||||
npc_level_label.text = "-"
|
||||
npc_icon_rect.texture = null # 或者一个“无”的占位图
|
||||
stat_design_label.text = "-"
|
||||
stat_code_label.text = "-"
|
||||
stat_art_label.text = "-"
|
||||
stat_audio_label.text = "-"
|
||||
cost_label.text = "-"
|
||||
|
||||
# 隐藏所有体力条片段
|
||||
for segment in _power_bar_segments:
|
||||
segment.visible = false
|
||||
|
||||
if prev_button: prev_button.disabled = true
|
||||
if next_button: next_button.disabled = true
|
||||
if confirm_button: confirm_button.disabled = true
|
||||
return
|
||||
|
||||
# --- 如果有有效NPC ---
|
||||
if prev_button: prev_button.disabled = enabled_npc_keys.size() <= 1
|
||||
if next_button: next_button.disabled = enabled_npc_keys.size() <= 1
|
||||
if confirm_button: confirm_button.disabled = false
|
||||
|
||||
var display_index = current_npc_index + 1
|
||||
var total_count = enabled_npc_keys.size()
|
||||
title_label.text = "策划案负责人 %d/%d" % [display_index, total_count]
|
||||
|
||||
var npc_key = enabled_npc_keys[current_npc_index]
|
||||
if not _all_npcs_data.has(npc_key):
|
||||
printerr(str(self.name) + ": Current NPC key '%s' not found in cached _all_npcs_data!" % npc_key)
|
||||
# 显示错误状态,可以做得更友好
|
||||
npc_name_label.text = "错误:数据丢失"
|
||||
# 隐藏所有体力条片段
|
||||
for segment in _power_bar_segments:
|
||||
segment.visible = false
|
||||
return
|
||||
|
||||
var npc_info = _all_npcs_data[npc_key]
|
||||
|
||||
# 更新基本信息
|
||||
npc_name_label.text = npc_key
|
||||
npc_staff_type_label.text = npc_info.get("type", "员工") # 根据筛选,这里应该是"员工"
|
||||
npc_job_label.text = npc_info.get("title", "-")
|
||||
npc_level_label.text = "Lv" + str(int(npc_info.get("level", 1)))
|
||||
|
||||
# 更新图标 (后续会从npc_info.Icon获取)
|
||||
var icon_name_from_data = npc_info.get("Icon", "") # 假设后续会有这个字段
|
||||
if not icon_name_from_data.is_empty():
|
||||
var dynamic_icon_path = NPC_ICON_BASE_PATH + icon_name_from_data + ".png" # 假设文件名规则
|
||||
if ResourceLoader.exists(dynamic_icon_path):
|
||||
npc_icon_rect.texture = ResourceLoader.load(dynamic_icon_path)
|
||||
else:
|
||||
printerr(str(self.name) + ": Failed to load NPC icon: " + dynamic_icon_path + ". Falling back to default.")
|
||||
npc_icon_rect.texture = ResourceLoader.load(DEFAULT_NPC_ICON_PATH)
|
||||
else:
|
||||
# print(str(self.name) + ": NPC icon name is empty for key '%s'. Using default." % npc_key)
|
||||
npc_icon_rect.texture = ResourceLoader.load(DEFAULT_NPC_ICON_PATH)
|
||||
|
||||
|
||||
# 更新能力值 (确保转换为整数显示)
|
||||
stat_design_label.text = str(int(npc_info.get("design", 0.0)))
|
||||
stat_code_label.text = str(int(npc_info.get("code", 0.0)))
|
||||
stat_art_label.text = str(int(npc_info.get("art", 0.0)))
|
||||
stat_audio_label.text = str(int(npc_info.get("audio", 0.0)))
|
||||
|
||||
# 更新费用
|
||||
cost_label.text = str(int(npc_info.get("outsourcing", 0.0)))
|
||||
|
||||
# --- 更新体力条 (包含 visible 控制) ---
|
||||
var power = float(npc_info.get("power", 0.0))
|
||||
var power_max = float(npc_info.get("power_max", 0.0))
|
||||
|
||||
if power_max <= 0: # 防止除零错误或无效数据
|
||||
for segment in _power_bar_segments:
|
||||
segment.visible = false # 如果最大体力为0或无效,所有格段都不可见
|
||||
else:
|
||||
var total_visible_segments = floori(power_max / 10.0) # 根据 power_max 计算总共应显示的格数
|
||||
var current_power_segments = floori(power / 10.0) # 当前体力对应的格数
|
||||
|
||||
# 确保 current_power_segments 不会超过 total_visible_segments (逻辑上 power 不应大于 power_max)
|
||||
current_power_segments = mini(current_power_segments, total_visible_segments)
|
||||
|
||||
for i in range(_power_bar_segments.size()): # 遍历所有20个可能的格段
|
||||
var segment = _power_bar_segments[i]
|
||||
|
||||
if i < total_visible_segments:
|
||||
segment.visible = true # 此格段在NPC的最大体力范围内,设为可见
|
||||
if i < current_power_segments:
|
||||
segment.color = POWER_CURRENT_COLOR # 当前体力部分
|
||||
else:
|
||||
segment.color = POWER_MAX_POTENTIAL_COLOR # 最大潜力中未充满的部分
|
||||
else:
|
||||
segment.visible = false # 此格段超出NPC的最大体力范围,设为不可见
|
||||
|
||||
func _on_previous_pressed() -> void:
|
||||
if enabled_npc_keys.size() > 1:
|
||||
current_npc_index -= 1
|
||||
if current_npc_index < 0:
|
||||
current_npc_index = enabled_npc_keys.size() - 1
|
||||
_display_current_npc()
|
||||
|
||||
func _on_next_pressed() -> void:
|
||||
if enabled_npc_keys.size() > 1:
|
||||
current_npc_index += 1
|
||||
if current_npc_index >= enabled_npc_keys.size():
|
||||
current_npc_index = 0
|
||||
_display_current_npc()
|
||||
|
||||
func _on_confirm_pressed() -> void:
|
||||
if current_npc_index != -1 and current_npc_index < enabled_npc_keys.size():
|
||||
var selected_npc_key = enabled_npc_keys[current_npc_index]
|
||||
|
||||
#set_main_data("关键环节负责人", key_to_confirm)
|
||||
go_next()
|
||||
@ -0,0 +1 @@
|
||||
uid://1emqepctick7
|
||||
640
UI/popup/task_development/npc_select_1/npc_select_1.tscn
Normal file
640
UI/popup/task_development/npc_select_1/npc_select_1.tscn
Normal file
@ -0,0 +1,640 @@
|
||||
[gd_scene load_steps=30 format=3 uid="uid://b5nxlnb6xr2oc"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://1emqepctick7" path="res://UI/popup/task_development/npc_select_1/npc_select_1.gd" id="1_sgs0r"]
|
||||
[ext_resource type="Texture2D" uid="uid://pucudatqrcrq" path="res://UI/popup/popup_bg_1.png" id="2_oyv27"]
|
||||
[ext_resource type="Texture2D" uid="uid://dgcugleiv7sfw" path="res://UI/popup/task_development/arrow.png" id="3_qga8r"]
|
||||
[ext_resource type="FontFile" uid="uid://egugs822n8gr" path="res://UI/font/AlimamaFangYuanTiVF-Thin.ttf" id="4_mk7go"]
|
||||
[ext_resource type="Texture2D" uid="uid://hdidwixuokxn" path="res://Entity/NPC/npc_ability_icon.png" id="5_8ts75"]
|
||||
[ext_resource type="LabelSettings" uid="uid://qcn0aduvrgvw" path="res://UI/tres/task_development_platform_label_settings.tres" id="6_3iojh"]
|
||||
[ext_resource type="Theme" uid="uid://bau80ps6kx783" path="res://UI/tres/Bottom_Info_button_theme.tres" id="7_mchvh"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_chj15"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_c3aay"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_yswoy"]
|
||||
|
||||
[sub_resource type="Animation" id="Animation_bu5lv"]
|
||||
length = 0.001
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Title/previous:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [Vector2(9, 7)]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_6a8uh"]
|
||||
resource_name = "base"
|
||||
length = 0.6
|
||||
loop_mode = 1
|
||||
step = 0.2
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Title/previous:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.2, 0.4, 0.6),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [Vector2(16, 7), Vector2(12, 7), Vector2(9, 7), Vector2(16, 7)]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_mue51"]
|
||||
_data = {
|
||||
&"RESET": SubResource("Animation_bu5lv"),
|
||||
&"base": SubResource("Animation_6a8uh")
|
||||
}
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_t3kh8"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_xk4rn"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_xp2hk"]
|
||||
|
||||
[sub_resource type="Animation" id="Animation_wpgbx"]
|
||||
length = 0.001
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath(".:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [Vector2(461, 7)]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_mue51"]
|
||||
resource_name = "base"
|
||||
length = 0.6
|
||||
loop_mode = 1
|
||||
step = 0.2
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath(".:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.2, 0.4, 0.6),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [Vector2(455, 7), Vector2(458, 7), Vector2(461, 7), Vector2(455, 7)]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_r6b7x"]
|
||||
_data = {
|
||||
&"RESET": SubResource("Animation_wpgbx"),
|
||||
&"base": SubResource("Animation_mue51")
|
||||
}
|
||||
|
||||
[sub_resource type="LabelSettings" id="LabelSettings_w5gvb"]
|
||||
font = ExtResource("4_mk7go")
|
||||
font_size = 23
|
||||
font_color = Color(0, 0, 0, 1)
|
||||
|
||||
[sub_resource type="LabelSettings" id="LabelSettings_kgbbm"]
|
||||
font = ExtResource("4_mk7go")
|
||||
font_size = 21
|
||||
font_color = Color(0, 0, 0, 1)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_bktga"]
|
||||
bg_color = Color(0.913725, 0.913725, 0.913725, 0.913725)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_x70d5"]
|
||||
bg_color = Color(0.913725, 0.913725, 0.913725, 0.913725)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_lnvfu"]
|
||||
bg_color = Color(0.913725, 0.913725, 0.913725, 0.913725)
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_7vjot"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_dm4ce"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_hgp08"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_v40qy"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_cfg1r"]
|
||||
|
||||
[node name="npc_select_1" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_sgs0r")
|
||||
|
||||
[node name="BG" type="NinePatchRect" parent="."]
|
||||
custom_minimum_size = Vector2(500, 350)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -250.0
|
||||
offset_top = -175.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 175.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("2_oyv27")
|
||||
region_rect = Rect2(1, 35, 86, 53)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 35
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 32
|
||||
|
||||
[node name="Title" type="NinePatchRect" parent="BG"]
|
||||
custom_minimum_size = Vector2(500, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -250.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 44.0
|
||||
grow_horizontal = 2
|
||||
texture = ExtResource("2_oyv27")
|
||||
region_rect = Rect2(1, 27, 86, 8)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 7
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Title" type="Label" parent="BG/Title"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -34.5
|
||||
offset_top = -18.0
|
||||
offset_right = 34.5
|
||||
offset_bottom = 18.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 27
|
||||
text = "策划案负责人"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="previous" type="NinePatchRect" parent="BG/Title"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 4
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 9.0
|
||||
offset_top = -15.0
|
||||
offset_right = 39.0
|
||||
offset_bottom = 15.0
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("3_qga8r")
|
||||
region_rect = Rect2(0, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="BG/Title/previous"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_chj15")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_c3aay")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_yswoy")
|
||||
flat = true
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="BG/Title/previous"]
|
||||
root_node = NodePath("../../..")
|
||||
libraries = {
|
||||
&"": SubResource("AnimationLibrary_mue51")
|
||||
}
|
||||
autoplay = "base"
|
||||
|
||||
[node name="next" type="NinePatchRect" parent="BG/Title"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 6
|
||||
anchor_left = 1.0
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -39.0
|
||||
offset_top = -15.0
|
||||
offset_right = -9.0
|
||||
offset_bottom = 15.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("3_qga8r")
|
||||
region_rect = Rect2(6, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="BG/Title/next"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_t3kh8")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_xk4rn")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_xp2hk")
|
||||
flat = true
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="BG/Title/next"]
|
||||
libraries = {
|
||||
&"": SubResource("AnimationLibrary_r6b7x")
|
||||
}
|
||||
autoplay = "base"
|
||||
|
||||
[node name="Option" type="Control" parent="BG"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="NPC_Info_1" type="HBoxContainer" parent="BG/Option"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -170.0
|
||||
offset_top = 47.0
|
||||
offset_right = 202.0
|
||||
offset_bottom = 87.0
|
||||
grow_horizontal = 2
|
||||
theme_override_constants/separation = 160
|
||||
|
||||
[node name="Name" type="Label" parent="BG/Option/NPC_Info_1"]
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 24
|
||||
text = "米子一"
|
||||
label_settings = SubResource("LabelSettings_w5gvb")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Staff" type="Label" parent="BG/Option/NPC_Info_1"]
|
||||
custom_minimum_size = Vector2(140, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_fonts/font = ExtResource("4_mk7go")
|
||||
theme_override_font_sizes/font_size = 20
|
||||
text = "员工"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="NPC_Info_2" type="NinePatchRect" parent="BG/Option"]
|
||||
custom_minimum_size = Vector2(440, 200)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -220.0
|
||||
offset_top = -92.0
|
||||
offset_right = 220.0
|
||||
offset_bottom = 130.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("2_oyv27")
|
||||
region_rect = Rect2(92, 38, 76, 34)
|
||||
patch_margin_left = 2
|
||||
patch_margin_top = 33
|
||||
patch_margin_right = 2
|
||||
patch_margin_bottom = 33
|
||||
|
||||
[node name="Info_List_0" type="VBoxContainer" parent="BG/Option/NPC_Info_2"]
|
||||
custom_minimum_size = Vector2(0, 95)
|
||||
layout_mode = 0
|
||||
offset_left = 26.0
|
||||
offset_top = 23.0
|
||||
offset_right = 185.0
|
||||
offset_bottom = 147.0
|
||||
theme_override_constants/separation = 14
|
||||
|
||||
[node name="Job" type="HBoxContainer" parent="BG/Option/NPC_Info_2/Info_List_0"]
|
||||
custom_minimum_size = Vector2(180, 0)
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 32
|
||||
|
||||
[node name="Title" type="Label" parent="BG/Option/NPC_Info_2/Info_List_0/Job"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
text = "产品总监"
|
||||
label_settings = SubResource("LabelSettings_kgbbm")
|
||||
|
||||
[node name="Level" type="Label" parent="BG/Option/NPC_Info_2/Info_List_0/Job"]
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
text = "Lv1"
|
||||
label_settings = SubResource("LabelSettings_kgbbm")
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Icon" type="TextureRect" parent="BG/Option/NPC_Info_2/Info_List_0"]
|
||||
custom_minimum_size = Vector2(95, 95)
|
||||
layout_mode = 2
|
||||
stretch_mode = 5
|
||||
|
||||
[node name="Info_List_1" type="GridContainer" parent="BG/Option/NPC_Info_2"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 6
|
||||
anchor_left = 1.0
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -204.0
|
||||
offset_top = -87.0
|
||||
offset_right = -8.0
|
||||
offset_bottom = 46.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 2
|
||||
theme_override_constants/v_separation = 7
|
||||
|
||||
[node name="Info_1" type="HBoxContainer" parent="BG/Option/NPC_Info_2/Info_List_1"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="icon" type="NinePatchRect" parent="BG/Option/NPC_Info_2/Info_List_1/Info_1"]
|
||||
custom_minimum_size = Vector2(28, 28)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("5_8ts75")
|
||||
region_rect = Rect2(38, 30, 20, 15)
|
||||
|
||||
[node name="title" type="Label" parent="BG/Option/NPC_Info_2/Info_List_1/Info_1"]
|
||||
custom_minimum_size = Vector2(60, 0)
|
||||
layout_mode = 2
|
||||
theme_override_fonts/font = ExtResource("4_mk7go")
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_bktga")
|
||||
text = "策划"
|
||||
label_settings = ExtResource("6_3iojh")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info" type="Label" parent="BG/Option/NPC_Info_2/Info_List_1/Info_1"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
text = "80"
|
||||
label_settings = ExtResource("6_3iojh")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Info_2" type="HBoxContainer" parent="BG/Option/NPC_Info_2/Info_List_1"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="icon" type="NinePatchRect" parent="BG/Option/NPC_Info_2/Info_List_1/Info_2"]
|
||||
custom_minimum_size = Vector2(28, 28)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("5_8ts75")
|
||||
region_rect = Rect2(12, 31, 17, 16)
|
||||
|
||||
[node name="title" type="Label" parent="BG/Option/NPC_Info_2/Info_List_1/Info_2"]
|
||||
custom_minimum_size = Vector2(60, 0)
|
||||
layout_mode = 2
|
||||
theme_override_fonts/font = ExtResource("4_mk7go")
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_bktga")
|
||||
text = "程序"
|
||||
label_settings = ExtResource("6_3iojh")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info" type="Label" parent="BG/Option/NPC_Info_2/Info_List_1/Info_2"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
text = "80"
|
||||
label_settings = ExtResource("6_3iojh")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Info_3" type="HBoxContainer" parent="BG/Option/NPC_Info_2/Info_List_1"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="icon" type="NinePatchRect" parent="BG/Option/NPC_Info_2/Info_List_1/Info_3"]
|
||||
custom_minimum_size = Vector2(28, 28)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("5_8ts75")
|
||||
region_rect = Rect2(63, 29, 21, 16)
|
||||
|
||||
[node name="title" type="Label" parent="BG/Option/NPC_Info_2/Info_List_1/Info_3"]
|
||||
custom_minimum_size = Vector2(60, 0)
|
||||
layout_mode = 2
|
||||
theme_override_fonts/font = ExtResource("4_mk7go")
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_bktga")
|
||||
text = "美术"
|
||||
label_settings = ExtResource("6_3iojh")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info" type="Label" parent="BG/Option/NPC_Info_2/Info_List_1/Info_3"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
text = "80"
|
||||
label_settings = ExtResource("6_3iojh")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Info_4" type="HBoxContainer" parent="BG/Option/NPC_Info_2/Info_List_1"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="icon" type="NinePatchRect" parent="BG/Option/NPC_Info_2/Info_List_1/Info_4"]
|
||||
custom_minimum_size = Vector2(28, 28)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("5_8ts75")
|
||||
region_rect = Rect2(92, 29, 22, 16)
|
||||
|
||||
[node name="title" type="Label" parent="BG/Option/NPC_Info_2/Info_List_1/Info_4"]
|
||||
custom_minimum_size = Vector2(60, 0)
|
||||
layout_mode = 2
|
||||
theme_override_fonts/font = ExtResource("4_mk7go")
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_bktga")
|
||||
text = "音频"
|
||||
label_settings = ExtResource("6_3iojh")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info" type="Label" parent="BG/Option/NPC_Info_2/Info_List_1/Info_4"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
text = "80"
|
||||
label_settings = ExtResource("6_3iojh")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Info_List_2" type="HBoxContainer" parent="BG/Option/NPC_Info_2"]
|
||||
layout_mode = 1
|
||||
offset_left = 49.0
|
||||
offset_top = 164.0
|
||||
offset_right = 169.0
|
||||
offset_bottom = 164.0
|
||||
theme_override_constants/separation = 0
|
||||
alignment = 1
|
||||
|
||||
[node name="Segment_1" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 10)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_2" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_3" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_4" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_5" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_6" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_7" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_8" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_9" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_10" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_11" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_12" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_13" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_14" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_15" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_16" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_17" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_18" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_19" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_20" type="ColorRect" parent="BG/Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Info_List_3" type="HBoxContainer" parent="BG/Option/NPC_Info_2"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 7
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -191.5
|
||||
offset_top = -38.0
|
||||
offset_right = 191.5
|
||||
offset_bottom = -10.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
|
||||
[node name="info_4" type="HBoxContainer" parent="BG/Option/NPC_Info_2/Info_List_3"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="title" type="Label" parent="BG/Option/NPC_Info_2/Info_List_3/info_4"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
theme_override_fonts/font = ExtResource("4_mk7go")
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_x70d5")
|
||||
text = "费用"
|
||||
label_settings = ExtResource("6_3iojh")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info" type="Label" parent="BG/Option/NPC_Info_2/Info_List_3/info_4"]
|
||||
custom_minimum_size = Vector2(70, 0)
|
||||
layout_mode = 2
|
||||
text = "500"
|
||||
label_settings = ExtResource("6_3iojh")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info_5" type="HBoxContainer" parent="BG/Option/NPC_Info_2/Info_List_3"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
[node name="title" type="Label" parent="BG/Option/NPC_Info_2/Info_List_3/info_5"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_lnvfu")
|
||||
text = "开发次数"
|
||||
label_settings = ExtResource("6_3iojh")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info" type="Label" parent="BG/Option/NPC_Info_2/Info_List_3/info_5"]
|
||||
custom_minimum_size = Vector2(30, 0)
|
||||
layout_mode = 2
|
||||
text = "0"
|
||||
label_settings = ExtResource("6_3iojh")
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="unit" type="Label" parent="BG/Option/NPC_Info_2/Info_List_3/info_5"]
|
||||
layout_mode = 2
|
||||
text = "次"
|
||||
label_settings = ExtResource("6_3iojh")
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Confirm" type="Button" parent="BG"]
|
||||
custom_minimum_size = Vector2(70, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 7
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -35.0
|
||||
offset_top = -43.0
|
||||
offset_right = 35.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
theme = ExtResource("7_mchvh")
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_focus_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 23
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_7vjot")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxFlat_dm4ce")
|
||||
theme_override_styles/hover = SubResource("StyleBoxFlat_hgp08")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_v40qy")
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_cfg1r")
|
||||
text = "确定"
|
||||
@ -1,5 +1,4 @@
|
||||
# product_focus.gd
|
||||
extends NinePatchRect
|
||||
extends UIPage # 继承自我们之前创建的 UIPage
|
||||
|
||||
#-- 配置变量 (可在 Inspector 中调整) --
|
||||
@export var min_value_per_category: int = 0 # 每个类别的最小值
|
||||
@ -8,24 +7,25 @@ extends NinePatchRect
|
||||
@export var inactive_color: Color = Color("acacac") # 非激活格子的颜色
|
||||
|
||||
#-- 内部变量 --
|
||||
var total_points_from_state: int = 0 # 从 GameState 获取的总点数
|
||||
var total_points_from_state: int = 0 # 从get_main_data获取的总点数
|
||||
var remaining_points: int = 0
|
||||
# 存储每个类别 (info_1 到 info_6) 当前分配的点数
|
||||
var category_points: Array[int] = []
|
||||
# 存储每个类别在 GameState 中的键名 ("视觉表现", "游戏深度", ...)
|
||||
# 存储每个类别在 get_main_data 中的键名 ("视觉表现", "游戏深度", ...)
|
||||
var category_keys: Array[String] = []
|
||||
|
||||
# 存储每个类别 UI 元素的引用
|
||||
var category_controls: Array[Dictionary] = []
|
||||
|
||||
#-- 节点引用 --
|
||||
@onready var points_label: Label = $Part_2/HBoxContainer/Points
|
||||
@onready var grid_container: GridContainer = $Part_3/GridContainer
|
||||
@onready var gameplay_info_label: Label = $Part_4/gameplay/info
|
||||
@onready var theme_info_label: Label = $Part_4/theme/info
|
||||
@onready var confirm_button: Button = $Confirm
|
||||
@onready var points_label: Label = $BG/Part_2/HBoxContainer/Points
|
||||
@onready var grid_container: GridContainer = $BG/Part_3/GridContainer
|
||||
@onready var gameplay_info_label: Label = $BG/Part_4/gameplay/info
|
||||
@onready var theme_info_label: Label = $BG/Part_4/theme/info
|
||||
@onready var confirm_button: Button = $BG/Confirm
|
||||
|
||||
func _ready():
|
||||
super._ready() # 调用父类的 _ready() (如果 UIPage 中有 _ready() 逻辑)
|
||||
add_to_group(str(name)) # 方便父节点查找
|
||||
|
||||
# --- 初始化控件引用和类别键名 ---
|
||||
@ -103,15 +103,8 @@ func reset_display():
|
||||
return
|
||||
|
||||
# 1. 从 GameState 获取 task_development 数据
|
||||
var task_dev_data: Dictionary = GameState.get_value("task_development", {})
|
||||
var focus_data: Dictionary = {} # 初始化为空字典
|
||||
|
||||
if task_dev_data.is_empty():
|
||||
push_warning("Product Focus: Failed to get 'task_development' data from GameState. Using defaults for focus points.")
|
||||
total_points_from_state = 20 # 使用默认总点数
|
||||
else:
|
||||
# 从 task_dev_data 中获取 product_focus_points
|
||||
focus_data = task_dev_data.get("product_focus_points", {})
|
||||
#var task_dev_data: Dictionary = GameState.get_value("task_development", {})
|
||||
var focus_data: Dictionary = get_main_data("产品侧重点",{})
|
||||
if focus_data.is_empty():
|
||||
push_warning("Product Focus: 'product_focus_points' not found in task_development data. Using defaults.")
|
||||
total_points_from_state = 20 # 使用默认总点数
|
||||
@ -231,23 +224,8 @@ func _update_all_button_states():
|
||||
|
||||
# 从父节点加载 Part_4 的信息 (玩法和题材)
|
||||
func _load_part4_info():
|
||||
var parent = get_parent()
|
||||
# 检查父节点和 task_info 是否有效
|
||||
if not is_instance_valid(parent):
|
||||
push_warning("Product Focus: Parent node or its 'task_info' metadata not available for Part 4.")
|
||||
gameplay_info_label.text = "错误"
|
||||
theme_info_label.text = "错误"
|
||||
return
|
||||
|
||||
# 使用 get_meta 获取,避免直接访问可能不存在的属性
|
||||
var task_info = parent.task_info # 提供默认值 null
|
||||
if task_info is Dictionary:
|
||||
gameplay_info_label.text = task_info.get("玩法", "未知")
|
||||
theme_info_label.text = task_info.get("题材", "未知")
|
||||
else:
|
||||
push_warning("Product Focus: Parent's task_info metadata is not a Dictionary or is null.")
|
||||
gameplay_info_label.text = "错误"
|
||||
theme_info_label.text = "错误"
|
||||
gameplay_info_label.text = get_main_data("玩法", "未知")
|
||||
theme_info_label.text = get_main_data("题材", "未知")
|
||||
|
||||
# --- 处理确定按钮的逻辑 ---
|
||||
func _on_confirm_pressed():
|
||||
@ -260,15 +238,6 @@ func _on_confirm_pressed():
|
||||
|
||||
for i in range(category_keys.size()):
|
||||
confirmed_focus_points[category_keys[i]] = category_points[i]
|
||||
|
||||
# 2. 获取父节点 (task_development) 并 传递数据
|
||||
var parent_node = get_parent()
|
||||
if parent_node and parent_node.has_method("update_task_options"):
|
||||
# 通知父节点更新其内部的 task_info
|
||||
parent_node.update_task_options({"产品侧重点": confirmed_focus_points})
|
||||
else:
|
||||
printerr("错误:Product Focus: 父节点未找到或缺少 'update_task_options' 方法。")
|
||||
|
||||
# 3. 进入下一个节点
|
||||
self.hide()
|
||||
parent_node.show_dialogue("谁来写立项书呢?", "proposal")
|
||||
confirmed_focus_points['总数'] = total_points_from_state
|
||||
set_main_data("产品侧重点", confirmed_focus_points)
|
||||
go_next()
|
||||
|
||||
@ -1 +1 @@
|
||||
uid://dfny4mxgw5yb6
|
||||
uid://cvek2tasik7y1
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
[gd_scene load_steps=21 format=3 uid="uid://dpshanwm4o3by"]
|
||||
[gd_scene load_steps=21 format=3 uid="uid://chl131ysu15rd"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://pucudatqrcrq" path="res://UI/popup/popup_bg_1.png" id="1_kjf47"]
|
||||
[ext_resource type="Script" uid="uid://dfny4mxgw5yb6" path="res://UI/popup/task_development/product_focus/product_focus.gd" id="2_dt4oy"]
|
||||
[ext_resource type="FontFile" uid="uid://bbr43ojt1sreu" path="res://UI/font/MinecraftStandard.otf" id="2_klru0"]
|
||||
[ext_resource type="FontFile" uid="uid://egugs822n8gr" path="res://UI/font/AlimamaFangYuanTiVF-Thin.ttf" id="3_hxsho"]
|
||||
[ext_resource type="LabelSettings" uid="uid://qcn0aduvrgvw" path="res://UI/tres/task_development_platform_label_settings.tres" id="3_kjf47"]
|
||||
[ext_resource type="Theme" uid="uid://bau80ps6kx783" path="res://UI/tres/Bottom_Info_button_theme.tres" id="4_hxsho"]
|
||||
[ext_resource type="Texture2D" uid="uid://dgcugleiv7sfw" path="res://UI/popup/task_development/arrow.png" id="4_klru0"]
|
||||
[ext_resource type="Script" uid="uid://cvek2tasik7y1" path="res://UI/popup/task_development/product_focus/product_focus.gd" id="1_qmivp"]
|
||||
[ext_resource type="Texture2D" uid="uid://pucudatqrcrq" path="res://UI/popup/popup_bg_1.png" id="2_hxsho"]
|
||||
[ext_resource type="FontFile" uid="uid://egugs822n8gr" path="res://UI/font/AlimamaFangYuanTiVF-Thin.ttf" id="3_ct65a"]
|
||||
[ext_resource type="FontFile" uid="uid://bbr43ojt1sreu" path="res://UI/font/MinecraftStandard.otf" id="4_lha8x"]
|
||||
[ext_resource type="LabelSettings" uid="uid://qcn0aduvrgvw" path="res://UI/tres/task_development_platform_label_settings.tres" id="5_33nyt"]
|
||||
[ext_resource type="Texture2D" uid="uid://dgcugleiv7sfw" path="res://UI/popup/task_development/arrow.png" id="6_u37th"]
|
||||
[ext_resource type="Theme" uid="uid://bau80ps6kx783" path="res://UI/tres/Bottom_Info_button_theme.tres" id="7_wmlhw"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ct65a"]
|
||||
|
||||
[sub_resource type="LabelSettings" id="LabelSettings_lha8x"]
|
||||
font = ExtResource("2_klru0")
|
||||
font = ExtResource("4_lha8x")
|
||||
font_size = 14
|
||||
outline_size = 6
|
||||
outline_color = Color(0, 0, 0, 1)
|
||||
@ -38,28 +38,37 @@ outline_color = Color(0, 0, 0, 1)
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_so1ex"]
|
||||
|
||||
[node name="product_focus" type="NinePatchRect"]
|
||||
[node name="product_focus" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_qmivp")
|
||||
|
||||
[node name="BG" type="NinePatchRect" parent="."]
|
||||
custom_minimum_size = Vector2(500, 350)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -250.0
|
||||
offset_top = -175.0
|
||||
offset_top = -200.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 175.0
|
||||
offset_bottom = 150.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("1_kjf47")
|
||||
texture = ExtResource("2_hxsho")
|
||||
region_rect = Rect2(1, 35, 86, 53)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 35
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 32
|
||||
script = ExtResource("2_dt4oy")
|
||||
|
||||
[node name="Part_1" type="NinePatchRect" parent="."]
|
||||
[node name="Part_1" type="NinePatchRect" parent="BG"]
|
||||
custom_minimum_size = Vector2(500, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
@ -69,14 +78,14 @@ offset_left = -250.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 44.0
|
||||
grow_horizontal = 2
|
||||
texture = ExtResource("1_kjf47")
|
||||
texture = ExtResource("2_hxsho")
|
||||
region_rect = Rect2(1, 27, 86, 8)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 7
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Title" type="Label" parent="Part_1"]
|
||||
[node name="Title" type="Label" parent="BG/Part_1"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
@ -94,7 +103,7 @@ theme_override_font_sizes/font_size = 27
|
||||
text = "侧重点"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="Part_2" type="Control" parent="."]
|
||||
[node name="Part_2" type="Control" parent="BG"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
@ -105,7 +114,7 @@ offset_right = 20.0
|
||||
offset_bottom = 53.0
|
||||
grow_horizontal = 2
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Part_2"]
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="BG/Part_2"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
@ -120,15 +129,15 @@ grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
alignment = 1
|
||||
|
||||
[node name="Title" type="Label" parent="Part_2/HBoxContainer"]
|
||||
[node name="Title" type="Label" parent="BG/Part_2/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_fonts/font = ExtResource("3_hxsho")
|
||||
theme_override_fonts/font = ExtResource("3_ct65a")
|
||||
theme_override_font_sizes/font_size = 24
|
||||
text = "剩余可用点数"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Points" type="Label" parent="Part_2/HBoxContainer"]
|
||||
[node name="Points" type="Label" parent="BG/Part_2/HBoxContainer"]
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
@ -139,7 +148,7 @@ text = "2"
|
||||
label_settings = SubResource("LabelSettings_lha8x")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Part_3" type="NinePatchRect" parent="."]
|
||||
[node name="Part_3" type="NinePatchRect" parent="BG"]
|
||||
custom_minimum_size = Vector2(440, 200)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
@ -153,14 +162,14 @@ offset_right = 220.0
|
||||
offset_bottom = 109.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("1_kjf47")
|
||||
texture = ExtResource("2_hxsho")
|
||||
region_rect = Rect2(92, 38, 76, 34)
|
||||
patch_margin_left = 2
|
||||
patch_margin_top = 33
|
||||
patch_margin_right = 2
|
||||
patch_margin_bottom = 33
|
||||
|
||||
[node name="GridContainer" type="GridContainer" parent="Part_3"]
|
||||
[node name="GridContainer" type="GridContainer" parent="BG/Part_3"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
@ -177,25 +186,25 @@ theme_override_constants/h_separation = 40
|
||||
theme_override_constants/v_separation = 10
|
||||
columns = 2
|
||||
|
||||
[node name="info_1" type="VBoxContainer" parent="Part_3/GridContainer"]
|
||||
[node name="info_1" type="VBoxContainer" parent="BG/Part_3/GridContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Title" type="Label" parent="Part_3/GridContainer/info_1"]
|
||||
[node name="Title" type="Label" parent="BG/Part_3/GridContainer/info_1"]
|
||||
layout_mode = 2
|
||||
text = "视觉表现"
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
label_settings = ExtResource("5_33nyt")
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Part_3/GridContainer/info_1"]
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="BG/Part_3/GridContainer/info_1"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Previous" type="NinePatchRect" parent="Part_3/GridContainer/info_1/HBoxContainer"]
|
||||
[node name="Previous" type="NinePatchRect" parent="BG/Part_3/GridContainer/info_1/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
texture = ExtResource("6_u37th")
|
||||
region_rect = Rect2(0, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_1/HBoxContainer/Previous"]
|
||||
[node name="Button" type="Button" parent="BG/Part_3/GridContainer/info_1/HBoxContainer/Previous"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@ -207,57 +216,57 @@ theme_override_styles/hover = SubResource("StyleBoxEmpty_hxsho")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_lha8x")
|
||||
flat = true
|
||||
|
||||
[node name="Segments" type="HBoxContainer" parent="Part_3/GridContainer/info_1/HBoxContainer"]
|
||||
[node name="Segments" type="HBoxContainer" parent="BG/Part_3/GridContainer/info_1/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_1" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
[node name="Segment_1" type="ColorRect" parent="BG/Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_2" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
[node name="Segment_2" type="ColorRect" parent="BG/Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_3" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
[node name="Segment_3" type="ColorRect" parent="BG/Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_4" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
[node name="Segment_4" type="ColorRect" parent="BG/Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_5" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
[node name="Segment_5" type="ColorRect" parent="BG/Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_6" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
[node name="Segment_6" type="ColorRect" parent="BG/Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_7" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
[node name="Segment_7" type="ColorRect" parent="BG/Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_8" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
[node name="Segment_8" type="ColorRect" parent="BG/Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_9" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
[node name="Segment_9" type="ColorRect" parent="BG/Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_10" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
[node name="Segment_10" type="ColorRect" parent="BG/Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Next" type="NinePatchRect" parent="Part_3/GridContainer/info_1/HBoxContainer"]
|
||||
[node name="Next" type="NinePatchRect" parent="BG/Part_3/GridContainer/info_1/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
texture = ExtResource("6_u37th")
|
||||
region_rect = Rect2(6, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_1/HBoxContainer/Next"]
|
||||
[node name="Button" type="Button" parent="BG/Part_3/GridContainer/info_1/HBoxContainer/Next"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@ -269,25 +278,25 @@ theme_override_styles/hover = SubResource("StyleBoxEmpty_u37th")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_wmlhw")
|
||||
flat = true
|
||||
|
||||
[node name="info_2" type="VBoxContainer" parent="Part_3/GridContainer"]
|
||||
[node name="info_2" type="VBoxContainer" parent="BG/Part_3/GridContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Title" type="Label" parent="Part_3/GridContainer/info_2"]
|
||||
[node name="Title" type="Label" parent="BG/Part_3/GridContainer/info_2"]
|
||||
layout_mode = 2
|
||||
text = "游戏深度"
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
label_settings = ExtResource("5_33nyt")
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Part_3/GridContainer/info_2"]
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="BG/Part_3/GridContainer/info_2"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Previous" type="NinePatchRect" parent="Part_3/GridContainer/info_2/HBoxContainer"]
|
||||
[node name="Previous" type="NinePatchRect" parent="BG/Part_3/GridContainer/info_2/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
texture = ExtResource("6_u37th")
|
||||
region_rect = Rect2(0, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_2/HBoxContainer/Previous"]
|
||||
[node name="Button" type="Button" parent="BG/Part_3/GridContainer/info_2/HBoxContainer/Previous"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@ -299,57 +308,57 @@ theme_override_styles/hover = SubResource("StyleBoxEmpty_hxsho")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_lha8x")
|
||||
flat = true
|
||||
|
||||
[node name="Segments" type="HBoxContainer" parent="Part_3/GridContainer/info_2/HBoxContainer"]
|
||||
[node name="Segments" type="HBoxContainer" parent="BG/Part_3/GridContainer/info_2/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_1" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
[node name="Segment_1" type="ColorRect" parent="BG/Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_2" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
[node name="Segment_2" type="ColorRect" parent="BG/Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_3" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
[node name="Segment_3" type="ColorRect" parent="BG/Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_4" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
[node name="Segment_4" type="ColorRect" parent="BG/Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_5" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
[node name="Segment_5" type="ColorRect" parent="BG/Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_6" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
[node name="Segment_6" type="ColorRect" parent="BG/Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_7" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
[node name="Segment_7" type="ColorRect" parent="BG/Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_8" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
[node name="Segment_8" type="ColorRect" parent="BG/Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_9" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
[node name="Segment_9" type="ColorRect" parent="BG/Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_10" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
[node name="Segment_10" type="ColorRect" parent="BG/Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Next" type="NinePatchRect" parent="Part_3/GridContainer/info_2/HBoxContainer"]
|
||||
[node name="Next" type="NinePatchRect" parent="BG/Part_3/GridContainer/info_2/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
texture = ExtResource("6_u37th")
|
||||
region_rect = Rect2(6, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_2/HBoxContainer/Next"]
|
||||
[node name="Button" type="Button" parent="BG/Part_3/GridContainer/info_2/HBoxContainer/Next"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@ -361,25 +370,25 @@ theme_override_styles/hover = SubResource("StyleBoxEmpty_u37th")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_wmlhw")
|
||||
flat = true
|
||||
|
||||
[node name="info_3" type="VBoxContainer" parent="Part_3/GridContainer"]
|
||||
[node name="info_3" type="VBoxContainer" parent="BG/Part_3/GridContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Title" type="Label" parent="Part_3/GridContainer/info_3"]
|
||||
[node name="Title" type="Label" parent="BG/Part_3/GridContainer/info_3"]
|
||||
layout_mode = 2
|
||||
text = "创新性"
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
label_settings = ExtResource("5_33nyt")
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Part_3/GridContainer/info_3"]
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="BG/Part_3/GridContainer/info_3"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Previous" type="NinePatchRect" parent="Part_3/GridContainer/info_3/HBoxContainer"]
|
||||
[node name="Previous" type="NinePatchRect" parent="BG/Part_3/GridContainer/info_3/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
texture = ExtResource("6_u37th")
|
||||
region_rect = Rect2(0, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_3/HBoxContainer/Previous"]
|
||||
[node name="Button" type="Button" parent="BG/Part_3/GridContainer/info_3/HBoxContainer/Previous"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@ -391,57 +400,57 @@ theme_override_styles/hover = SubResource("StyleBoxEmpty_hxsho")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_lha8x")
|
||||
flat = true
|
||||
|
||||
[node name="Segments" type="HBoxContainer" parent="Part_3/GridContainer/info_3/HBoxContainer"]
|
||||
[node name="Segments" type="HBoxContainer" parent="BG/Part_3/GridContainer/info_3/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_1" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
[node name="Segment_1" type="ColorRect" parent="BG/Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_2" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
[node name="Segment_2" type="ColorRect" parent="BG/Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_3" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
[node name="Segment_3" type="ColorRect" parent="BG/Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_4" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
[node name="Segment_4" type="ColorRect" parent="BG/Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_5" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
[node name="Segment_5" type="ColorRect" parent="BG/Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_6" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
[node name="Segment_6" type="ColorRect" parent="BG/Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_7" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
[node name="Segment_7" type="ColorRect" parent="BG/Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_8" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
[node name="Segment_8" type="ColorRect" parent="BG/Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_9" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
[node name="Segment_9" type="ColorRect" parent="BG/Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_10" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
[node name="Segment_10" type="ColorRect" parent="BG/Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Next" type="NinePatchRect" parent="Part_3/GridContainer/info_3/HBoxContainer"]
|
||||
[node name="Next" type="NinePatchRect" parent="BG/Part_3/GridContainer/info_3/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
texture = ExtResource("6_u37th")
|
||||
region_rect = Rect2(6, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_3/HBoxContainer/Next"]
|
||||
[node name="Button" type="Button" parent="BG/Part_3/GridContainer/info_3/HBoxContainer/Next"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@ -453,25 +462,25 @@ theme_override_styles/hover = SubResource("StyleBoxEmpty_u37th")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_wmlhw")
|
||||
flat = true
|
||||
|
||||
[node name="info_4" type="VBoxContainer" parent="Part_3/GridContainer"]
|
||||
[node name="info_4" type="VBoxContainer" parent="BG/Part_3/GridContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Title" type="Label" parent="Part_3/GridContainer/info_4"]
|
||||
[node name="Title" type="Label" parent="BG/Part_3/GridContainer/info_4"]
|
||||
layout_mode = 2
|
||||
text = "易玩性"
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
label_settings = ExtResource("5_33nyt")
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Part_3/GridContainer/info_4"]
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="BG/Part_3/GridContainer/info_4"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Previous" type="NinePatchRect" parent="Part_3/GridContainer/info_4/HBoxContainer"]
|
||||
[node name="Previous" type="NinePatchRect" parent="BG/Part_3/GridContainer/info_4/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
texture = ExtResource("6_u37th")
|
||||
region_rect = Rect2(0, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_4/HBoxContainer/Previous"]
|
||||
[node name="Button" type="Button" parent="BG/Part_3/GridContainer/info_4/HBoxContainer/Previous"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@ -483,57 +492,57 @@ theme_override_styles/hover = SubResource("StyleBoxEmpty_hxsho")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_lha8x")
|
||||
flat = true
|
||||
|
||||
[node name="Segments" type="HBoxContainer" parent="Part_3/GridContainer/info_4/HBoxContainer"]
|
||||
[node name="Segments" type="HBoxContainer" parent="BG/Part_3/GridContainer/info_4/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_1" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
[node name="Segment_1" type="ColorRect" parent="BG/Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_2" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
[node name="Segment_2" type="ColorRect" parent="BG/Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_3" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
[node name="Segment_3" type="ColorRect" parent="BG/Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_4" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
[node name="Segment_4" type="ColorRect" parent="BG/Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_5" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
[node name="Segment_5" type="ColorRect" parent="BG/Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_6" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
[node name="Segment_6" type="ColorRect" parent="BG/Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_7" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
[node name="Segment_7" type="ColorRect" parent="BG/Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_8" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
[node name="Segment_8" type="ColorRect" parent="BG/Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_9" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
[node name="Segment_9" type="ColorRect" parent="BG/Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_10" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
[node name="Segment_10" type="ColorRect" parent="BG/Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Next" type="NinePatchRect" parent="Part_3/GridContainer/info_4/HBoxContainer"]
|
||||
[node name="Next" type="NinePatchRect" parent="BG/Part_3/GridContainer/info_4/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
texture = ExtResource("6_u37th")
|
||||
region_rect = Rect2(6, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_4/HBoxContainer/Next"]
|
||||
[node name="Button" type="Button" parent="BG/Part_3/GridContainer/info_4/HBoxContainer/Next"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@ -545,25 +554,25 @@ theme_override_styles/hover = SubResource("StyleBoxEmpty_u37th")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_wmlhw")
|
||||
flat = true
|
||||
|
||||
[node name="info_5" type="VBoxContainer" parent="Part_3/GridContainer"]
|
||||
[node name="info_5" type="VBoxContainer" parent="BG/Part_3/GridContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Title" type="Label" parent="Part_3/GridContainer/info_5"]
|
||||
[node name="Title" type="Label" parent="BG/Part_3/GridContainer/info_5"]
|
||||
layout_mode = 2
|
||||
text = "操控感"
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
label_settings = ExtResource("5_33nyt")
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Part_3/GridContainer/info_5"]
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="BG/Part_3/GridContainer/info_5"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Previous" type="NinePatchRect" parent="Part_3/GridContainer/info_5/HBoxContainer"]
|
||||
[node name="Previous" type="NinePatchRect" parent="BG/Part_3/GridContainer/info_5/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
texture = ExtResource("6_u37th")
|
||||
region_rect = Rect2(0, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_5/HBoxContainer/Previous"]
|
||||
[node name="Button" type="Button" parent="BG/Part_3/GridContainer/info_5/HBoxContainer/Previous"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@ -575,57 +584,57 @@ theme_override_styles/hover = SubResource("StyleBoxEmpty_hxsho")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_lha8x")
|
||||
flat = true
|
||||
|
||||
[node name="Segments" type="HBoxContainer" parent="Part_3/GridContainer/info_5/HBoxContainer"]
|
||||
[node name="Segments" type="HBoxContainer" parent="BG/Part_3/GridContainer/info_5/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_1" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
[node name="Segment_1" type="ColorRect" parent="BG/Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_2" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
[node name="Segment_2" type="ColorRect" parent="BG/Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_3" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
[node name="Segment_3" type="ColorRect" parent="BG/Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_4" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
[node name="Segment_4" type="ColorRect" parent="BG/Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_5" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
[node name="Segment_5" type="ColorRect" parent="BG/Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_6" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
[node name="Segment_6" type="ColorRect" parent="BG/Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_7" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
[node name="Segment_7" type="ColorRect" parent="BG/Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_8" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
[node name="Segment_8" type="ColorRect" parent="BG/Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_9" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
[node name="Segment_9" type="ColorRect" parent="BG/Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_10" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
[node name="Segment_10" type="ColorRect" parent="BG/Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Next" type="NinePatchRect" parent="Part_3/GridContainer/info_5/HBoxContainer"]
|
||||
[node name="Next" type="NinePatchRect" parent="BG/Part_3/GridContainer/info_5/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
texture = ExtResource("6_u37th")
|
||||
region_rect = Rect2(6, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_5/HBoxContainer/Next"]
|
||||
[node name="Button" type="Button" parent="BG/Part_3/GridContainer/info_5/HBoxContainer/Next"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@ -637,25 +646,25 @@ theme_override_styles/hover = SubResource("StyleBoxEmpty_u37th")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_wmlhw")
|
||||
flat = true
|
||||
|
||||
[node name="info_6" type="VBoxContainer" parent="Part_3/GridContainer"]
|
||||
[node name="info_6" type="VBoxContainer" parent="BG/Part_3/GridContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Title" type="Label" parent="Part_3/GridContainer/info_6"]
|
||||
[node name="Title" type="Label" parent="BG/Part_3/GridContainer/info_6"]
|
||||
layout_mode = 2
|
||||
text = "沉浸感"
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
label_settings = ExtResource("5_33nyt")
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Part_3/GridContainer/info_6"]
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="BG/Part_3/GridContainer/info_6"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Previous" type="NinePatchRect" parent="Part_3/GridContainer/info_6/HBoxContainer"]
|
||||
[node name="Previous" type="NinePatchRect" parent="BG/Part_3/GridContainer/info_6/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
texture = ExtResource("6_u37th")
|
||||
region_rect = Rect2(0, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_6/HBoxContainer/Previous"]
|
||||
[node name="Button" type="Button" parent="BG/Part_3/GridContainer/info_6/HBoxContainer/Previous"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@ -667,57 +676,57 @@ theme_override_styles/hover = SubResource("StyleBoxEmpty_hxsho")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_lha8x")
|
||||
flat = true
|
||||
|
||||
[node name="Segments" type="HBoxContainer" parent="Part_3/GridContainer/info_6/HBoxContainer"]
|
||||
[node name="Segments" type="HBoxContainer" parent="BG/Part_3/GridContainer/info_6/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_1" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
[node name="Segment_1" type="ColorRect" parent="BG/Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_2" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
[node name="Segment_2" type="ColorRect" parent="BG/Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_3" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
[node name="Segment_3" type="ColorRect" parent="BG/Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_4" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
[node name="Segment_4" type="ColorRect" parent="BG/Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_5" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
[node name="Segment_5" type="ColorRect" parent="BG/Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_6" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
[node name="Segment_6" type="ColorRect" parent="BG/Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_7" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
[node name="Segment_7" type="ColorRect" parent="BG/Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_8" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
[node name="Segment_8" type="ColorRect" parent="BG/Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_9" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
[node name="Segment_9" type="ColorRect" parent="BG/Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_10" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
[node name="Segment_10" type="ColorRect" parent="BG/Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Next" type="NinePatchRect" parent="Part_3/GridContainer/info_6/HBoxContainer"]
|
||||
[node name="Next" type="NinePatchRect" parent="BG/Part_3/GridContainer/info_6/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
texture = ExtResource("6_u37th")
|
||||
region_rect = Rect2(6, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_6/HBoxContainer/Next"]
|
||||
[node name="Button" type="Button" parent="BG/Part_3/GridContainer/info_6/HBoxContainer/Next"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@ -729,7 +738,7 @@ theme_override_styles/hover = SubResource("StyleBoxEmpty_u37th")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_wmlhw")
|
||||
flat = true
|
||||
|
||||
[node name="Part_4" type="VBoxContainer" parent="."]
|
||||
[node name="Part_4" type="VBoxContainer" parent="BG"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 2
|
||||
anchor_top = 1.0
|
||||
@ -741,33 +750,33 @@ offset_bottom = -11.0
|
||||
grow_vertical = 0
|
||||
theme_override_constants/separation = 2
|
||||
|
||||
[node name="gameplay" type="HBoxContainer" parent="Part_4"]
|
||||
[node name="gameplay" type="HBoxContainer" parent="BG/Part_4"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="title" type="Label" parent="Part_4/gameplay"]
|
||||
[node name="title" type="Label" parent="BG/Part_4/gameplay"]
|
||||
layout_mode = 2
|
||||
text = "玩法 - "
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
label_settings = ExtResource("5_33nyt")
|
||||
|
||||
[node name="info" type="Label" parent="Part_4/gameplay"]
|
||||
[node name="info" type="Label" parent="BG/Part_4/gameplay"]
|
||||
layout_mode = 2
|
||||
text = "桌面游戏"
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
label_settings = ExtResource("5_33nyt")
|
||||
|
||||
[node name="theme" type="HBoxContainer" parent="Part_4"]
|
||||
[node name="theme" type="HBoxContainer" parent="BG/Part_4"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="title" type="Label" parent="Part_4/theme"]
|
||||
[node name="title" type="Label" parent="BG/Part_4/theme"]
|
||||
layout_mode = 2
|
||||
text = "题材 - "
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
label_settings = ExtResource("5_33nyt")
|
||||
|
||||
[node name="info" type="Label" parent="Part_4/theme"]
|
||||
[node name="info" type="Label" parent="BG/Part_4/theme"]
|
||||
layout_mode = 2
|
||||
text = "校园模拟"
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
label_settings = ExtResource("5_33nyt")
|
||||
|
||||
[node name="Confirm" type="Button" parent="."]
|
||||
[node name="Confirm" type="Button" parent="BG"]
|
||||
custom_minimum_size = Vector2(70, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 3
|
||||
@ -781,10 +790,10 @@ offset_right = -67.0
|
||||
offset_bottom = -15.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 0
|
||||
theme = ExtResource("4_hxsho")
|
||||
theme = ExtResource("7_wmlhw")
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_focus_color = Color(0, 0, 0, 1)
|
||||
theme_override_fonts/font = ExtResource("3_hxsho")
|
||||
theme_override_fonts/font = ExtResource("3_ct65a")
|
||||
theme_override_font_sizes/font_size = 23
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_rjt3h")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxFlat_ykocv")
|
||||
|
||||
16
UI/popup/task_development/proposal/proposal.gd
Normal file
16
UI/popup/task_development/proposal/proposal.gd
Normal file
@ -0,0 +1,16 @@
|
||||
extends NinePatchRect
|
||||
|
||||
@onready var confirm_button: Button = $Confirm
|
||||
|
||||
func _ready() -> void:
|
||||
var node_name = str(self.name)
|
||||
add_to_group(node_name)
|
||||
|
||||
if confirm_button:
|
||||
if not confirm_button.pressed.is_connected(_on_confirm_pressed):
|
||||
confirm_button.pressed.connect(_on_confirm_pressed)
|
||||
|
||||
func _on_confirm_pressed():
|
||||
get_parent().start_task()
|
||||
self.hide()
|
||||
get_parent().close_all_popups()
|
||||
632
UI/popup/task_development/proposal/proposal.tscn
Normal file
632
UI/popup/task_development/proposal/proposal.tscn
Normal file
@ -0,0 +1,632 @@
|
||||
[gd_scene load_steps=31 format=3 uid="uid://be000l53jxash"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://pucudatqrcrq" path="res://UI/popup/popup_bg_1.png" id="1_0ruly"]
|
||||
[ext_resource type="Script" uid="uid://ciqayqceaadw4" path="res://UI/popup/task_development/proposal/proposal.gd" id="2_uudne"]
|
||||
[ext_resource type="Texture2D" uid="uid://dgcugleiv7sfw" path="res://UI/popup/task_development/arrow.png" id="3_uudne"]
|
||||
[ext_resource type="FontFile" uid="uid://egugs822n8gr" path="res://UI/font/AlimamaFangYuanTiVF-Thin.ttf" id="4_csatq"]
|
||||
[ext_resource type="LabelSettings" uid="uid://qcn0aduvrgvw" path="res://UI/tres/task_development_platform_label_settings.tres" id="5_l6j0s"]
|
||||
[ext_resource type="Texture2D" uid="uid://bb3kyiufyyj05" path="res://Entity/NPC/NPC_1_UI.png" id="5_uudne"]
|
||||
[ext_resource type="Theme" uid="uid://bau80ps6kx783" path="res://UI/tres/Bottom_Info_button_theme.tres" id="6_6v1sj"]
|
||||
[ext_resource type="Texture2D" uid="uid://hdidwixuokxn" path="res://Entity/NPC/npc_ability_icon.png" id="6_ybd2x"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_6a8uh"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_bu5lv"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_mue51"]
|
||||
|
||||
[sub_resource type="Animation" id="Animation_bu5lv"]
|
||||
length = 0.001
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Title/previous:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [Vector2(9, 7)]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_6a8uh"]
|
||||
resource_name = "base"
|
||||
length = 0.6
|
||||
loop_mode = 1
|
||||
step = 0.2
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Title/previous:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.2, 0.4, 0.6),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [Vector2(16, 7), Vector2(12, 7), Vector2(9, 7), Vector2(16, 7)]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_mue51"]
|
||||
_data = {
|
||||
&"RESET": SubResource("Animation_bu5lv"),
|
||||
&"base": SubResource("Animation_6a8uh")
|
||||
}
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_wpgbx"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_r6b7x"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_hsiy4"]
|
||||
|
||||
[sub_resource type="Animation" id="Animation_wpgbx"]
|
||||
length = 0.001
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath(".:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [Vector2(461, 7)]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_mue51"]
|
||||
resource_name = "base"
|
||||
length = 0.6
|
||||
loop_mode = 1
|
||||
step = 0.2
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath(".:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.2, 0.4, 0.6),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [Vector2(455, 7), Vector2(458, 7), Vector2(461, 7), Vector2(455, 7)]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_r6b7x"]
|
||||
_data = {
|
||||
&"RESET": SubResource("Animation_wpgbx"),
|
||||
&"base": SubResource("Animation_mue51")
|
||||
}
|
||||
|
||||
[sub_resource type="LabelSettings" id="LabelSettings_l6j0s"]
|
||||
font = ExtResource("4_csatq")
|
||||
font_size = 23
|
||||
font_color = Color(0, 0, 0, 1)
|
||||
|
||||
[sub_resource type="LabelSettings" id="LabelSettings_6v1sj"]
|
||||
font = ExtResource("4_csatq")
|
||||
font_size = 24
|
||||
font_color = Color(0, 0, 0, 1)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_nckjb"]
|
||||
bg_color = Color(0.913725, 0.913725, 0.913725, 0.913725)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_qrj6y"]
|
||||
bg_color = Color(0.913725, 0.913725, 0.913725, 0.913725)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_v0qi7"]
|
||||
bg_color = Color(0.913725, 0.913725, 0.913725, 0.913725)
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_rl25l"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_tndxe"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_xx8ge"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ep6fu"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ci4su"]
|
||||
|
||||
[node name="proposal" type="NinePatchRect"]
|
||||
custom_minimum_size = Vector2(500, 350)
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -250.0
|
||||
offset_top = -175.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 175.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("1_0ruly")
|
||||
region_rect = Rect2(1, 35, 86, 53)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 35
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 32
|
||||
script = ExtResource("2_uudne")
|
||||
|
||||
[node name="Title" type="NinePatchRect" parent="."]
|
||||
custom_minimum_size = Vector2(500, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -250.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 44.0
|
||||
grow_horizontal = 2
|
||||
texture = ExtResource("1_0ruly")
|
||||
region_rect = Rect2(1, 27, 86, 8)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 7
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Title" type="Label" parent="Title"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -34.5
|
||||
offset_top = -18.0
|
||||
offset_right = 34.5
|
||||
offset_bottom = 18.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 27
|
||||
text = "策划案负责人"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="previous" type="NinePatchRect" parent="Title"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 4
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 9.0
|
||||
offset_top = -15.0
|
||||
offset_right = 39.0
|
||||
offset_bottom = 15.0
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("3_uudne")
|
||||
region_rect = Rect2(0, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Title/previous"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_6a8uh")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_bu5lv")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_mue51")
|
||||
flat = true
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="Title/previous"]
|
||||
root_node = NodePath("../../..")
|
||||
libraries = {
|
||||
&"": SubResource("AnimationLibrary_mue51")
|
||||
}
|
||||
autoplay = "base"
|
||||
|
||||
[node name="next" type="NinePatchRect" parent="Title"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 6
|
||||
anchor_left = 1.0
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -39.0
|
||||
offset_top = -15.0
|
||||
offset_right = -9.0
|
||||
offset_bottom = 15.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("3_uudne")
|
||||
region_rect = Rect2(6, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Title/next"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_wpgbx")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_r6b7x")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_hsiy4")
|
||||
flat = true
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="Title/next"]
|
||||
libraries = {
|
||||
&"": SubResource("AnimationLibrary_r6b7x")
|
||||
}
|
||||
autoplay = "base"
|
||||
|
||||
[node name="Option" type="Control" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="NPC_Info_1" type="HBoxContainer" parent="Option"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -170.0
|
||||
offset_top = 47.0
|
||||
offset_right = 202.0
|
||||
offset_bottom = 87.0
|
||||
grow_horizontal = 2
|
||||
theme_override_constants/separation = 160
|
||||
|
||||
[node name="Name" type="Label" parent="Option/NPC_Info_1"]
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 24
|
||||
text = "米子一"
|
||||
label_settings = SubResource("LabelSettings_l6j0s")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Staff" type="Label" parent="Option/NPC_Info_1"]
|
||||
custom_minimum_size = Vector2(140, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_fonts/font = ExtResource("4_csatq")
|
||||
theme_override_font_sizes/font_size = 20
|
||||
text = "员工"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="NPC_Info_2" type="NinePatchRect" parent="Option"]
|
||||
custom_minimum_size = Vector2(440, 200)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -220.0
|
||||
offset_top = -92.0
|
||||
offset_right = 220.0
|
||||
offset_bottom = 130.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("1_0ruly")
|
||||
region_rect = Rect2(92, 38, 76, 34)
|
||||
patch_margin_left = 2
|
||||
patch_margin_top = 33
|
||||
patch_margin_right = 2
|
||||
patch_margin_bottom = 33
|
||||
|
||||
[node name="Info_List_0" type="VBoxContainer" parent="Option/NPC_Info_2"]
|
||||
custom_minimum_size = Vector2(0, 95)
|
||||
layout_mode = 0
|
||||
offset_left = 26.0
|
||||
offset_top = 23.0
|
||||
offset_right = 185.0
|
||||
offset_bottom = 147.0
|
||||
theme_override_constants/separation = 14
|
||||
|
||||
[node name="Job" type="HBoxContainer" parent="Option/NPC_Info_2/Info_List_0"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 25
|
||||
|
||||
[node name="Label" type="Label" parent="Option/NPC_Info_2/Info_List_0/Job"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
text = "产品总监"
|
||||
label_settings = SubResource("LabelSettings_6v1sj")
|
||||
|
||||
[node name="Level" type="Label" parent="Option/NPC_Info_2/Info_List_0/Job"]
|
||||
layout_mode = 2
|
||||
text = "Lv1"
|
||||
label_settings = SubResource("LabelSettings_6v1sj")
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Icon" type="TextureRect" parent="Option/NPC_Info_2/Info_List_0"]
|
||||
custom_minimum_size = Vector2(95, 95)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("5_uudne")
|
||||
stretch_mode = 5
|
||||
|
||||
[node name="Info_List_1" type="GridContainer" parent="Option/NPC_Info_2"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 6
|
||||
anchor_left = 1.0
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -204.0
|
||||
offset_top = -87.0
|
||||
offset_right = -8.0
|
||||
offset_bottom = 46.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 2
|
||||
theme_override_constants/v_separation = 7
|
||||
|
||||
[node name="Info_1" type="HBoxContainer" parent="Option/NPC_Info_2/Info_List_1"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="icon" type="NinePatchRect" parent="Option/NPC_Info_2/Info_List_1/Info_1"]
|
||||
custom_minimum_size = Vector2(28, 28)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("6_ybd2x")
|
||||
region_rect = Rect2(38, 30, 20, 15)
|
||||
|
||||
[node name="title" type="Label" parent="Option/NPC_Info_2/Info_List_1/Info_1"]
|
||||
custom_minimum_size = Vector2(60, 0)
|
||||
layout_mode = 2
|
||||
theme_override_fonts/font = ExtResource("4_csatq")
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_nckjb")
|
||||
text = "策划"
|
||||
label_settings = ExtResource("5_l6j0s")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info" type="Label" parent="Option/NPC_Info_2/Info_List_1/Info_1"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
text = "80"
|
||||
label_settings = ExtResource("5_l6j0s")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Info_2" type="HBoxContainer" parent="Option/NPC_Info_2/Info_List_1"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="icon" type="NinePatchRect" parent="Option/NPC_Info_2/Info_List_1/Info_2"]
|
||||
custom_minimum_size = Vector2(28, 28)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("6_ybd2x")
|
||||
region_rect = Rect2(12, 31, 17, 16)
|
||||
|
||||
[node name="title" type="Label" parent="Option/NPC_Info_2/Info_List_1/Info_2"]
|
||||
custom_minimum_size = Vector2(60, 0)
|
||||
layout_mode = 2
|
||||
theme_override_fonts/font = ExtResource("4_csatq")
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_nckjb")
|
||||
text = "程序"
|
||||
label_settings = ExtResource("5_l6j0s")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info" type="Label" parent="Option/NPC_Info_2/Info_List_1/Info_2"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
text = "80"
|
||||
label_settings = ExtResource("5_l6j0s")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Info_3" type="HBoxContainer" parent="Option/NPC_Info_2/Info_List_1"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="icon" type="NinePatchRect" parent="Option/NPC_Info_2/Info_List_1/Info_3"]
|
||||
custom_minimum_size = Vector2(28, 28)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("6_ybd2x")
|
||||
region_rect = Rect2(63, 29, 21, 16)
|
||||
|
||||
[node name="title" type="Label" parent="Option/NPC_Info_2/Info_List_1/Info_3"]
|
||||
custom_minimum_size = Vector2(60, 0)
|
||||
layout_mode = 2
|
||||
theme_override_fonts/font = ExtResource("4_csatq")
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_nckjb")
|
||||
text = "美术"
|
||||
label_settings = ExtResource("5_l6j0s")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info" type="Label" parent="Option/NPC_Info_2/Info_List_1/Info_3"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
text = "80"
|
||||
label_settings = ExtResource("5_l6j0s")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Info_4" type="HBoxContainer" parent="Option/NPC_Info_2/Info_List_1"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="icon" type="NinePatchRect" parent="Option/NPC_Info_2/Info_List_1/Info_4"]
|
||||
custom_minimum_size = Vector2(28, 28)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("6_ybd2x")
|
||||
region_rect = Rect2(92, 29, 22, 16)
|
||||
|
||||
[node name="title" type="Label" parent="Option/NPC_Info_2/Info_List_1/Info_4"]
|
||||
custom_minimum_size = Vector2(60, 0)
|
||||
layout_mode = 2
|
||||
theme_override_fonts/font = ExtResource("4_csatq")
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_nckjb")
|
||||
text = "音频"
|
||||
label_settings = ExtResource("5_l6j0s")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info" type="Label" parent="Option/NPC_Info_2/Info_List_1/Info_4"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
text = "80"
|
||||
label_settings = ExtResource("5_l6j0s")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Info_List_2" type="HBoxContainer" parent="Option/NPC_Info_2"]
|
||||
custom_minimum_size = Vector2(160, 10)
|
||||
layout_mode = 1
|
||||
offset_left = 27.0
|
||||
offset_top = 159.0
|
||||
offset_right = 187.0
|
||||
offset_bottom = 169.0
|
||||
theme_override_constants/separation = 0
|
||||
alignment = 1
|
||||
|
||||
[node name="Segment_1" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_2" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_3" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_4" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_5" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_6" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_7" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_8" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_9" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_10" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_11" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_12" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_13" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_14" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_15" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_16" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_17" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_18" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_19" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_20" type="ColorRect" parent="Option/NPC_Info_2/Info_List_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Info_List_3" type="HBoxContainer" parent="Option/NPC_Info_2"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 7
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -191.5
|
||||
offset_top = -38.0
|
||||
offset_right = 191.5
|
||||
offset_bottom = -10.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
|
||||
[node name="info_4" type="HBoxContainer" parent="Option/NPC_Info_2/Info_List_3"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="title" type="Label" parent="Option/NPC_Info_2/Info_List_3/info_4"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
theme_override_fonts/font = ExtResource("4_csatq")
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_qrj6y")
|
||||
text = "费用"
|
||||
label_settings = ExtResource("5_l6j0s")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info" type="Label" parent="Option/NPC_Info_2/Info_List_3/info_4"]
|
||||
custom_minimum_size = Vector2(70, 0)
|
||||
layout_mode = 2
|
||||
text = "500"
|
||||
label_settings = ExtResource("5_l6j0s")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info_5" type="HBoxContainer" parent="Option/NPC_Info_2/Info_List_3"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
[node name="title" type="Label" parent="Option/NPC_Info_2/Info_List_3/info_5"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_v0qi7")
|
||||
text = "开发次数"
|
||||
label_settings = ExtResource("5_l6j0s")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info" type="Label" parent="Option/NPC_Info_2/Info_List_3/info_5"]
|
||||
custom_minimum_size = Vector2(30, 0)
|
||||
layout_mode = 2
|
||||
text = "0"
|
||||
label_settings = ExtResource("5_l6j0s")
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="unit" type="Label" parent="Option/NPC_Info_2/Info_List_3/info_5"]
|
||||
layout_mode = 2
|
||||
text = "次"
|
||||
label_settings = ExtResource("5_l6j0s")
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Confirm" type="Button" parent="."]
|
||||
custom_minimum_size = Vector2(70, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 7
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -35.0
|
||||
offset_top = -43.0
|
||||
offset_right = 35.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
theme = ExtResource("6_6v1sj")
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_focus_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 23
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_rl25l")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxFlat_tndxe")
|
||||
theme_override_styles/hover = SubResource("StyleBoxFlat_xx8ge")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_ep6fu")
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_ci4su")
|
||||
text = "确定"
|
||||
@ -23,13 +23,12 @@ var is_active: bool = false
|
||||
|
||||
# 存储用户在当前配置过程中的临时选择 (使用中文 Key)
|
||||
var task_info: Dictionary = {
|
||||
"平台": "",
|
||||
"玩法": "",
|
||||
"题材": "",
|
||||
"开发策略": "",
|
||||
"预算": 0,
|
||||
"产品侧重点": {},
|
||||
"关键环节负责人": [] # <--- 新增并初始化为空数组
|
||||
"平台": "", # 中文 Key for the selected platform (e.g., "台式 & 笔记本")
|
||||
"玩法": "", # 中文 Key for the selected gameplay (e.g., "角色扮演(RPG)")
|
||||
"题材": "", # 中文 Key for the selected theme (e.g., "现代都市")
|
||||
"开发策略": "", # 中文 Key for the selected strategy (e.g., "正常开发")
|
||||
"预算": 0, # Calculated budget based on selections
|
||||
"产品侧重点": {} # To be filled by product_focus popup
|
||||
}
|
||||
|
||||
# --- 初始化 ---
|
||||
@ -274,41 +273,23 @@ func _on_category_button_pressed(popup_node: Control) -> void:
|
||||
|
||||
|
||||
# 提供给子弹出窗口调用的接口函数,用于更新选择
|
||||
# options: 字典,包含更新的类别和对应的 Key
|
||||
# options: 字典,包含更新的类别和对应的 Key,例如 {"平台": "Switch"}
|
||||
func update_task_options(options: Dictionary) -> void:
|
||||
var updated = false
|
||||
for key in options:
|
||||
var new_value = options[key]
|
||||
|
||||
if key == "关键环节负责人":
|
||||
# --- 特殊处理 "关键环节负责人" ---
|
||||
if not task_info.has(key) or not typeof(task_info[key]) == TYPE_ARRAY:
|
||||
task_info[key] = [] # 如果不存在或类型不对,则初始化为空数组
|
||||
|
||||
if not new_value in task_info[key]: # 避免重复添加 (可选,根据需求)
|
||||
task_info[key].append(new_value)
|
||||
for key in options: # key 是 "平台", "玩法" 等中文名
|
||||
if task_info.has(key):
|
||||
var new_value_key = options[key] # new_value_key 是 "Switch" 等中文 Key
|
||||
if task_info[key] != new_value_key:
|
||||
task_info[key] = new_value_key
|
||||
updated = true
|
||||
print(node_name + ": Appended '%s' to '%s'. Current: %s" % [new_value, key, task_info[key]])
|
||||
print(node_name + ": Option '%s' updated to '%s'." % [key, new_value_key])
|
||||
else:
|
||||
print(node_name + ": '%s' already in '%s'. No change." % [new_value, key])
|
||||
|
||||
elif task_info.has(key):
|
||||
# --- 原有逻辑处理其他普通键值对 ---
|
||||
if task_info[key] != new_value:
|
||||
task_info[key] = new_value
|
||||
updated = true
|
||||
print(node_name + ": Option '%s' updated to '%s'." % [key, new_value])
|
||||
else:
|
||||
printerr(node_name + ": Invalid key '%s' provided in update_task_options and not handled as a special case." % key)
|
||||
printerr(node_name + ": Invalid key '%s' provided in update_task_options." % key)
|
||||
|
||||
if updated:
|
||||
# 对于 "关键环节负责人" 的更新,通常不需要更新按钮文本或重新计算预算
|
||||
# 但如果其他选项更新了,则需要执行
|
||||
if not (options.has("关键环节负责人") and options.size() == 1): # 如果不仅仅是更新负责人
|
||||
update_button_texts()
|
||||
calculate_and_update_budget()
|
||||
|
||||
print(node_name + ": Task info updated: ", task_info)
|
||||
update_button_texts() # 更新主界面按钮显示名称
|
||||
calculate_and_update_budget() # 重新计算预算
|
||||
print(node_name + ": Task info updated: ", task_info) # Debug
|
||||
|
||||
# 处理子弹出窗口确认后关闭并返回主页面的逻辑
|
||||
func _close_child_popup_and_return(child_popup_node: Control) -> void:
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
[ext_resource type="PackedScene" uid="uid://bej6f0cqirn4j" path="res://UI/popup/task_development/theme/theme.tscn" id="8_nckjb"]
|
||||
[ext_resource type="PackedScene" uid="uid://ctcbxvgljrkvi" path="res://UI/popup/task_development/strategy/strategy.tscn" id="9_6r1e0"]
|
||||
[ext_resource type="PackedScene" uid="uid://dpshanwm4o3by" path="res://UI/popup/task_development/product_focus/product_focus.tscn" id="10_at31c"]
|
||||
[ext_resource type="PackedScene" uid="uid://be000l53jxash" path="res://UI/popup/task_development/key_output/proposal.tscn" id="12_v0qi7"]
|
||||
[ext_resource type="PackedScene" uid="uid://be000l53jxash" path="res://UI/popup/task_development/proposal/proposal.tscn" id="12_v0qi7"]
|
||||
[ext_resource type="PackedScene" uid="uid://dtywh0m5odikx" path="res://UI/popup/dialogue.tscn" id="13_kctqw"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_xtl2p"]
|
||||
|
||||
87
UI/popup/task_development/task_development_start.tscn
Normal file
87
UI/popup/task_development/task_development_start.tscn
Normal file
@ -0,0 +1,87 @@
|
||||
[gd_scene load_steps=10 format=3 uid="uid://b5npsmec2fo2w"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://du4qd5ynhkjs6" path="res://UI/ui_framework.gd" id="1_6fk5m"]
|
||||
[ext_resource type="PackedScene" uid="uid://bfmnpiqcyi83h" path="res://UI/popup/task_development/main_plan/main_plan.tscn" id="2_qpnja"]
|
||||
[ext_resource type="PackedScene" uid="uid://hidwgnr45bw7" path="res://UI/popup/task_development/main_plan/platform/platform.tscn" id="3_5pged"]
|
||||
[ext_resource type="PackedScene" uid="uid://b8bb7bnc08siu" path="res://UI/popup/task_development/main_plan/gameplay/gameplay.tscn" id="4_ub8no"]
|
||||
[ext_resource type="PackedScene" uid="uid://ydvns1eq64e5" path="res://UI/popup/task_development/main_plan/theme/theme.tscn" id="5_l54p6"]
|
||||
[ext_resource type="PackedScene" uid="uid://cx5nui56begu8" path="res://UI/popup/task_development/main_plan/strategy/strategy.tscn" id="6_adtuk"]
|
||||
[ext_resource type="PackedScene" uid="uid://chl131ysu15rd" path="res://UI/popup/task_development/product_focus/product_focus.tscn" id="7_l1sf4"]
|
||||
[ext_resource type="PackedScene" uid="uid://dtywh0m5odikx" path="res://UI/popup/dialogue.tscn" id="8_6il88"]
|
||||
[ext_resource type="PackedScene" uid="uid://b5nxlnb6xr2oc" path="res://UI/popup/task_development/npc_select_1/npc_select_1.tscn" id="9_qpnja"]
|
||||
|
||||
[node name="task_development_start" type="Control" groups=["task_development"]]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
script = ExtResource("1_6fk5m")
|
||||
initial_page_path = NodePath("main_plan")
|
||||
gamestate_data_key = "task_info"
|
||||
|
||||
[node name="main_plan" parent="." instance=ExtResource("2_qpnja")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
next_ui_node_path = NodePath("../product_focus")
|
||||
|
||||
[node name="platform" parent="main_plan" instance=ExtResource("3_5pged")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -20.0
|
||||
offset_top = -20.0
|
||||
offset_right = 20.0
|
||||
offset_bottom = 20.0
|
||||
next_ui_node_path = NodePath("..")
|
||||
parent_page_node_path = NodePath("..")
|
||||
|
||||
[node name="gameplay" parent="main_plan" instance=ExtResource("4_ub8no")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
next_ui_node_path = NodePath("..")
|
||||
parent_page_node_path = NodePath("..")
|
||||
|
||||
[node name="theme" parent="main_plan" instance=ExtResource("5_l54p6")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
next_ui_node_path = NodePath("..")
|
||||
parent_page_node_path = NodePath("..")
|
||||
|
||||
[node name="strategy" parent="main_plan" instance=ExtResource("6_adtuk")]
|
||||
layout_mode = 1
|
||||
next_ui_node_path = NodePath("..")
|
||||
parent_page_node_path = NodePath("..")
|
||||
|
||||
[node name="product_focus" parent="." instance=ExtResource("7_l1sf4")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -20.0
|
||||
offset_top = -20.0
|
||||
offset_right = 20.0
|
||||
offset_bottom = 20.0
|
||||
next_ui_node_path = NodePath("../dialogue")
|
||||
back_ui_node_path = NodePath("../main_plan")
|
||||
|
||||
[node name="dialogue" parent="." instance=ExtResource("8_6il88")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
dialogues = ["谁来写立项书呢?"]
|
||||
next_ui_node_path = NodePath("../npc_select_1")
|
||||
back_ui_node_path = NodePath("../npc_select_1")
|
||||
|
||||
[node name="npc_select_1" parent="." instance=ExtResource("9_qpnja")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
back_ui_node_path = NodePath("../main_plan")
|
||||
390
UI/popup/task_development_bak/gameplay/gameplay.gd
Normal file
390
UI/popup/task_development_bak/gameplay/gameplay.gd
Normal file
@ -0,0 +1,390 @@
|
||||
# gameplay.gd (更新版)
|
||||
extends NinePatchRect
|
||||
|
||||
# UI Node References
|
||||
@onready var list_container = $Option/Info
|
||||
@onready var previous_button = $Title/previous/Button
|
||||
@onready var next_button = $Title/next/Button
|
||||
@onready var title_label = $Title/Title
|
||||
|
||||
# Configuration
|
||||
var items_per_page: int = 7 # 每页显示的选项数量
|
||||
|
||||
# Data Storage
|
||||
var gameplay_list_nodes: Array[VBoxContainer] = [] # 存储 List_1, List_2 等节点
|
||||
var option_nodes_per_list: Array = [] # 存储每个 List 对应的 option_X 按钮数组
|
||||
var all_enabled_gameplays: Array = [] # 存储筛选后的玩法数据 { "name": String, "data": Dictionary }
|
||||
|
||||
# State
|
||||
var total_pages: int = 0
|
||||
var current_page_index: int = 0
|
||||
var selected_gameplay_key: String = "" # 当前逻辑上选中的项的 Key (用于确认)
|
||||
var currently_selected_button: Button = null # 当前高亮/聚焦的按钮节点引用
|
||||
var initial_key_to_highlight: String = "" # 弹窗打开时需要高亮的 Key (由父节点设置)
|
||||
|
||||
func _ready():
|
||||
# 1. 获取 List 节点 (与原版一致)
|
||||
for i in range(1, 4): # 检查 List_1, List_2, List_3
|
||||
var list_node = list_container.get_node_or_null("List_" + str(i))
|
||||
if list_node:
|
||||
gameplay_list_nodes.append(list_node)
|
||||
else:
|
||||
break
|
||||
|
||||
if gameplay_list_nodes.is_empty():
|
||||
printerr("错误:在 gameplay.tscn 中未找到 List 节点!无法显示选项。")
|
||||
set_process(false)
|
||||
return
|
||||
|
||||
# 2. 获取每个 List 内的 Option 节点 (与原版一致)
|
||||
for list_node in gameplay_list_nodes:
|
||||
var current_list_options: Array = []
|
||||
for i in range(1, items_per_page + 1):
|
||||
var option_node = list_node.get_node_or_null("option_" + str(i))
|
||||
if option_node and option_node is Button:
|
||||
current_list_options.append(option_node)
|
||||
else:
|
||||
push_warning("警告:在 %s 中未能找到 option_%d 按钮" % [list_node.name, i])
|
||||
option_nodes_per_list.append(current_list_options)
|
||||
|
||||
# 3. 连接按钮信号 (与原版一致)
|
||||
if previous_button:
|
||||
if not previous_button.pressed.is_connected(_on_previous_pressed):
|
||||
previous_button.pressed.connect(_on_previous_pressed)
|
||||
else: printerr("错误:在 gameplay.tscn 中未找到 Previous 按钮")
|
||||
|
||||
if next_button:
|
||||
if not next_button.pressed.is_connected(_on_next_pressed):
|
||||
next_button.pressed.connect(_on_next_pressed)
|
||||
else: printerr("错误:在 gameplay.tscn 中未找到 Next 按钮")
|
||||
|
||||
# 4. 连接 visibility_changed 信号 (与原版一致)
|
||||
if not is_connected("visibility_changed", _on_visibility_changed):
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
|
||||
# 5. 移除 _ready 中的初始数据加载和显示更新
|
||||
# 这些逻辑现在完全由 _on_visibility_changed -> reset_display 处理
|
||||
|
||||
# --- Visibility Change Handler ---
|
||||
func _on_visibility_changed():
|
||||
if is_visible_in_tree():
|
||||
print("Gameplay: 弹窗变为可见,调用 reset_display()")
|
||||
reset_display() # 当变为可见时调用 reset
|
||||
# else: # 可选:隐藏时的清理逻辑
|
||||
# print("Gameplay: 弹窗变为隐藏。")
|
||||
|
||||
# --- 新增:用于父节点设置初始选中项 ---
|
||||
func set_initial_selection(key: String):
|
||||
"""
|
||||
由父节点 (task_development) 在显示此弹窗前调用,
|
||||
传递当前在 task_info 中选中的玩法 Key。
|
||||
"""
|
||||
initial_key_to_highlight = key
|
||||
print("Gameplay: 父节点设置初始高亮 Key 为: '%s'" % initial_key_to_highlight)
|
||||
|
||||
|
||||
# --- Data Processing and Display Logic ---
|
||||
|
||||
func _process_gameplay_data(all_gameplays_data: Dictionary):
|
||||
"""【修改】根据从 GameState 获取的玩法数据,筛选出启用的玩法,并计算总页数。"""
|
||||
all_enabled_gameplays.clear()
|
||||
if all_gameplays_data.is_empty():
|
||||
push_warning("警告:接收到的玩法数据为空。")
|
||||
total_pages = 0
|
||||
return
|
||||
|
||||
# 遍历从 GameState 获取的玩法字典
|
||||
for gameplay_name in all_gameplays_data:
|
||||
var gameplay_info = all_gameplays_data[gameplay_name]
|
||||
# 检查是否为字典且 "enabled" 字段为 true
|
||||
if typeof(gameplay_info) == TYPE_DICTIONARY and gameplay_info.get("enabled", false) == true:
|
||||
all_enabled_gameplays.append({"name": gameplay_name, "data": gameplay_info})
|
||||
# else: # Debugging: 可以取消注释来看哪些被过滤了
|
||||
# print("Gameplay: 过滤掉未启用或格式错误的玩法: ", gameplay_name)
|
||||
|
||||
# 根据筛选结果计算总页数
|
||||
if items_per_page > 0:
|
||||
total_pages = ceil(float(all_enabled_gameplays.size()) / items_per_page)
|
||||
else:
|
||||
total_pages = 0
|
||||
printerr("错误:items_per_page 为零,无法计算页数。")
|
||||
|
||||
print("Gameplay: 处理完成,找到 %d 个启用的玩法,共 %d 页。" % [all_enabled_gameplays.size(), total_pages])
|
||||
|
||||
|
||||
func reset_display():
|
||||
"""【修改】重置状态,从 GameState 重新加载数据,并准备更新显示。"""
|
||||
print("Gameplay: 重置显示状态 (reset_display)。")
|
||||
# 1. 重置本地状态变量
|
||||
currently_selected_button = null
|
||||
selected_gameplay_key = ""
|
||||
# initial_key_to_highlight 由 set_initial_selection 设置,这里不清空
|
||||
|
||||
# 2. 【修改】从 GameState 重新加载并处理数据
|
||||
if not GameState:
|
||||
printerr("错误:GameState 在 reset_display 期间不可用。")
|
||||
total_pages = 0
|
||||
all_enabled_gameplays.clear()
|
||||
_update_display() # 即使没有数据也要更新显示(显示空状态)
|
||||
return
|
||||
|
||||
var task_dev_data = GameState.get_value("task_development", {})
|
||||
if task_dev_data.is_empty():
|
||||
printerr("错误:从 GameState 获取 'task_development' 数据失败。")
|
||||
total_pages = 0
|
||||
all_enabled_gameplays.clear()
|
||||
else:
|
||||
var all_gameplays_data = task_dev_data.get("gameplays", {})
|
||||
_process_gameplay_data(all_gameplays_data) # 重新处理数据,计算 total_pages
|
||||
|
||||
# 3. 【修改】根据 initial_key_to_highlight 确定初始页面
|
||||
current_page_index = 0 # 默认为第一页
|
||||
var found_initial_key = false
|
||||
if total_pages > 0 and not initial_key_to_highlight.is_empty():
|
||||
# 查找 initial_key_to_highlight 所在的索引和页面
|
||||
for i in range(all_enabled_gameplays.size()):
|
||||
if all_enabled_gameplays[i].name == initial_key_to_highlight:
|
||||
current_page_index = int(floor(float(i) / items_per_page))
|
||||
found_initial_key = true
|
||||
print("Gameplay: 找到需要初始高亮的 Key '%s' 在索引 %d, 目标页面 %d" % [initial_key_to_highlight, i, current_page_index])
|
||||
break # 找到了,停止循环
|
||||
if not found_initial_key:
|
||||
print("Gameplay: 需要初始高亮的 Key '%s' 未在启用的玩法中找到,将显示第一页。" % initial_key_to_highlight)
|
||||
# 保持 current_page_index 为 0
|
||||
initial_key_to_highlight = "" # 清空,避免后续 _update_display 尝试高亮不存在的项
|
||||
|
||||
# 确保页面索引有效
|
||||
if total_pages == 0:
|
||||
current_page_index = 0
|
||||
elif current_page_index >= total_pages:
|
||||
current_page_index = total_pages - 1
|
||||
elif current_page_index < 0:
|
||||
current_page_index = 0
|
||||
|
||||
# 4. 触发显示更新
|
||||
_update_display()
|
||||
|
||||
func _update_display():
|
||||
"""【更新版】更新列表的可见性并填充当前页面的内容。
|
||||
现在将“经验”和“成本”显示为整数。
|
||||
"""
|
||||
# --- 处理无数据情况 ---
|
||||
if gameplay_list_nodes.is_empty():
|
||||
print("Gameplay: 无可用的 List 节点。")
|
||||
if title_label: title_label.text = "玩法选择"
|
||||
return
|
||||
|
||||
if total_pages == 0:
|
||||
for list_node in gameplay_list_nodes: list_node.visible = false
|
||||
print("Gameplay: 没有启用的玩法选项可供显示。")
|
||||
if title_label: title_label.text = "玩法选择 (无可用)"
|
||||
# 确保按钮也禁用或隐藏
|
||||
if previous_button: previous_button.disabled = true
|
||||
if next_button: next_button.disabled = true
|
||||
return
|
||||
else:
|
||||
# 确保按钮状态正确 (启用/禁用基于页数)
|
||||
if previous_button: previous_button.disabled = (total_pages <= 1)
|
||||
if next_button: next_button.disabled = (total_pages <= 1)
|
||||
|
||||
|
||||
# --- 更新页面索引 (循环) ---
|
||||
# 注意: reset_display 设置了初始页, 取模主要用于翻页
|
||||
if total_pages > 0 : # 避免除以零
|
||||
current_page_index = current_page_index % total_pages
|
||||
if current_page_index < 0:
|
||||
current_page_index += total_pages
|
||||
else:
|
||||
current_page_index = 0
|
||||
|
||||
|
||||
# --- 更新标题 ---
|
||||
if title_label:
|
||||
var display_page_number = current_page_index + 1 # 显示给用户的页码从1开始
|
||||
title_label.text = "玩法选择 %d/%d" % [display_page_number, total_pages]
|
||||
|
||||
# --- 更新 List 可见性 ---
|
||||
# 确保只有一个 List 节点是可见的,即当前页对应的 List
|
||||
for i in range(gameplay_list_nodes.size()):
|
||||
gameplay_list_nodes[i].visible = (i == current_page_index)
|
||||
|
||||
# --- 填充可见列表并查找要高亮的按钮 ---
|
||||
var button_to_highlight: Button = null
|
||||
var first_enabled_button_on_page: Button = null # 如果 initial_key 不在本页,则使用此按钮
|
||||
|
||||
# 检查当前页索引是否在有效范围内
|
||||
if current_page_index < option_nodes_per_list.size():
|
||||
var current_options = option_nodes_per_list[current_page_index] # 获取当前页的所有按钮节点
|
||||
var start_index = current_page_index * items_per_page # 计算当前页数据在 all_enabled_gameplays 中的起始索引
|
||||
|
||||
# 遍历当前页的按钮槽位
|
||||
for i in range(current_options.size()):
|
||||
var option_button = current_options[i] # 获取具体的按钮节点
|
||||
var item_index = start_index + i # 计算此按钮对应的数据索引
|
||||
|
||||
# --- 断开旧信号 ---
|
||||
# 确保在连接新信号前断开旧的,防止重复连接
|
||||
if option_button.pressed.is_connected(_on_option_selected):
|
||||
option_button.pressed.disconnect(_on_option_selected)
|
||||
|
||||
# 检查数据索引是否在有效范围内
|
||||
if item_index < all_enabled_gameplays.size():
|
||||
# 获取对应的玩法数据
|
||||
var gameplay_entry = all_enabled_gameplays[item_index]
|
||||
var gameplay_name = gameplay_entry.name
|
||||
var gameplay_data = gameplay_entry.data # 这是包含 Cost, Experience, Popularity 等信息的字典
|
||||
|
||||
# 获取按钮内部用于显示信息的 Row 节点
|
||||
var row = option_button.get_node_or_null("Row")
|
||||
if row:
|
||||
# 填充标签文本
|
||||
var title_label_in_row = row.get_node_or_null("Title")
|
||||
var exp_label = row.get_node_or_null("Experience")
|
||||
var pop_label = row.get_node_or_null("Popularity")
|
||||
# 查找成本标签,兼容 "Cost" 和 "cost" 两种可能的节点名
|
||||
var cost_label = row.get_node_or_null("Cost") if row.has_node("Cost") else row.get_node_or_null("cost")
|
||||
|
||||
# 设置标题
|
||||
if title_label_in_row: title_label_in_row.text = gameplay_name
|
||||
|
||||
# 【修改】设置经验值,显示为整数
|
||||
if exp_label:
|
||||
var experience_value = gameplay_data.get("Experience", 0.0) # 获取原始值
|
||||
exp_label.text = str(int(experience_value)) # 转为整数再转为字符串
|
||||
|
||||
# 【保持】设置流行度,保持原始字符串显示
|
||||
if pop_label:
|
||||
var popularity_value = gameplay_data.get("Popularity", "未知") # 获取原始值
|
||||
pop_label.text = str(popularity_value) # 直接转为字符串
|
||||
|
||||
# 【修改】设置成本,显示为整数
|
||||
if cost_label:
|
||||
var cost_value = gameplay_data.get("Cost", 0.0) # 获取原始值
|
||||
cost_label.text = str(int(cost_value)) # 转为整数再转为字符串
|
||||
|
||||
# 设置按钮可见、可用,并存储玩法名称到元数据
|
||||
option_button.visible = true
|
||||
option_button.disabled = false
|
||||
option_button.set_meta("gameplay_name", gameplay_name)
|
||||
|
||||
# --- 连接新信号 (使用 bind) ---
|
||||
# 传递玩法名称和按钮节点本身给处理函数
|
||||
option_button.pressed.connect(_on_option_selected.bind(gameplay_name, option_button))
|
||||
|
||||
# 记录本页第一个可用的按钮,作为备选高亮目标
|
||||
if first_enabled_button_on_page == null:
|
||||
first_enabled_button_on_page = option_button
|
||||
|
||||
# 检查此按钮是否是需要初始高亮的按钮
|
||||
if not initial_key_to_highlight.is_empty() and gameplay_name == initial_key_to_highlight:
|
||||
button_to_highlight = option_button
|
||||
# print("Gameplay: 找到需要初始高亮的按钮: ", button_to_highlight.name) # Debug
|
||||
|
||||
else: # 未找到 Row 节点
|
||||
push_warning("警告:在按钮 %s 中未找到 Row 节点" % option_button.get_path())
|
||||
option_button.visible = false # 隐藏按钮以避免显示不完整
|
||||
option_button.disabled = true
|
||||
else: # 此槽位没有对应的启用玩法数据 (例如最后一页不满)
|
||||
option_button.visible = false # 隐藏按钮
|
||||
option_button.disabled = true
|
||||
else:
|
||||
# 这种情况理论上不应发生,除非页面计算或节点结构有问题
|
||||
printerr("错误:当前页面索引 %d 超出 option_nodes_per_list 的范围 (大小 %d)" % [current_page_index, option_nodes_per_list.size()])
|
||||
|
||||
# --- 设置初始高亮和焦点 ---
|
||||
# 优先高亮 initial_key_to_highlight 对应的按钮
|
||||
if button_to_highlight:
|
||||
# print("Gameplay: 尝试高亮指定按钮: ", button_to_highlight.name) # Debug
|
||||
_set_initial_highlight(button_to_highlight)
|
||||
# 如果没有指定按钮或指定按钮不在当前页,则高亮当前页的第一个可用按钮
|
||||
elif first_enabled_button_on_page:
|
||||
print("Gameplay: 初始 Key '%s' 不在本页或为空。高亮本页第一个按钮: %s" % [initial_key_to_highlight, first_enabled_button_on_page.name])
|
||||
_set_initial_highlight(first_enabled_button_on_page)
|
||||
# 如果当前页没有任何可用按钮
|
||||
else:
|
||||
print("Gameplay: 本页没有可供高亮的按钮。")
|
||||
currently_selected_button = null # 确保没有按钮被标记为选中
|
||||
selected_gameplay_key = "" # 确保没有 Key 被标记为选中
|
||||
|
||||
# (Helper) 设置初始高亮和焦点 (与原版类似,增加日志)
|
||||
func _set_initial_highlight(button_to_highlight: Button):
|
||||
if not is_instance_valid(button_to_highlight):
|
||||
printerr("错误:传递给 _set_initial_highlight 的按钮无效。")
|
||||
currently_selected_button = null
|
||||
selected_gameplay_key = ""
|
||||
return
|
||||
|
||||
# print("Gameplay: 设置高亮按钮: ", button_to_highlight.name) # Debug
|
||||
currently_selected_button = button_to_highlight
|
||||
selected_gameplay_key = button_to_highlight.get_meta("gameplay_name", "") # 同时设置 Key
|
||||
# print("Gameplay: currently_selected_button 设置为: ", currently_selected_button.name) # Debug
|
||||
# print("Gameplay: selected_gameplay_key 设置为: '", selected_gameplay_key, "'") # Debug
|
||||
|
||||
# 延迟调用 grab_focus 确保按钮已准备好接收焦点
|
||||
if currently_selected_button and currently_selected_button.is_inside_tree():
|
||||
# print("Gameplay: 尝试为按钮 call_deferred('grab_focus'): ", currently_selected_button.name) # Debug
|
||||
currently_selected_button.call_deferred("grab_focus")
|
||||
else:
|
||||
print("Gameplay: 按钮无效或不在场景树中,无法获取焦点。")
|
||||
|
||||
|
||||
# --- Signal Handlers ---
|
||||
|
||||
func _on_previous_pressed():
|
||||
if total_pages > 1: # 仅当有多页时才翻页
|
||||
current_page_index -= 1
|
||||
# 循环由 _update_display 处理
|
||||
_update_display()
|
||||
|
||||
func _on_next_pressed():
|
||||
if total_pages > 1: # 仅当有多页时才翻页
|
||||
current_page_index += 1
|
||||
# 循环由 _update_display 处理
|
||||
_update_display()
|
||||
|
||||
# 【修改】处理选项按钮按下事件 (与原版类似,增加日志)
|
||||
func _on_option_selected(gameplay_name: String, button_node: Button):
|
||||
"""当选项按钮被按下时调用。"""
|
||||
if not is_instance_valid(button_node):
|
||||
printerr("错误:在 _on_option_selected 中收到无效按钮节点,Key: " + gameplay_name)
|
||||
return
|
||||
|
||||
if button_node == currently_selected_button:
|
||||
# --- 双击 (或点击已选中的按钮) ---
|
||||
print("Gameplay: 检测到双击或确认点击: ", gameplay_name)
|
||||
_confirm_and_close(gameplay_name) # 确认此选择
|
||||
else:
|
||||
# --- 首次点击或点击不同按钮 ---
|
||||
print("Gameplay: 选中 (高亮) 玩法: ", gameplay_name)
|
||||
currently_selected_button = button_node
|
||||
selected_gameplay_key = gameplay_name # 更新 Key,以便后续可能的确认
|
||||
|
||||
# 更新视觉焦点
|
||||
button_node.grab_focus()
|
||||
|
||||
# 【修改】确认选择并关闭弹窗的逻辑
|
||||
func _confirm_and_close(key_to_confirm: String):
|
||||
"""更新父节点并关闭此弹窗。"""
|
||||
if key_to_confirm.is_empty():
|
||||
printerr("错误:尝试确认一个空的玩法 Key。")
|
||||
return
|
||||
|
||||
print("Gameplay: 确认选择: ", key_to_confirm)
|
||||
|
||||
# --- 更新父节点 (Task Development Popup) ---
|
||||
var parent_node = get_parent()
|
||||
if parent_node and parent_node.has_method("update_task_options"):
|
||||
# 通知父节点更新其内部的 task_info
|
||||
parent_node.update_task_options({"玩法": key_to_confirm})
|
||||
print("Gameplay: 已更新父节点的 task_options: 玩法 = ", key_to_confirm)
|
||||
else:
|
||||
printerr("错误:Gameplay: 父节点未找到或缺少 'update_task_options' 方法。")
|
||||
# 考虑是否应该在此处停止或仅记录错误后继续
|
||||
|
||||
# --- 关闭此弹窗 ---
|
||||
if parent_node and parent_node.has_method("_close_child_popup_and_return"):
|
||||
# 调用父节点的标准方法来关闭子弹窗并返回
|
||||
parent_node._close_child_popup_and_return(self)
|
||||
else:
|
||||
printerr("错误:Gameplay: 父节点未找到或缺少 '_close_child_popup_and_return' 方法。")
|
||||
self.hide() # 作为备选方案,直接隐藏自身
|
||||
1
UI/popup/task_development_bak/gameplay/gameplay.gd.uid
Normal file
1
UI/popup/task_development_bak/gameplay/gameplay.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://cbiwirr68lspl
|
||||
1394
UI/popup/task_development_bak/gameplay/gameplay.tscn
Normal file
1394
UI/popup/task_development_bak/gameplay/gameplay.tscn
Normal file
File diff suppressed because it is too large
Load Diff
BIN
UI/popup/task_development_bak/key_output/key_output.png
Normal file
BIN
UI/popup/task_development_bak/key_output/key_output.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://ctled08bky4mu"
|
||||
path="res://.godot/imported/key_output.png-a31ee9fabd17a37980a8303ee0aa6cf0.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://UI/popup/task_development_bak/key_output/key_output.png"
|
||||
dest_files=["res://.godot/imported/key_output.png-a31ee9fabd17a37980a8303ee0aa6cf0.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
1
UI/popup/task_development_bak/key_output/proposal.gd.uid
Normal file
1
UI/popup/task_development_bak/key_output/proposal.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://ciqayqceaadw4
|
||||
@ -1,7 +1,7 @@
|
||||
[gd_scene load_steps=30 format=3 uid="uid://be000l53jxash"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://pucudatqrcrq" path="res://UI/popup/popup_bg_1.png" id="1_0ruly"]
|
||||
[ext_resource type="Script" uid="uid://ciqayqceaadw4" path="res://UI/popup/task_development/key_output/proposal.gd" id="2_uudne"]
|
||||
[ext_resource type="Script" uid="uid://ciqayqceaadw4" path="res://UI/popup/task_development_bak/key_output/proposal.gd" id="2_uudne"]
|
||||
[ext_resource type="Texture2D" uid="uid://dgcugleiv7sfw" path="res://UI/popup/task_development/arrow.png" id="3_uudne"]
|
||||
[ext_resource type="FontFile" uid="uid://egugs822n8gr" path="res://UI/font/AlimamaFangYuanTiVF-Thin.ttf" id="4_csatq"]
|
||||
[ext_resource type="LabelSettings" uid="uid://qcn0aduvrgvw" path="res://UI/tres/task_development_platform_label_settings.tres" id="5_l6j0s"]
|
||||
278
UI/popup/task_development_bak/platform/platform.gd
Normal file
278
UI/popup/task_development_bak/platform/platform.gd
Normal file
@ -0,0 +1,278 @@
|
||||
extends NinePatchRect
|
||||
|
||||
# References to UI elements
|
||||
@onready var title_label = $Title/Title
|
||||
@onready var name_label = $Option/Name
|
||||
@onready var icon_rect = $Option/Info/Icon
|
||||
@onready var info1_label = $Option/Info/Info_List_1/Info_1/info # 制造商 (Maker)
|
||||
@onready var info2_label = $Option/Info/Info_List_1/Info_2/info # 发售 (Sales)
|
||||
@onready var info3_label = $Option/Info/Info_List_1/Info_3/info # 市场占比 (Market_share)
|
||||
@onready var info4_label = $Option/Info/Info_List_2/info_4/info # 开发费用 (Cost)
|
||||
# @onready var info5_label = $Option/Info/Info_List_2/info_5/info # 开发次数 - 暂不处理,数据源未知
|
||||
|
||||
@onready var prev_button = $Title/previous/Button
|
||||
@onready var next_button = $Title/next/Button
|
||||
@onready var confirm_button = $Confirm
|
||||
|
||||
# Internal state
|
||||
var enabled_platform_keys: Array[String] = [] # Store keys (names) of enabled platforms
|
||||
var current_platform_index: int = -1 # Index in the enabled_platform_keys array
|
||||
|
||||
const PLATFORM_ICON_PATH = "res://UI/popup/task_development/platform/"
|
||||
# --- 新增:用于存储从 GameState 获取的平台数据 ---
|
||||
var _platforms_data: Dictionary = {}
|
||||
# --- 新增:用于存储上次确认的平台 Key 的 GameState 键名 ---
|
||||
const SELECTED_PLATFORM_KEY_NAME = "selected_platform_key" # 假设用这个顶层键存储
|
||||
|
||||
func _ready():
|
||||
add_to_group(str(name)) # 保持不变
|
||||
|
||||
# Connect button signals (保持不变)
|
||||
if prev_button:
|
||||
if not prev_button.pressed.is_connected(_on_previous_pressed):
|
||||
prev_button.pressed.connect(_on_previous_pressed)
|
||||
if next_button:
|
||||
if not next_button.pressed.is_connected(_on_next_pressed):
|
||||
next_button.pressed.connect(_on_next_pressed)
|
||||
if confirm_button:
|
||||
if not confirm_button.pressed.is_connected(_on_confirm_pressed):
|
||||
confirm_button.pressed.connect(_on_confirm_pressed)
|
||||
|
||||
# Connect visibility changed signal (保持不变)
|
||||
if not is_connected("visibility_changed", _on_visibility_changed):
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
|
||||
# Initial call if already visible on ready (保持不变)
|
||||
if is_visible_in_tree():
|
||||
reset_display()
|
||||
|
||||
|
||||
# Visibility Change Handler (保持不变)
|
||||
func _on_visibility_changed():
|
||||
if is_visible_in_tree():
|
||||
reset_display()
|
||||
|
||||
|
||||
# --- 修改:reset_display ---
|
||||
# 重置显示状态,在窗口可见时调用
|
||||
func reset_display():
|
||||
print("Platform: Resetting display state.")
|
||||
# 1. 加载并过滤平台数据
|
||||
_load_and_filter_platforms() # 这会更新 _platforms_data 和 enabled_platform_keys
|
||||
|
||||
# 2. 检查是否有可用的平台
|
||||
if enabled_platform_keys.is_empty():
|
||||
print("Platform: No enabled platforms found during reset.")
|
||||
current_platform_index = -1
|
||||
_display_current_platform() # 显示 "无可用平台" 状态
|
||||
return
|
||||
|
||||
# 3. 获取上次确认的平台 Key
|
||||
var last_confirmed_key = ""
|
||||
if GameState:
|
||||
# --- 修改:使用 get_value 获取上次选择 ---
|
||||
last_confirmed_key = GameState.get_value(SELECTED_PLATFORM_KEY_NAME, "")
|
||||
else:
|
||||
push_error("GameState not available during reset_display.")
|
||||
# 默认使用第一个可用平台
|
||||
current_platform_index = 0
|
||||
_display_current_platform()
|
||||
return
|
||||
|
||||
# 4. 查找上次确认的 Key 在当前可用列表中的索引
|
||||
if not last_confirmed_key.is_empty():
|
||||
var found_index = enabled_platform_keys.find(last_confirmed_key)
|
||||
if found_index != -1:
|
||||
# 5. 如果找到,更新当前索引
|
||||
current_platform_index = found_index
|
||||
print("Platform: Found last confirmed key '%s' at index %d." % [last_confirmed_key, found_index])
|
||||
else:
|
||||
# 6. 如果找不到(可能平台不再可用),默认使用第一个可用平台
|
||||
print("Platform: Last confirmed key '%s' not found in enabled list. Defaulting to index 0." % last_confirmed_key)
|
||||
current_platform_index = 0
|
||||
else:
|
||||
# 7. 如果 GameState 中没有记录,默认使用第一个可用平台
|
||||
print("Platform: No last confirmed key found in GameState. Defaulting to index 0.")
|
||||
current_platform_index = 0
|
||||
|
||||
# 8. 更新显示
|
||||
_display_current_platform()
|
||||
|
||||
|
||||
# --- 修改:_load_and_filter_platforms ---
|
||||
# 从 GameState 获取平台数据并筛选出启用的平台
|
||||
func _load_and_filter_platforms():
|
||||
enabled_platform_keys.clear()
|
||||
_platforms_data = {} # 清空旧数据
|
||||
|
||||
if not GameState:
|
||||
push_error("GameState not available in _load_and_filter_platforms.")
|
||||
return
|
||||
|
||||
# --- 修改:从 GameState 获取 task_development 数据 ---
|
||||
var task_dev_data = GameState.get_value("task_development", {})
|
||||
if task_dev_data.is_empty():
|
||||
printerr("Platform: Failed to get 'task_development' data from GameState.")
|
||||
return
|
||||
|
||||
# --- 修改:获取 platforms 字典 ---
|
||||
var all_platforms = task_dev_data.get("platforms", {})
|
||||
if all_platforms.is_empty():
|
||||
print("Platform: 'platforms' data in GameState is empty.")
|
||||
return
|
||||
|
||||
# --- 修改:将获取到的平台数据存储到内部变量 ---
|
||||
_platforms_data = all_platforms
|
||||
|
||||
# 遍历平台数据,筛选出启用的平台 Key
|
||||
for platform_key in _platforms_data:
|
||||
var platform_info = _platforms_data[platform_key]
|
||||
# 确保 platform_info 是字典并且 'enabled' 键存在且为 true
|
||||
if typeof(platform_info) == TYPE_DICTIONARY and platform_info.get("enabled", false) == true:
|
||||
enabled_platform_keys.append(platform_key)
|
||||
|
||||
# 可选:按键名排序,保持一致性
|
||||
#if not enabled_platform_keys.is_empty():
|
||||
#enabled_platform_keys.sort() # 简单字符串排序
|
||||
## current_platform_index 会在 reset_display 中设置
|
||||
#else:
|
||||
#print("Platform: No enabled platforms found.")
|
||||
#current_platform_index = -1 # 明确设置无可用平台
|
||||
|
||||
# 根据 current_platform_index 更新 UI 显示
|
||||
func _display_current_platform():
|
||||
# 处理无可用平台或索引无效的情况
|
||||
if current_platform_index < 0 or current_platform_index >= enabled_platform_keys.size():
|
||||
title_label.text = "游戏平台"
|
||||
name_label.text = "无可用平台"
|
||||
if icon_rect: icon_rect.texture = null
|
||||
if info1_label: info1_label.text = "-" # Maker
|
||||
if info2_label: info2_label.text = "-" # Sales
|
||||
if info3_label: info3_label.text = "-" # Market_share
|
||||
if info4_label: info4_label.text = "-" # Cost
|
||||
if prev_button: prev_button.disabled = true
|
||||
if next_button: next_button.disabled = true
|
||||
if confirm_button: confirm_button.disabled = true
|
||||
return
|
||||
|
||||
# --- 如果有有效平台 ---
|
||||
if confirm_button: confirm_button.disabled = false # 启用确认按钮
|
||||
|
||||
# 更新标题
|
||||
var display_index = current_platform_index + 1
|
||||
var total_count = enabled_platform_keys.size()
|
||||
title_label.text = "游戏平台 %d/%d" % [display_index, total_count]
|
||||
|
||||
# 获取当前平台的 Key 和数据
|
||||
var platform_key = enabled_platform_keys[current_platform_index]
|
||||
|
||||
# --- 从内部缓存 _platforms_data 获取平台信息 ---
|
||||
if not _platforms_data.has(platform_key):
|
||||
push_error("Current platform key '%s' not found in cached _platforms_data!" % platform_key)
|
||||
name_label.text = "错误:数据丢失"
|
||||
# ... 清空其他信息 ...
|
||||
return
|
||||
|
||||
var platform_info = _platforms_data[platform_key]
|
||||
|
||||
# 更新平台名称
|
||||
name_label.text = platform_key
|
||||
|
||||
# --- 修改:从 platform_info 读取所有需要的信息,数值转为整数显示 ---
|
||||
# 使用 .get(key, default) 确保安全访问
|
||||
|
||||
# 制造商 (Maker) - 通常是字符串,保持不变
|
||||
info1_label.text = platform_info.get("Maker", "-")
|
||||
|
||||
# 发售 (Sales) - 转换为整数显示
|
||||
var sales_value = platform_info.get("Sales", null)
|
||||
if typeof(sales_value) == TYPE_INT or typeof(sales_value) == TYPE_FLOAT:
|
||||
info2_label.text = str(int(sales_value)) # 转换为整数再转字符串
|
||||
else:
|
||||
info2_label.text = "-" # 如果不是数字或不存在,显示 "-"
|
||||
|
||||
# 市场占比 (Market_share) - 转换为整数显示
|
||||
var market_share_value = platform_info.get("Market_share", null)
|
||||
if typeof(market_share_value) == TYPE_INT or typeof(market_share_value) == TYPE_FLOAT:
|
||||
info3_label.text = str(int(market_share_value)) # 转换为整数再转字符串
|
||||
else:
|
||||
info3_label.text = "-"
|
||||
|
||||
# 开发费用 (Cost) - 转换为整数显示
|
||||
var cost_value = platform_info.get("Cost", null)
|
||||
if typeof(cost_value) == TYPE_INT or typeof(cost_value) == TYPE_FLOAT:
|
||||
info4_label.text = str(int(cost_value)) # 转换为整数再转字符串
|
||||
else:
|
||||
info4_label.text = "-"
|
||||
|
||||
# info5 (开发次数) 暂不处理
|
||||
|
||||
# 更新图标 (逻辑不变)
|
||||
var icon_name = platform_info.get("Icon", "")
|
||||
if not icon_name.is_empty():
|
||||
var icon_path = PLATFORM_ICON_PATH + icon_name + ".png"
|
||||
if ResourceLoader.exists(icon_path):
|
||||
icon_rect.texture = ResourceLoader.load(icon_path)
|
||||
else:
|
||||
push_error("Failed to load platform icon: " + icon_path)
|
||||
icon_rect.texture = null
|
||||
else:
|
||||
print("Platform icon name is empty for key: ", platform_key)
|
||||
icon_rect.texture = null
|
||||
|
||||
# 更新导航按钮状态 (逻辑不变)
|
||||
var can_navigate = enabled_platform_keys.size() > 1
|
||||
if prev_button: prev_button.disabled = not can_navigate
|
||||
if next_button: next_button.disabled = not can_navigate
|
||||
|
||||
|
||||
# --- _on_previous_pressed (逻辑不变) ---
|
||||
func _on_previous_pressed():
|
||||
if enabled_platform_keys.size() > 1:
|
||||
current_platform_index -= 1
|
||||
if current_platform_index < 0:
|
||||
current_platform_index = enabled_platform_keys.size() - 1
|
||||
_display_current_platform()
|
||||
|
||||
|
||||
# --- _on_next_pressed (逻辑不变) ---
|
||||
func _on_next_pressed():
|
||||
if enabled_platform_keys.size() > 1:
|
||||
current_platform_index += 1
|
||||
if current_platform_index >= enabled_platform_keys.size():
|
||||
current_platform_index = 0
|
||||
_display_current_platform()
|
||||
|
||||
|
||||
# --- 修改:_on_confirm_pressed ---
|
||||
# 处理确认选择
|
||||
func _on_confirm_pressed():
|
||||
if current_platform_index != -1 and current_platform_index < enabled_platform_keys.size():
|
||||
# 1. 获取选中的平台 Key
|
||||
var selected_platform_key = enabled_platform_keys[current_platform_index]
|
||||
|
||||
# 2. 获取父节点 (task_development)
|
||||
var parent_node = get_parent()
|
||||
|
||||
# 3. 调用父节点的 update_task_options 更新选项 (保持不变)
|
||||
if parent_node and parent_node.has_method("update_task_options"):
|
||||
parent_node.update_task_options({"平台": selected_platform_key})
|
||||
else:
|
||||
push_error("Platform: Parent node not found or missing 'update_task_options' method.")
|
||||
# 即使父节点更新失败,也尝试关闭窗口
|
||||
|
||||
# 4. 调用父节点的方法来处理关闭自身 (保持不变)
|
||||
if parent_node and parent_node.has_method("_close_child_popup_and_return"):
|
||||
parent_node._close_child_popup_and_return(self)
|
||||
else:
|
||||
push_error("Platform: Parent node not found or missing '_close_child_popup_and_return' method.")
|
||||
self.hide() # Fallback hide
|
||||
else:
|
||||
# 处理没有有效平台被选中的情况
|
||||
print("Platform: No valid platform selected to confirm.")
|
||||
# 仍然尝试关闭窗口
|
||||
var parent_node = get_parent()
|
||||
if parent_node and parent_node.has_method("_close_child_popup_and_return"):
|
||||
parent_node._close_child_popup_and_return(self)
|
||||
else:
|
||||
self.hide() # Fallback hide
|
||||
1
UI/popup/task_development_bak/platform/platform.gd.uid
Normal file
1
UI/popup/task_development_bak/platform/platform.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://ddadoyxwx3sbh
|
||||
488
UI/popup/task_development_bak/platform/platform.tscn
Normal file
488
UI/popup/task_development_bak/platform/platform.tscn
Normal file
@ -0,0 +1,488 @@
|
||||
[gd_scene load_steps=29 format=3 uid="uid://blv6i6w651pcs"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://pucudatqrcrq" path="res://UI/popup/popup_bg_1.png" id="1_kr1r5"]
|
||||
[ext_resource type="Texture2D" uid="uid://dgcugleiv7sfw" path="res://UI/popup/task_development/arrow.png" id="2_6a8uh"]
|
||||
[ext_resource type="Script" uid="uid://ddadoyxwx3sbh" path="res://UI/popup/task_development_bak/platform/platform.gd" id="2_bu5lv"]
|
||||
[ext_resource type="Texture2D" uid="uid://b2n1f22bd06tc" path="res://UI/popup/task_development/main_plan/platform/platform_1.png" id="3_bu5lv"]
|
||||
[ext_resource type="LabelSettings" uid="uid://qcn0aduvrgvw" path="res://UI/tres/task_development_platform_label_settings.tres" id="4_mue51"]
|
||||
[ext_resource type="Theme" uid="uid://bau80ps6kx783" path="res://UI/tres/Bottom_Info_button_theme.tres" id="5_wpgbx"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_6a8uh"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_bu5lv"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_mue51"]
|
||||
|
||||
[sub_resource type="Animation" id="Animation_bu5lv"]
|
||||
length = 0.001
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Title/previous:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [Vector2(9, 7)]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_6a8uh"]
|
||||
resource_name = "base"
|
||||
length = 0.6
|
||||
loop_mode = 1
|
||||
step = 0.2
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Title/previous:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.2, 0.4, 0.6),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [Vector2(16, 7), Vector2(12, 7), Vector2(9, 7), Vector2(16, 7)]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_mue51"]
|
||||
_data = {
|
||||
&"RESET": SubResource("Animation_bu5lv"),
|
||||
&"base": SubResource("Animation_6a8uh")
|
||||
}
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_wpgbx"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_r6b7x"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_hsiy4"]
|
||||
|
||||
[sub_resource type="Animation" id="Animation_wpgbx"]
|
||||
length = 0.001
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath(".:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [Vector2(461, 7)]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_mue51"]
|
||||
resource_name = "base"
|
||||
length = 0.6
|
||||
loop_mode = 1
|
||||
step = 0.2
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath(".:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.2, 0.4, 0.6),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [Vector2(455, 7), Vector2(458, 7), Vector2(461, 7), Vector2(455, 7)]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_r6b7x"]
|
||||
_data = {
|
||||
&"RESET": SubResource("Animation_wpgbx"),
|
||||
&"base": SubResource("Animation_mue51")
|
||||
}
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_nckjb"]
|
||||
bg_color = Color(0.913725, 0.913725, 0.913725, 0.913725)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_6r1e0"]
|
||||
bg_color = Color(0.913725, 0.913725, 0.913725, 0.913725)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_at31c"]
|
||||
bg_color = Color(0.913725, 0.913725, 0.913725, 0.913725)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_qrj6y"]
|
||||
bg_color = Color(0.913725, 0.913725, 0.913725, 0.913725)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_v0qi7"]
|
||||
bg_color = Color(0.913725, 0.913725, 0.913725, 0.913725)
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_rl25l"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_tndxe"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_xx8ge"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ep6fu"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ci4su"]
|
||||
|
||||
[node name="platform" type="NinePatchRect"]
|
||||
custom_minimum_size = Vector2(500, 350)
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -250.0
|
||||
offset_top = -175.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 175.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("1_kr1r5")
|
||||
region_rect = Rect2(1, 35, 86, 53)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 35
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 32
|
||||
script = ExtResource("2_bu5lv")
|
||||
|
||||
[node name="Title" type="NinePatchRect" parent="."]
|
||||
custom_minimum_size = Vector2(500, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -250.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 44.0
|
||||
grow_horizontal = 2
|
||||
texture = ExtResource("1_kr1r5")
|
||||
region_rect = Rect2(1, 27, 86, 8)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 7
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Title" type="Label" parent="Title"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -34.5
|
||||
offset_top = -18.0
|
||||
offset_right = 34.5
|
||||
offset_bottom = 18.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 27
|
||||
text = "游戏平台"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="previous" type="NinePatchRect" parent="Title"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 4
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 9.0
|
||||
offset_top = -15.0
|
||||
offset_right = 39.0
|
||||
offset_bottom = 15.0
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("2_6a8uh")
|
||||
region_rect = Rect2(0, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Title/previous"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_6a8uh")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_bu5lv")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_mue51")
|
||||
flat = true
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="Title/previous"]
|
||||
root_node = NodePath("../../..")
|
||||
libraries = {
|
||||
&"": SubResource("AnimationLibrary_mue51")
|
||||
}
|
||||
autoplay = "base"
|
||||
|
||||
[node name="next" type="NinePatchRect" parent="Title"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 6
|
||||
anchor_left = 1.0
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -39.0
|
||||
offset_top = -15.0
|
||||
offset_right = -9.0
|
||||
offset_bottom = 15.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("2_6a8uh")
|
||||
region_rect = Rect2(6, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Title/next"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_wpgbx")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_r6b7x")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_hsiy4")
|
||||
flat = true
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="Title/next"]
|
||||
libraries = {
|
||||
&"": SubResource("AnimationLibrary_r6b7x")
|
||||
}
|
||||
autoplay = "base"
|
||||
|
||||
[node name="Option" type="Control" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="Name" type="Label" parent="Option"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -75.0
|
||||
offset_top = -129.5
|
||||
offset_right = 75.0
|
||||
offset_bottom = -95.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 24
|
||||
text = "台式 & 笔记本"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Info" type="NinePatchRect" parent="Option"]
|
||||
custom_minimum_size = Vector2(440, 200)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -220.0
|
||||
offset_top = -92.0
|
||||
offset_right = 220.0
|
||||
offset_bottom = 130.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("1_kr1r5")
|
||||
region_rect = Rect2(92, 38, 76, 34)
|
||||
patch_margin_left = 2
|
||||
patch_margin_top = 33
|
||||
patch_margin_right = 2
|
||||
patch_margin_bottom = 33
|
||||
|
||||
[node name="Icon" type="NinePatchRect" parent="Option/Info"]
|
||||
custom_minimum_size = Vector2(144, 144)
|
||||
layout_mode = 1
|
||||
anchors_preset = 4
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_top = -108.0
|
||||
offset_right = 190.0
|
||||
offset_bottom = 82.0
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("3_bu5lv")
|
||||
|
||||
[node name="Info_List_1" type="GridContainer" parent="Option/Info"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 6
|
||||
anchor_left = 1.0
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -225.0
|
||||
offset_top = -82.0
|
||||
offset_right = -9.0
|
||||
offset_bottom = 19.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 2
|
||||
theme_override_constants/v_separation = 7
|
||||
|
||||
[node name="Info_1" type="HBoxContainer" parent="Option/Info/Info_List_1"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="start" type="Label" parent="Option/Info/Info_List_1/Info_1"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_nckjb")
|
||||
text = " "
|
||||
label_settings = ExtResource("4_mue51")
|
||||
|
||||
[node name="title" type="Label" parent="Option/Info/Info_List_1/Info_1"]
|
||||
custom_minimum_size = Vector2(90, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_nckjb")
|
||||
text = "制造商"
|
||||
label_settings = ExtResource("4_mue51")
|
||||
|
||||
[node name="info" type="Label" parent="Option/Info/Info_List_1/Info_1"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 2
|
||||
text = "不定"
|
||||
label_settings = ExtResource("4_mue51")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Info_2" type="HBoxContainer" parent="Option/Info/Info_List_1"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="start" type="Label" parent="Option/Info/Info_List_1/Info_2"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_nckjb")
|
||||
text = " "
|
||||
label_settings = ExtResource("4_mue51")
|
||||
|
||||
[node name="title" type="Label" parent="Option/Info/Info_List_1/Info_2"]
|
||||
custom_minimum_size = Vector2(90, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_6r1e0")
|
||||
text = "发售"
|
||||
label_settings = ExtResource("4_mue51")
|
||||
|
||||
[node name="info" type="Label" parent="Option/Info/Info_List_1/Info_2"]
|
||||
custom_minimum_size = Vector2(60, 0)
|
||||
layout_mode = 2
|
||||
text = "50"
|
||||
label_settings = ExtResource("4_mue51")
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="unit" type="Label" parent="Option/Info/Info_List_1/Info_2"]
|
||||
layout_mode = 2
|
||||
text = "万台"
|
||||
label_settings = ExtResource("4_mue51")
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Info_3" type="HBoxContainer" parent="Option/Info/Info_List_1"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="start" type="Label" parent="Option/Info/Info_List_1/Info_3"]
|
||||
custom_minimum_size = Vector2(6, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_nckjb")
|
||||
text = " "
|
||||
label_settings = ExtResource("4_mue51")
|
||||
|
||||
[node name="title" type="Label" parent="Option/Info/Info_List_1/Info_3"]
|
||||
custom_minimum_size = Vector2(90, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_at31c")
|
||||
text = "市场占比"
|
||||
label_settings = ExtResource("4_mue51")
|
||||
|
||||
[node name="info" type="Label" parent="Option/Info/Info_List_1/Info_3"]
|
||||
custom_minimum_size = Vector2(60, 0)
|
||||
layout_mode = 2
|
||||
text = "38"
|
||||
label_settings = ExtResource("4_mue51")
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="unit" type="Label" parent="Option/Info/Info_List_1/Info_3"]
|
||||
layout_mode = 2
|
||||
text = "%"
|
||||
label_settings = ExtResource("4_mue51")
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Info_List_2" type="HBoxContainer" parent="Option/Info"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 7
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -191.5
|
||||
offset_top = -38.0
|
||||
offset_right = 191.5
|
||||
offset_bottom = -10.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
alignment = 1
|
||||
|
||||
[node name="info_4" type="HBoxContainer" parent="Option/Info/Info_List_2"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="title" type="Label" parent="Option/Info/Info_List_2/info_4"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_qrj6y")
|
||||
text = "开发费用"
|
||||
label_settings = ExtResource("4_mue51")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info" type="Label" parent="Option/Info/Info_List_2/info_4"]
|
||||
custom_minimum_size = Vector2(70, 0)
|
||||
layout_mode = 2
|
||||
text = "500"
|
||||
label_settings = ExtResource("4_mue51")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info_5" type="HBoxContainer" parent="Option/Info/Info_List_2"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="title" type="Label" parent="Option/Info/Info_List_2/info_5"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_v0qi7")
|
||||
text = "开发次数"
|
||||
label_settings = ExtResource("4_mue51")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="info" type="Label" parent="Option/Info/Info_List_2/info_5"]
|
||||
custom_minimum_size = Vector2(30, 0)
|
||||
layout_mode = 2
|
||||
text = "0"
|
||||
label_settings = ExtResource("4_mue51")
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="unit" type="Label" parent="Option/Info/Info_List_2/info_5"]
|
||||
layout_mode = 2
|
||||
text = "次"
|
||||
label_settings = ExtResource("4_mue51")
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Confirm" type="Button" parent="."]
|
||||
custom_minimum_size = Vector2(70, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 7
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -35.0
|
||||
offset_top = -43.0
|
||||
offset_right = 35.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
theme = ExtResource("5_wpgbx")
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_focus_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 23
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_rl25l")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxFlat_tndxe")
|
||||
theme_override_styles/hover = SubResource("StyleBoxFlat_xx8ge")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_ep6fu")
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_ci4su")
|
||||
text = "确定"
|
||||
274
UI/popup/task_development_bak/product_focus/product_focus.gd
Normal file
274
UI/popup/task_development_bak/product_focus/product_focus.gd
Normal file
@ -0,0 +1,274 @@
|
||||
# product_focus.gd
|
||||
extends NinePatchRect
|
||||
|
||||
#-- 配置变量 (可在 Inspector 中调整) --
|
||||
@export var min_value_per_category: int = 0 # 每个类别的最小值
|
||||
@export var max_value_per_category: int = 10 # 每个类别的最大值 (对应10个格子)
|
||||
@export var active_color: Color = Color("05b700") # 激活格子的颜色
|
||||
@export var inactive_color: Color = Color("acacac") # 非激活格子的颜色
|
||||
|
||||
#-- 内部变量 --
|
||||
var total_points_from_state: int = 0 # 从 GameState 获取的总点数
|
||||
var remaining_points: int = 0
|
||||
# 存储每个类别 (info_1 到 info_6) 当前分配的点数
|
||||
var category_points: Array[int] = []
|
||||
# 存储每个类别在 GameState 中的键名 ("视觉表现", "游戏深度", ...)
|
||||
var category_keys: Array[String] = []
|
||||
|
||||
# 存储每个类别 UI 元素的引用
|
||||
var category_controls: Array[Dictionary] = []
|
||||
|
||||
#-- 节点引用 --
|
||||
@onready var points_label: Label = $Part_2/HBoxContainer/Points
|
||||
@onready var grid_container: GridContainer = $Part_3/GridContainer
|
||||
@onready var gameplay_info_label: Label = $Part_4/gameplay/info
|
||||
@onready var theme_info_label: Label = $Part_4/theme/info
|
||||
@onready var confirm_button: Button = $Confirm
|
||||
|
||||
func _ready():
|
||||
add_to_group(str(name)) # 方便父节点查找
|
||||
|
||||
# --- 初始化控件引用和类别键名 ---
|
||||
category_keys.clear()
|
||||
category_controls.clear()
|
||||
category_points.clear() # 确保清空
|
||||
|
||||
var category_index = 0
|
||||
for info_node in grid_container.get_children():
|
||||
if not info_node is VBoxContainer:
|
||||
continue
|
||||
|
||||
# 获取类别键名 (从 Title Label)
|
||||
var title_label = info_node.get_node_or_null("Title")
|
||||
if title_label:
|
||||
category_keys.append(title_label.text)
|
||||
else:
|
||||
printerr("Product Focus: Category node '%s' is missing a Title Label!" % info_node.name)
|
||||
category_keys.append("未知类别_%d" % category_index) # 占位符
|
||||
|
||||
# 获取并存储控件引用
|
||||
var hbox = info_node.get_node("HBoxContainer")
|
||||
var prev_button = hbox.get_node("Previous/Button")
|
||||
var next_button = hbox.get_node("Next/Button")
|
||||
var segments_container = hbox.get_node("Segments")
|
||||
|
||||
var segments_array: Array[ColorRect] = []
|
||||
for segment_node in segments_container.get_children():
|
||||
if segment_node is ColorRect:
|
||||
segments_array.append(segment_node)
|
||||
|
||||
if segments_array.size() != max_value_per_category:
|
||||
push_warning("Product Focus: Category '%s' has %d segments, expected %d." % [info_node.name, segments_array.size(), max_value_per_category])
|
||||
|
||||
var controls = {
|
||||
"prev_button": prev_button,
|
||||
"next_button": next_button,
|
||||
"segments": segments_array
|
||||
}
|
||||
category_controls.append(controls)
|
||||
|
||||
# 连接按钮信号 (确保只连接一次)
|
||||
if not prev_button.is_connected("pressed", _on_adjust_points):
|
||||
prev_button.pressed.connect(_on_adjust_points.bind(-1, category_index))
|
||||
if not next_button.is_connected("pressed", _on_adjust_points):
|
||||
next_button.pressed.connect(_on_adjust_points.bind(1, category_index))
|
||||
|
||||
category_index += 1
|
||||
|
||||
# 连接 visibility_changed 信号 (用于界面显示时重置)
|
||||
if not is_connected("visibility_changed", _on_visibility_changed):
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
|
||||
# 连接确认按钮信号
|
||||
if confirm_button and not confirm_button.is_connected("pressed", _on_confirm_pressed):
|
||||
confirm_button.pressed.connect(_on_confirm_pressed)
|
||||
elif not confirm_button:
|
||||
printerr("Product Focus: Confirm button node not found!")
|
||||
|
||||
# 初始数据加载和 UI 更新将在 _on_visibility_changed 中处理
|
||||
|
||||
# --- 可见性改变处理 ---
|
||||
func _on_visibility_changed():
|
||||
if is_visible_in_tree():
|
||||
print("Product Focus: Becoming visible, resetting display.")
|
||||
reset_display()
|
||||
# else: # 可选:隐藏时清理
|
||||
# print("Product Focus: Becoming hidden.")
|
||||
|
||||
# --- 重置和加载数据 ---
|
||||
func reset_display():
|
||||
if not GameState:
|
||||
printerr("Product Focus: GameState not available during reset_display.")
|
||||
# 可以考虑禁用界面或显示错误信息
|
||||
return
|
||||
|
||||
# 1. 从 GameState 获取 task_development 数据
|
||||
var task_dev_data: Dictionary = GameState.get_value("task_development", {})
|
||||
var focus_data: Dictionary = {} # 初始化为空字典
|
||||
|
||||
if task_dev_data.is_empty():
|
||||
push_warning("Product Focus: Failed to get 'task_development' data from GameState. Using defaults for focus points.")
|
||||
total_points_from_state = 20 # 使用默认总点数
|
||||
else:
|
||||
# 从 task_dev_data 中获取 product_focus_points
|
||||
focus_data = task_dev_data.get("product_focus_points", {})
|
||||
if focus_data.is_empty():
|
||||
push_warning("Product Focus: 'product_focus_points' not found in task_development data. Using defaults.")
|
||||
total_points_from_state = 20 # 使用默认总点数
|
||||
else:
|
||||
# 从 focus_data 获取总数,如果不存在则使用默认值
|
||||
total_points_from_state = focus_data.get("总数", 20)
|
||||
|
||||
# 2. 初始化本地 category_points (从 focus_data 加载)
|
||||
category_points.clear()
|
||||
var current_total_allocated = 0
|
||||
for key in category_keys:
|
||||
# 从 focus_data 获取该类别的值,进行类型检查和范围限制
|
||||
var value_loaded = focus_data.get(key, min_value_per_category)
|
||||
var value: int = min_value_per_category # 默认值
|
||||
|
||||
if typeof(value_loaded) == TYPE_INT:
|
||||
value = value_loaded
|
||||
elif typeof(value_loaded) == TYPE_FLOAT:
|
||||
value = int(value_loaded) # 浮点数转整数
|
||||
# push_warning("Product Focus: Loaded float value for key '%s', converting to int." % key)
|
||||
# else: # 非数字类型已在上面用默认值处理
|
||||
|
||||
# 确保值在合法范围内
|
||||
value = clamp(value, min_value_per_category, max_value_per_category)
|
||||
category_points.append(value)
|
||||
current_total_allocated += value
|
||||
|
||||
# 3. 计算剩余点数 (修正逻辑)
|
||||
# 如果加载的总分配点数超过了总点数(可能由于存档数据或配置问题)
|
||||
if current_total_allocated > total_points_from_state:
|
||||
push_warning("Product Focus: Loaded allocated points (%d) exceed total points (%d). Resetting points to minimums." % [current_total_allocated, total_points_from_state])
|
||||
# 重置所有点数为最小值,并重新计算
|
||||
category_points.clear()
|
||||
current_total_allocated = 0
|
||||
for _i in range(category_keys.size()):
|
||||
category_points.append(min_value_per_category)
|
||||
current_total_allocated += min_value_per_category
|
||||
remaining_points = total_points_from_state - current_total_allocated
|
||||
else:
|
||||
# 正常计算剩余点数
|
||||
remaining_points = total_points_from_state - current_total_allocated
|
||||
|
||||
# 4. 更新 UI
|
||||
_update_remaining_points_label()
|
||||
_update_all_category_visuals() # 更新所有格子颜色
|
||||
_update_all_button_states() # 更新所有按钮状态
|
||||
_load_part4_info() # 加载玩法和题材信息
|
||||
|
||||
# 处理点数调整按钮点击的函数
|
||||
func _on_adjust_points(delta: int, category_index: int):
|
||||
# 检查索引是否有效
|
||||
if category_index < 0 or category_index >= category_points.size():
|
||||
printerr("Product Focus: Invalid category_index %d in _on_adjust_points" % category_index)
|
||||
return
|
||||
|
||||
var current_cat_value = category_points[category_index]
|
||||
var new_cat_value = current_cat_value + delta
|
||||
|
||||
# 合法性检查: 是否在单项范围内,是否有足够剩余点数来增加
|
||||
if new_cat_value < min_value_per_category or new_cat_value > max_value_per_category:
|
||||
return # 超出单项范围
|
||||
if delta > 0 and remaining_points <= 0:
|
||||
return # 没点数了不能加
|
||||
|
||||
# 更新数据
|
||||
category_points[category_index] = new_cat_value
|
||||
remaining_points -= delta
|
||||
|
||||
# 更新 UI
|
||||
_update_remaining_points_label()
|
||||
_update_category_visuals(category_index) # 只更新当前类别的视觉
|
||||
_update_all_button_states() # 更新所有按钮状态(因为剩余点数或单项值变了)
|
||||
|
||||
# 更新指定类别的格子颜色
|
||||
func _update_category_visuals(category_index: int):
|
||||
if category_index < 0 or category_index >= category_controls.size():
|
||||
printerr("Product Focus: Invalid category_index %d in _update_category_visuals" % category_index)
|
||||
return
|
||||
if category_index >= category_points.size():
|
||||
printerr("Product Focus: category_points array out of bounds for index %d" % category_index)
|
||||
return
|
||||
|
||||
var value = category_points[category_index]
|
||||
var segments = category_controls[category_index]["segments"]
|
||||
|
||||
for i in range(segments.size()):
|
||||
if i < value:
|
||||
segments[i].color = active_color
|
||||
else:
|
||||
segments[i].color = inactive_color
|
||||
|
||||
# 更新所有类别的格子颜色
|
||||
func _update_all_category_visuals():
|
||||
for i in range(category_controls.size()):
|
||||
_update_category_visuals(i)
|
||||
|
||||
# 更新剩余点数标签的文本
|
||||
func _update_remaining_points_label():
|
||||
points_label.text = str(remaining_points)
|
||||
|
||||
# 更新所有类别按钮的启用/禁用状态
|
||||
func _update_all_button_states():
|
||||
for i in range(category_controls.size()):
|
||||
if i >= category_controls.size() or i >= category_points.size():
|
||||
printerr("Product Focus: Index mismatch in _update_all_button_states at index %d" % i)
|
||||
continue # 安全检查
|
||||
|
||||
var controls = category_controls[i]
|
||||
var value = category_points[i]
|
||||
|
||||
# 更新 "-" 按钮状态: 当前值 > 最小值时启用
|
||||
controls["prev_button"].disabled = (value <= min_value_per_category)
|
||||
|
||||
# 更新 "+" 按钮状态: 当前值 < 最大值 且 剩余点数 > 0 时启用
|
||||
var can_increment = (value < max_value_per_category) and (remaining_points > 0)
|
||||
controls["next_button"].disabled = not can_increment
|
||||
|
||||
# 从父节点加载 Part_4 的信息 (玩法和题材)
|
||||
func _load_part4_info():
|
||||
var parent = get_parent()
|
||||
# 检查父节点和 task_info 是否有效
|
||||
if not is_instance_valid(parent):
|
||||
push_warning("Product Focus: Parent node or its 'task_info' metadata not available for Part 4.")
|
||||
gameplay_info_label.text = "错误"
|
||||
theme_info_label.text = "错误"
|
||||
return
|
||||
|
||||
# 使用 get_meta 获取,避免直接访问可能不存在的属性
|
||||
var task_info = parent.task_info # 提供默认值 null
|
||||
if task_info is Dictionary:
|
||||
gameplay_info_label.text = task_info.get("玩法", "未知")
|
||||
theme_info_label.text = task_info.get("题材", "未知")
|
||||
else:
|
||||
push_warning("Product Focus: Parent's task_info metadata is not a Dictionary or is null.")
|
||||
gameplay_info_label.text = "错误"
|
||||
theme_info_label.text = "错误"
|
||||
|
||||
# --- 处理确定按钮的逻辑 ---
|
||||
func _on_confirm_pressed():
|
||||
# 1. 构建包含当前侧重点分配的字典
|
||||
var confirmed_focus_points: Dictionary = {}
|
||||
if category_keys.size() != category_points.size():
|
||||
printerr("Product Focus: Mismatch between category_keys and category_points on confirm!")
|
||||
# 可以考虑显示错误提示给用户
|
||||
return # 阻止继续执行
|
||||
|
||||
for i in range(category_keys.size()):
|
||||
confirmed_focus_points[category_keys[i]] = category_points[i]
|
||||
|
||||
# 2. 获取父节点 (task_development) 并 传递数据
|
||||
var parent_node = get_parent()
|
||||
if parent_node and parent_node.has_method("update_task_options"):
|
||||
# 通知父节点更新其内部的 task_info
|
||||
parent_node.update_task_options({"产品侧重点": confirmed_focus_points})
|
||||
else:
|
||||
printerr("错误:Product Focus: 父节点未找到或缺少 'update_task_options' 方法。")
|
||||
|
||||
# 3. 进入下一个节点
|
||||
self.hide()
|
||||
parent_node.show_dialogue("谁来写立项书呢?", "proposal")
|
||||
@ -0,0 +1 @@
|
||||
uid://dfny4mxgw5yb6
|
||||
794
UI/popup/task_development_bak/product_focus/product_focus.tscn
Normal file
794
UI/popup/task_development_bak/product_focus/product_focus.tscn
Normal file
@ -0,0 +1,794 @@
|
||||
[gd_scene load_steps=21 format=3 uid="uid://dpshanwm4o3by"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://pucudatqrcrq" path="res://UI/popup/popup_bg_1.png" id="1_kjf47"]
|
||||
[ext_resource type="Script" uid="uid://dfny4mxgw5yb6" path="res://UI/popup/task_development_bak/product_focus/product_focus.gd" id="2_dt4oy"]
|
||||
[ext_resource type="FontFile" uid="uid://bbr43ojt1sreu" path="res://UI/font/MinecraftStandard.otf" id="2_klru0"]
|
||||
[ext_resource type="FontFile" uid="uid://egugs822n8gr" path="res://UI/font/AlimamaFangYuanTiVF-Thin.ttf" id="3_hxsho"]
|
||||
[ext_resource type="LabelSettings" uid="uid://qcn0aduvrgvw" path="res://UI/tres/task_development_platform_label_settings.tres" id="3_kjf47"]
|
||||
[ext_resource type="Theme" uid="uid://bau80ps6kx783" path="res://UI/tres/Bottom_Info_button_theme.tres" id="4_hxsho"]
|
||||
[ext_resource type="Texture2D" uid="uid://dgcugleiv7sfw" path="res://UI/popup/task_development/arrow.png" id="4_klru0"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ct65a"]
|
||||
|
||||
[sub_resource type="LabelSettings" id="LabelSettings_lha8x"]
|
||||
font = ExtResource("2_klru0")
|
||||
font_size = 14
|
||||
outline_size = 6
|
||||
outline_color = Color(0, 0, 0, 1)
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_dt4oy"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_hxsho"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_lha8x"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_33nyt"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_u37th"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_wmlhw"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_rjt3h"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ykocv"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_oakbh"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_pi7v6"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_so1ex"]
|
||||
|
||||
[node name="product_focus" type="NinePatchRect"]
|
||||
custom_minimum_size = Vector2(500, 350)
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -250.0
|
||||
offset_top = -175.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 175.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("1_kjf47")
|
||||
region_rect = Rect2(1, 35, 86, 53)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 35
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 32
|
||||
script = ExtResource("2_dt4oy")
|
||||
|
||||
[node name="Part_1" type="NinePatchRect" parent="."]
|
||||
custom_minimum_size = Vector2(500, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -250.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 44.0
|
||||
grow_horizontal = 2
|
||||
texture = ExtResource("1_kjf47")
|
||||
region_rect = Rect2(1, 27, 86, 8)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 7
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Title" type="Label" parent="Part_1"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -34.5
|
||||
offset_top = -18.0
|
||||
offset_right = 34.5
|
||||
offset_bottom = 18.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 27
|
||||
text = "侧重点"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="Part_2" type="Control" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -20.0
|
||||
offset_top = 34.0
|
||||
offset_right = 20.0
|
||||
offset_bottom = 53.0
|
||||
grow_horizontal = 2
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Part_2"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -89.0
|
||||
offset_top = 4.0
|
||||
offset_right = 143.0
|
||||
offset_bottom = 38.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
alignment = 1
|
||||
|
||||
[node name="Title" type="Label" parent="Part_2/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_fonts/font = ExtResource("3_hxsho")
|
||||
theme_override_font_sizes/font_size = 24
|
||||
text = "剩余可用点数"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Points" type="Label" parent="Part_2/HBoxContainer"]
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_ct65a")
|
||||
text = "2"
|
||||
label_settings = SubResource("LabelSettings_lha8x")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Part_3" type="NinePatchRect" parent="."]
|
||||
custom_minimum_size = Vector2(440, 200)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -220.0
|
||||
offset_top = -91.0
|
||||
offset_right = 220.0
|
||||
offset_bottom = 109.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("1_kjf47")
|
||||
region_rect = Rect2(92, 38, 76, 34)
|
||||
patch_margin_left = 2
|
||||
patch_margin_top = 33
|
||||
patch_margin_right = 2
|
||||
patch_margin_bottom = 33
|
||||
|
||||
[node name="GridContainer" type="GridContainer" parent="Part_3"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -204.0
|
||||
offset_top = -79.0
|
||||
offset_right = 204.0
|
||||
offset_bottom = 79.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/h_separation = 40
|
||||
theme_override_constants/v_separation = 10
|
||||
columns = 2
|
||||
|
||||
[node name="info_1" type="VBoxContainer" parent="Part_3/GridContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Title" type="Label" parent="Part_3/GridContainer/info_1"]
|
||||
layout_mode = 2
|
||||
text = "视觉表现"
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Part_3/GridContainer/info_1"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Previous" type="NinePatchRect" parent="Part_3/GridContainer/info_1/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
region_rect = Rect2(0, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_1/HBoxContainer/Previous"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_dt4oy")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_hxsho")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_lha8x")
|
||||
flat = true
|
||||
|
||||
[node name="Segments" type="HBoxContainer" parent="Part_3/GridContainer/info_1/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_1" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_2" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_3" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_4" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_5" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_6" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_7" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_8" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_9" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_10" type="ColorRect" parent="Part_3/GridContainer/info_1/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Next" type="NinePatchRect" parent="Part_3/GridContainer/info_1/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
region_rect = Rect2(6, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_1/HBoxContainer/Next"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_33nyt")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_u37th")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_wmlhw")
|
||||
flat = true
|
||||
|
||||
[node name="info_2" type="VBoxContainer" parent="Part_3/GridContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Title" type="Label" parent="Part_3/GridContainer/info_2"]
|
||||
layout_mode = 2
|
||||
text = "游戏深度"
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Part_3/GridContainer/info_2"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Previous" type="NinePatchRect" parent="Part_3/GridContainer/info_2/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
region_rect = Rect2(0, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_2/HBoxContainer/Previous"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_dt4oy")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_hxsho")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_lha8x")
|
||||
flat = true
|
||||
|
||||
[node name="Segments" type="HBoxContainer" parent="Part_3/GridContainer/info_2/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_1" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_2" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_3" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_4" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_5" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_6" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_7" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_8" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_9" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_10" type="ColorRect" parent="Part_3/GridContainer/info_2/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Next" type="NinePatchRect" parent="Part_3/GridContainer/info_2/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
region_rect = Rect2(6, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_2/HBoxContainer/Next"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_33nyt")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_u37th")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_wmlhw")
|
||||
flat = true
|
||||
|
||||
[node name="info_3" type="VBoxContainer" parent="Part_3/GridContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Title" type="Label" parent="Part_3/GridContainer/info_3"]
|
||||
layout_mode = 2
|
||||
text = "创新性"
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Part_3/GridContainer/info_3"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Previous" type="NinePatchRect" parent="Part_3/GridContainer/info_3/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
region_rect = Rect2(0, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_3/HBoxContainer/Previous"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_dt4oy")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_hxsho")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_lha8x")
|
||||
flat = true
|
||||
|
||||
[node name="Segments" type="HBoxContainer" parent="Part_3/GridContainer/info_3/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_1" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_2" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_3" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_4" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_5" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_6" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_7" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_8" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_9" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_10" type="ColorRect" parent="Part_3/GridContainer/info_3/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Next" type="NinePatchRect" parent="Part_3/GridContainer/info_3/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
region_rect = Rect2(6, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_3/HBoxContainer/Next"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_33nyt")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_u37th")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_wmlhw")
|
||||
flat = true
|
||||
|
||||
[node name="info_4" type="VBoxContainer" parent="Part_3/GridContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Title" type="Label" parent="Part_3/GridContainer/info_4"]
|
||||
layout_mode = 2
|
||||
text = "易玩性"
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Part_3/GridContainer/info_4"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Previous" type="NinePatchRect" parent="Part_3/GridContainer/info_4/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
region_rect = Rect2(0, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_4/HBoxContainer/Previous"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_dt4oy")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_hxsho")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_lha8x")
|
||||
flat = true
|
||||
|
||||
[node name="Segments" type="HBoxContainer" parent="Part_3/GridContainer/info_4/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_1" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_2" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_3" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_4" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_5" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_6" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_7" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_8" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_9" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_10" type="ColorRect" parent="Part_3/GridContainer/info_4/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Next" type="NinePatchRect" parent="Part_3/GridContainer/info_4/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
region_rect = Rect2(6, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_4/HBoxContainer/Next"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_33nyt")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_u37th")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_wmlhw")
|
||||
flat = true
|
||||
|
||||
[node name="info_5" type="VBoxContainer" parent="Part_3/GridContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Title" type="Label" parent="Part_3/GridContainer/info_5"]
|
||||
layout_mode = 2
|
||||
text = "操控感"
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Part_3/GridContainer/info_5"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Previous" type="NinePatchRect" parent="Part_3/GridContainer/info_5/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
region_rect = Rect2(0, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_5/HBoxContainer/Previous"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_dt4oy")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_hxsho")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_lha8x")
|
||||
flat = true
|
||||
|
||||
[node name="Segments" type="HBoxContainer" parent="Part_3/GridContainer/info_5/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_1" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_2" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_3" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_4" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_5" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_6" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_7" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_8" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_9" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_10" type="ColorRect" parent="Part_3/GridContainer/info_5/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Next" type="NinePatchRect" parent="Part_3/GridContainer/info_5/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
region_rect = Rect2(6, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_5/HBoxContainer/Next"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_33nyt")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_u37th")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_wmlhw")
|
||||
flat = true
|
||||
|
||||
[node name="info_6" type="VBoxContainer" parent="Part_3/GridContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Title" type="Label" parent="Part_3/GridContainer/info_6"]
|
||||
layout_mode = 2
|
||||
text = "沉浸感"
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Part_3/GridContainer/info_6"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Previous" type="NinePatchRect" parent="Part_3/GridContainer/info_6/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
region_rect = Rect2(0, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_6/HBoxContainer/Previous"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_dt4oy")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_hxsho")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_lha8x")
|
||||
flat = true
|
||||
|
||||
[node name="Segments" type="HBoxContainer" parent="Part_3/GridContainer/info_6/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_1" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_2" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_3" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_4" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_5" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_6" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_7" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_8" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_9" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Segment_10" type="ColorRect" parent="Part_3/GridContainer/info_6/HBoxContainer/Segments"]
|
||||
custom_minimum_size = Vector2(10, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Next" type="NinePatchRect" parent="Part_3/GridContainer/info_6/HBoxContainer"]
|
||||
modulate = Color(0.888333, 0.739503, 0.29321, 1)
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_klru0")
|
||||
region_rect = Rect2(6, 0, 6, 9)
|
||||
|
||||
[node name="Button" type="Button" parent="Part_3/GridContainer/info_6/HBoxContainer/Next"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_33nyt")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_u37th")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_wmlhw")
|
||||
flat = true
|
||||
|
||||
[node name="Part_4" type="VBoxContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 2
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 37.0
|
||||
offset_top = -55.0
|
||||
offset_right = 191.0
|
||||
offset_bottom = -11.0
|
||||
grow_vertical = 0
|
||||
theme_override_constants/separation = 2
|
||||
|
||||
[node name="gameplay" type="HBoxContainer" parent="Part_4"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="title" type="Label" parent="Part_4/gameplay"]
|
||||
layout_mode = 2
|
||||
text = "玩法 - "
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
|
||||
[node name="info" type="Label" parent="Part_4/gameplay"]
|
||||
layout_mode = 2
|
||||
text = "桌面游戏"
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
|
||||
[node name="theme" type="HBoxContainer" parent="Part_4"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="title" type="Label" parent="Part_4/theme"]
|
||||
layout_mode = 2
|
||||
text = "题材 - "
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
|
||||
[node name="info" type="Label" parent="Part_4/theme"]
|
||||
layout_mode = 2
|
||||
text = "校园模拟"
|
||||
label_settings = ExtResource("3_kjf47")
|
||||
|
||||
[node name="Confirm" type="Button" parent="."]
|
||||
custom_minimum_size = Vector2(70, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 3
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -137.0
|
||||
offset_top = -58.0
|
||||
offset_right = -67.0
|
||||
offset_bottom = -15.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 0
|
||||
theme = ExtResource("4_hxsho")
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_focus_color = Color(0, 0, 0, 1)
|
||||
theme_override_fonts/font = ExtResource("3_hxsho")
|
||||
theme_override_font_sizes/font_size = 23
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_rjt3h")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxFlat_ykocv")
|
||||
theme_override_styles/hover = SubResource("StyleBoxFlat_oakbh")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_pi7v6")
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_so1ex")
|
||||
text = "确定"
|
||||
291
UI/popup/task_development_bak/strategy/strategy.gd
Normal file
291
UI/popup/task_development_bak/strategy/strategy.gd
Normal file
@ -0,0 +1,291 @@
|
||||
# 文件名: strategy.gd
|
||||
# 脚本作用: 控制策略选择界面的显示和交互 (使用主题资源处理焦点视觉)
|
||||
# 版本:已根据方案 A 修改,使用通用 GameState 接口,从父节点获取初始选择
|
||||
|
||||
extends NinePatchRect
|
||||
|
||||
# --- 节点引用 ---
|
||||
@onready var options_container: VBoxContainer = $Option/Options/List_1
|
||||
@onready var explanation_label: Label = $Option/Explaination
|
||||
|
||||
# --- 内部状态 ---
|
||||
var option_buttons: Array[Button] = [] # 存储选项按钮节点的数组
|
||||
var highlighted_button: Button = null # 当前逻辑上选中的按钮 (用于区分首次点击和确认点击)
|
||||
var current_strategy_data: Dictionary = {} # 存储从 GameState 获取的原始策略数据
|
||||
var initial_selection_key: String = "" # 由父节点传入的初始/当前选择的策略 Key (中文名)
|
||||
|
||||
# --- 初始化 ---
|
||||
func _ready() -> void:
|
||||
add_to_group(str(name)) # 便于父节点或其他系统查找
|
||||
|
||||
# --- 获取按钮引用 ---
|
||||
option_buttons.clear()
|
||||
for child in options_container.get_children():
|
||||
if child is Button:
|
||||
option_buttons.append(child)
|
||||
# 断开旧连接以防万一 (虽然理论上 _ready 只执行一次)
|
||||
if child.is_connected("pressed", _on_option_button_pressed):
|
||||
child.disconnect("pressed", _on_option_button_pressed)
|
||||
|
||||
# --- 连接 GameState 通用值变化信号 ---
|
||||
# 用于响应策略数据可能的动态变化 (如解锁新策略)
|
||||
if GameState and not GameState.state_value_changed.is_connected(_on_game_state_value_changed):
|
||||
GameState.state_value_changed.connect(_on_game_state_value_changed)
|
||||
|
||||
# --- 连接 visibility_changed 信号 ---
|
||||
# 确保每次界面可见时都刷新列表内容
|
||||
if not is_connected("visibility_changed", _on_visibility_changed):
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
|
||||
# _update_strategy_list() 不再在 _ready 中调用,移至 _on_visibility_changed
|
||||
|
||||
# --- 父节点调用接口 ---
|
||||
# 由父节点 (task_development.gd) 在显示此弹窗前调用,传入当前的临时选择
|
||||
func set_initial_selection(strategy_key: String) -> void:
|
||||
initial_selection_key = strategy_key
|
||||
print("Strategy: Initial selection key set by parent: '", initial_selection_key, "'")
|
||||
# 注意:这里只存储值,实际的高亮逻辑仍在 _update_strategy_list 中处理
|
||||
|
||||
# --- 信号处理 ---
|
||||
|
||||
# 处理可见性变化的函数
|
||||
func _on_visibility_changed() -> void:
|
||||
print("Strategy: _on_visibility_changed called, visible = ", is_visible_in_tree())
|
||||
# 当节点变为可见时,更新列表并设置初始焦点
|
||||
if is_visible_in_tree():
|
||||
print("Strategy popup became visible. Updating list and setting focus...")
|
||||
# 确保在更新列表前,initial_selection_key 已被父节点设置
|
||||
_update_strategy_list()
|
||||
# else: # 可选:如果需要在隐藏时做清理,可以在这里添加逻辑
|
||||
# print("Strategy popup became hidden.")
|
||||
|
||||
# 当 GameState 的任何值发生变化时调用
|
||||
func _on_game_state_value_changed(key: String, new_value) -> void:
|
||||
# 检查是否是 task_development 数据发生了变化,这可能影响可用策略
|
||||
# 注意:这是一个比较宽泛的检查。如果 task_development 下其他不相关数据变化也会触发刷新。
|
||||
if key == "task_development":
|
||||
# 并且确保当前界面是可见的,避免在后台刷新不可见的UI
|
||||
if is_visible_in_tree():
|
||||
print("Strategy: Detected change in 'task_development', refreshing list...")
|
||||
# 重新执行列表更新,它会使用最新的 GameState 数据
|
||||
# 并尝试根据 initial_selection_key (由父节点设定,理论上不变) 恢复高亮
|
||||
_update_strategy_list()
|
||||
|
||||
# --- 核心 UI 更新逻辑 ---
|
||||
|
||||
# 更新策略列表UI的函数
|
||||
func _update_strategy_list() -> void:
|
||||
# 0. 重置界面逻辑状态 (清除上次的高亮和说明)
|
||||
_reset_highlight_state()
|
||||
|
||||
# 1. 从 GameState 获取最新的 task_development 数据
|
||||
if not GameState:
|
||||
printerr("Strategy: GameState not available during _update_strategy_list.")
|
||||
for button in option_buttons: button.visible = false
|
||||
explanation_label.text = "错误:无法访问游戏状态。"
|
||||
return
|
||||
|
||||
var task_dev_data: Dictionary = GameState.get_value("task_development", {})
|
||||
if task_dev_data.is_empty():
|
||||
printerr("Strategy: Failed to get 'task_development' data from GameState.")
|
||||
for button in option_buttons: button.visible = false
|
||||
explanation_label.text = "错误:无法获取开发数据。"
|
||||
return
|
||||
|
||||
# 提取策略子字典
|
||||
current_strategy_data = task_dev_data.get("strategies", {})
|
||||
if current_strategy_data.is_empty():
|
||||
printerr("Strategy: 'strategies' data not found or empty in task_development.")
|
||||
for button in option_buttons: button.visible = false
|
||||
explanation_label.text = "没有可用的开发策略。"
|
||||
return
|
||||
|
||||
# 2. 筛选出已启用的策略
|
||||
var enabled_strategies = []
|
||||
for strategy_name in current_strategy_data: # 遍历字典的键 (策略中文名)
|
||||
var details: Dictionary = current_strategy_data[strategy_name]
|
||||
# 确保 details 是字典并且 'enabled' 键存在且为 true
|
||||
if typeof(details) == TYPE_DICTIONARY and details.get("enabled", false) == true:
|
||||
enabled_strategies.append({"name": strategy_name, "details": details})
|
||||
|
||||
# 如果需要固定顺序,可能需要先对 enabled_strategies 排序 (基于某个字段或预设顺序)
|
||||
# enabled_strategies.sort_custom(func(a, b): return a["name"] < b["name"]) # 示例:按名称排序
|
||||
|
||||
# 3. 填充按钮
|
||||
var strategy_index: int = 0
|
||||
var first_enabled_button: Button = null # 用于没有初始选择时的默认高亮
|
||||
|
||||
# --- 确保每次更新时正确设置按钮状态和信号连接 ---
|
||||
for button in option_buttons: # 遍历场景中预设的按钮
|
||||
button.visible = false # 默认隐藏
|
||||
button.disabled = true # 默认禁用
|
||||
# 断开旧的 pressed 信号连接,防止重复触发
|
||||
if button.is_connected("pressed", _on_option_button_pressed):
|
||||
button.disconnect("pressed", _on_option_button_pressed)
|
||||
# 清除可能存在的旧元数据
|
||||
if button.has_meta("strategy_name"):
|
||||
button.remove_meta("strategy_name")
|
||||
|
||||
# 使用筛选出的启用策略数据填充按钮
|
||||
while strategy_index < enabled_strategies.size() and strategy_index < option_buttons.size():
|
||||
var button: Button = option_buttons[strategy_index]
|
||||
var strategy_data: Dictionary = enabled_strategies[strategy_index]
|
||||
var strategy_name: String = strategy_data["name"]
|
||||
var strategy_details: Dictionary = strategy_data["details"]
|
||||
|
||||
# 获取按钮内部的标签节点
|
||||
var title_label: Label = button.find_child("Title", true, false) as Label
|
||||
var cost_label: Label = button.find_child("Cost", true, false) as Label
|
||||
|
||||
if title_label and cost_label:
|
||||
# 设置策略名称
|
||||
title_label.text = strategy_name
|
||||
|
||||
# 设置成本显示 (格式化为百分比)
|
||||
var cost_value = strategy_details.get("Cost", null) # 尝试获取 Cost 值
|
||||
if typeof(cost_value) == TYPE_FLOAT or typeof(cost_value) == TYPE_INT:
|
||||
var percentage: int = int(cost_value * 100)
|
||||
cost_label.text = "+%d%%" % percentage # GDScript 中 % 需要转义
|
||||
else:
|
||||
cost_label.text = "N/A" # 如果 Cost 不存在或不是数字
|
||||
|
||||
# 将策略名称存储在按钮元数据中,方便点击时获取
|
||||
button.set_meta("strategy_name", strategy_name)
|
||||
button.visible = true # 显示按钮
|
||||
button.disabled = false # 启用按钮
|
||||
# 重新连接 pressed 信号,并绑定按钮自身作为参数
|
||||
button.pressed.connect(_on_option_button_pressed.bind(button))
|
||||
|
||||
# 记录第一个可用的按钮,作为没有初始选择时的备选高亮目标
|
||||
if first_enabled_button == null:
|
||||
first_enabled_button = button
|
||||
else:
|
||||
printerr("Strategy: 在按钮 '%s' 下未找到 Title 或 Cost 标签。" % button.name)
|
||||
# 保持按钮隐藏和禁用
|
||||
|
||||
strategy_index += 1
|
||||
|
||||
# 4. 设置初始逻辑选中状态和焦点
|
||||
print("--- Updating Strategy List ---")
|
||||
print("Initial selection key from parent: '", initial_selection_key, "'")
|
||||
var initial_highlight_button: Button = null
|
||||
|
||||
# 尝试根据父节点传入的 initial_selection_key 找到对应的按钮
|
||||
if not initial_selection_key.is_empty():
|
||||
print("Searching for matching button for key: '", initial_selection_key, "'")
|
||||
for button in option_buttons:
|
||||
# 检查按钮是否可见、启用,并且其元数据中的策略名与初始选择键匹配
|
||||
if button.visible and not button.disabled:
|
||||
var meta_name = button.get_meta("strategy_name", "")
|
||||
# print(" Checking button: '", button.name, "' with meta: '", meta_name, "'") # Debug
|
||||
if meta_name == initial_selection_key:
|
||||
print(" Match found!: ", button.name)
|
||||
initial_highlight_button = button
|
||||
break # 找到后即可停止搜索
|
||||
|
||||
# 如果没有找到匹配的按钮 (例如初始选择为空,或对应的策略不再可用)
|
||||
if initial_highlight_button == null:
|
||||
print("No match found for initial key or key was empty. Trying first enabled button.")
|
||||
initial_highlight_button = first_enabled_button # 使用第一个可用的按钮作为默认高亮
|
||||
|
||||
# 如果找到了要高亮的按钮 (无论是匹配到的还是第一个可用的)
|
||||
if initial_highlight_button:
|
||||
print("Button to initially highlight: ", initial_highlight_button.name)
|
||||
# 设置逻辑高亮状态并尝试让其获得焦点
|
||||
_set_initial_highlight(initial_highlight_button)
|
||||
else:
|
||||
# 如果连第一个可用的按钮都没有 (例如所有策略都未启用)
|
||||
print("No button available to highlight.")
|
||||
explanation_label.text = "没有可用的开发策略。" # 更新说明文本
|
||||
print("--- Finished Updating Strategy List ---")
|
||||
|
||||
|
||||
# --- 交互处理 ---
|
||||
|
||||
# 处理选项按钮点击事件的函数
|
||||
func _on_option_button_pressed(button_node: Button) -> void:
|
||||
# 从按钮元数据获取对应的策略名称
|
||||
var strategy_name: String = button_node.get_meta("strategy_name", "")
|
||||
if strategy_name.is_empty():
|
||||
printerr("Strategy: 无法从按钮 %s 获取 strategy_name 元数据。" % button_node.name)
|
||||
return
|
||||
|
||||
# 检查点击的按钮是否就是当前已逻辑高亮的按钮
|
||||
if button_node == highlighted_button:
|
||||
# --- 第二次点击 (确认选择) ---
|
||||
print("Strategy: Confirmed selection - ", strategy_name)
|
||||
|
||||
# 1. 通知父节点更新临时选择状态
|
||||
var parent_node = get_parent() # 获取父节点 (应该是 task_development)
|
||||
if parent_node and parent_node.has_method("update_task_options"):
|
||||
# 调用父节点的接口,传递更新信息 (使用中文键名)
|
||||
parent_node.update_task_options({"开发策略": strategy_name})
|
||||
print("Strategy: Updated parent task options with 开发策略 = ", strategy_name)
|
||||
else:
|
||||
printerr("Strategy: Parent node not found or missing 'update_task_options' method.")
|
||||
|
||||
# 2. 请求父节点关闭当前弹窗并返回主界面
|
||||
if parent_node and parent_node.has_method("_close_child_popup_and_return"):
|
||||
parent_node._close_child_popup_and_return(self)
|
||||
else:
|
||||
# 作为备选方案,如果找不到父节点或方法,直接隐藏自己
|
||||
printerr("Strategy: Parent node not found or missing '_close_child_popup_and_return' method. Hiding self.")
|
||||
self.hide()
|
||||
|
||||
else:
|
||||
# --- 第一次点击 或 点击了不同的按钮 (更新逻辑选择和说明) ---
|
||||
print("Strategy: Logically selected - ", strategy_name)
|
||||
# 更新当前逻辑高亮的按钮引用
|
||||
highlighted_button = button_node
|
||||
|
||||
# 更新底部的说明文本
|
||||
# 确保 current_strategy_data 是最新的 (理论上 _update_strategy_list 刚更新过)
|
||||
if current_strategy_data.has(strategy_name):
|
||||
var details: Dictionary = current_strategy_data[strategy_name]
|
||||
explanation_label.text = details.get("Explaination", "暂无说明。") # 使用 .get 提供默认值
|
||||
else:
|
||||
# 如果因为某些原因数据不同步,显示错误
|
||||
explanation_label.text = "错误:找不到策略详情。"
|
||||
printerr("Strategy: Could not find details for strategy '", strategy_name, "' in current_strategy_data.")
|
||||
|
||||
# 注意:此时按钮的视觉焦点可能还未改变,依赖于 Button 主题的 focus 样式
|
||||
# _set_initial_highlight 内部会处理 grab_focus
|
||||
|
||||
# --- 辅助函数 ---
|
||||
|
||||
# (辅助函数) 重置界面逻辑高亮状态
|
||||
func _reset_highlight_state() -> void:
|
||||
highlighted_button = null # 清除逻辑高亮引用
|
||||
explanation_label.text = "" # 清空说明文本
|
||||
|
||||
# (辅助函数) 设置初始逻辑选中按钮并赋予焦点
|
||||
func _set_initial_highlight(button_to_highlight: Button) -> void:
|
||||
print("--- Setting Initial Highlight ---")
|
||||
if not is_instance_valid(button_to_highlight):
|
||||
printerr("Strategy: Invalid button passed to _set_initial_highlight.")
|
||||
return
|
||||
|
||||
print("Button received: ", button_to_highlight.name)
|
||||
# 设置逻辑高亮引用
|
||||
highlighted_button = button_to_highlight
|
||||
print("highlighted_button variable set to: ", highlighted_button.name)
|
||||
|
||||
# 更新说明文本
|
||||
var strategy_name = highlighted_button.get_meta("strategy_name", "")
|
||||
if not strategy_name.is_empty() and current_strategy_data.has(strategy_name):
|
||||
var details: Dictionary = current_strategy_data[strategy_name]
|
||||
explanation_label.text = details.get("Explaination", "暂无说明。")
|
||||
elif not strategy_name.is_empty():
|
||||
explanation_label.text = "错误:找不到策略详情。"
|
||||
printerr("Strategy: Could not find details for highlighted strategy '", strategy_name, "'")
|
||||
else:
|
||||
explanation_label.text = "错误:无法获取策略名称。" # 如果连元数据都没有
|
||||
|
||||
# 尝试让按钮获得实际输入焦点 (使用 call_deferred 确保在安全的时机执行)
|
||||
# 这会让按钮应用其主题中的 "focus" 样式
|
||||
if highlighted_button.is_inside_tree() and highlighted_button.visible and not highlighted_button.disabled:
|
||||
print("Attempting call_deferred('grab_focus') for: ", highlighted_button.name)
|
||||
highlighted_button.call_deferred("grab_focus")
|
||||
else:
|
||||
print("Button '%s' not valid, not in tree, hidden, or disabled. Cannot grab focus." % highlighted_button.name)
|
||||
print("--- Finished Setting Initial Highlight ---")
|
||||
1
UI/popup/task_development_bak/strategy/strategy.gd.uid
Normal file
1
UI/popup/task_development_bak/strategy/strategy.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://b5mfw2kc6lqpd
|
||||
351
UI/popup/task_development_bak/strategy/strategy.tscn
Normal file
351
UI/popup/task_development_bak/strategy/strategy.tscn
Normal file
@ -0,0 +1,351 @@
|
||||
[gd_scene load_steps=5 format=3 uid="uid://ctcbxvgljrkvi"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://pucudatqrcrq" path="res://UI/popup/popup_bg_1.png" id="1_pbd5q"]
|
||||
[ext_resource type="Script" uid="uid://b5mfw2kc6lqpd" path="res://UI/popup/task_development_bak/strategy/strategy.gd" id="2_rq5uk"]
|
||||
[ext_resource type="Theme" uid="uid://ddq54ba6vwyn0" path="res://UI/popup/task_development/main_plan/gameplay/gameplay_option_button.tres" id="3_rq5uk"]
|
||||
[ext_resource type="Texture2D" uid="uid://bb3kyiufyyj05" path="res://Entity/NPC/NPC_1_UI.png" id="4_pbd5q"]
|
||||
|
||||
[node name="strategy" type="NinePatchRect"]
|
||||
custom_minimum_size = Vector2(500, 350)
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -250.0
|
||||
offset_top = -175.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 175.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("1_pbd5q")
|
||||
region_rect = Rect2(1, 35, 86, 53)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 35
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 32
|
||||
script = ExtResource("2_rq5uk")
|
||||
|
||||
[node name="Title" type="NinePatchRect" parent="."]
|
||||
custom_minimum_size = Vector2(500, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -250.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 44.0
|
||||
grow_horizontal = 2
|
||||
texture = ExtResource("1_pbd5q")
|
||||
region_rect = Rect2(1, 27, 86, 8)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 7
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Title" type="Label" parent="Title"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -34.5
|
||||
offset_top = -18.0
|
||||
offset_right = 34.5
|
||||
offset_bottom = 18.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 27
|
||||
text = "开发策略"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="Option" type="Control" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="Column_Headers" type="HBoxContainer" parent="Option"]
|
||||
custom_minimum_size = Vector2(420, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -210.0
|
||||
offset_top = 51.0
|
||||
offset_right = 210.0
|
||||
offset_bottom = 82.0
|
||||
grow_horizontal = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="Title" type="Label" parent="Option/Column_Headers"]
|
||||
custom_minimum_size = Vector2(320, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 22
|
||||
text = "开发方针"
|
||||
|
||||
[node name="Cost" type="Label" parent="Option/Column_Headers"]
|
||||
custom_minimum_size = Vector2(80, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 22
|
||||
text = "成本"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Options" type="NinePatchRect" parent="Option"]
|
||||
custom_minimum_size = Vector2(440, 170)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -220.0
|
||||
offset_top = -92.0
|
||||
offset_right = 220.0
|
||||
offset_bottom = 78.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("1_pbd5q")
|
||||
region_rect = Rect2(92, 38, 76, 34)
|
||||
patch_margin_left = 2
|
||||
patch_margin_top = 33
|
||||
patch_margin_right = 2
|
||||
patch_margin_bottom = 33
|
||||
|
||||
[node name="List_1" type="VBoxContainer" parent="Option/Options"]
|
||||
custom_minimum_size = Vector2(436, 160)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -210.0
|
||||
offset_top = -80.0
|
||||
offset_right = 210.0
|
||||
offset_bottom = 80.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="option_1" type="Button" parent="Option/Options/List_1"]
|
||||
custom_minimum_size = Vector2(0, 32)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("3_rq5uk")
|
||||
disabled = true
|
||||
flat = true
|
||||
|
||||
[node name="Row" type="HBoxContainer" parent="Option/Options/List_1/option_1"]
|
||||
custom_minimum_size = Vector2(420, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -210.0
|
||||
offset_top = -15.5
|
||||
offset_right = 210.0
|
||||
offset_bottom = 15.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="Title" type="Label" parent="Option/Options/List_1/option_1/Row"]
|
||||
custom_minimum_size = Vector2(300, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
text = "正常开发"
|
||||
|
||||
[node name="Cost" type="Label" parent="Option/Options/List_1/option_1/Row"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
text = "0"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="option_2" type="Button" parent="Option/Options/List_1"]
|
||||
custom_minimum_size = Vector2(0, 32)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("3_rq5uk")
|
||||
disabled = true
|
||||
flat = true
|
||||
|
||||
[node name="Row" type="HBoxContainer" parent="Option/Options/List_1/option_2"]
|
||||
custom_minimum_size = Vector2(420, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -210.0
|
||||
offset_top = -15.5
|
||||
offset_right = 210.0
|
||||
offset_bottom = 15.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="Title" type="Label" parent="Option/Options/List_1/option_2/Row"]
|
||||
custom_minimum_size = Vector2(300, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
|
||||
[node name="Cost" type="Label" parent="Option/Options/List_1/option_2/Row"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="option_3" type="Button" parent="Option/Options/List_1"]
|
||||
custom_minimum_size = Vector2(0, 32)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("3_rq5uk")
|
||||
disabled = true
|
||||
flat = true
|
||||
|
||||
[node name="Row" type="HBoxContainer" parent="Option/Options/List_1/option_3"]
|
||||
custom_minimum_size = Vector2(420, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -210.0
|
||||
offset_top = -15.5
|
||||
offset_right = 210.0
|
||||
offset_bottom = 15.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="Title" type="Label" parent="Option/Options/List_1/option_3/Row"]
|
||||
custom_minimum_size = Vector2(300, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
|
||||
[node name="Cost" type="Label" parent="Option/Options/List_1/option_3/Row"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="option_4" type="Button" parent="Option/Options/List_1"]
|
||||
custom_minimum_size = Vector2(0, 32)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("3_rq5uk")
|
||||
disabled = true
|
||||
flat = true
|
||||
|
||||
[node name="Row" type="HBoxContainer" parent="Option/Options/List_1/option_4"]
|
||||
custom_minimum_size = Vector2(420, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -210.0
|
||||
offset_top = -15.5
|
||||
offset_right = 210.0
|
||||
offset_bottom = 15.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="Title" type="Label" parent="Option/Options/List_1/option_4/Row"]
|
||||
custom_minimum_size = Vector2(300, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
|
||||
[node name="Cost" type="Label" parent="Option/Options/List_1/option_4/Row"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="option_5" type="Button" parent="Option/Options/List_1"]
|
||||
custom_minimum_size = Vector2(0, 32)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("3_rq5uk")
|
||||
disabled = true
|
||||
flat = true
|
||||
|
||||
[node name="Row" type="HBoxContainer" parent="Option/Options/List_1/option_5"]
|
||||
custom_minimum_size = Vector2(420, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -210.0
|
||||
offset_top = -15.5
|
||||
offset_right = 210.0
|
||||
offset_bottom = 15.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="Title" type="Label" parent="Option/Options/List_1/option_5/Row"]
|
||||
custom_minimum_size = Vector2(300, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
|
||||
[node name="Cost" type="Label" parent="Option/Options/List_1/option_5/Row"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Explaination" type="Label" parent="Option"]
|
||||
custom_minimum_size = Vector2(200, 60)
|
||||
layout_mode = 1
|
||||
anchors_preset = 2
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 47.0
|
||||
offset_top = -83.0
|
||||
offset_right = 358.0
|
||||
offset_bottom = -23.0
|
||||
grow_vertical = 0
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
text = "说明"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
autowrap_mode = 3
|
||||
|
||||
[node name="Human" type="TextureRect" parent="Option"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 3
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -128.0
|
||||
offset_top = -90.0
|
||||
offset_right = -55.0
|
||||
offset_bottom = -17.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 0
|
||||
texture = ExtResource("4_pbd5q")
|
||||
381
UI/popup/task_development_bak/task_development.gd
Normal file
381
UI/popup/task_development_bak/task_development.gd
Normal file
@ -0,0 +1,381 @@
|
||||
# task_development.gd
|
||||
extends Control
|
||||
|
||||
# --- 节点引用 ---
|
||||
@onready var confirm_button = $main_page/Confirm
|
||||
@onready var platform_button = $"main_page/Part_3/Select_List/1_right/Button"
|
||||
@onready var gameplay_button = $"main_page/Part_3/Select_List/2_right/Button"
|
||||
@onready var theme_button = $"main_page/Part_3/Select_List/3_right/Button"
|
||||
@onready var strategy_button = $"main_page/Part_3/Select_List/4_right/Button"
|
||||
@onready var budget_button = $"main_page/Part_2/HBoxContainer/Button"
|
||||
@onready var main_page = $main_page
|
||||
@onready var platform_popup = $platform
|
||||
@onready var gameplay_popup = $gameplay
|
||||
@onready var theme_popup = $theme
|
||||
@onready var strategy_popup = $strategy
|
||||
@onready var product_focus = $product_focus
|
||||
@onready var dialogue: Control = $dialogue
|
||||
|
||||
# --- 内部状态 ---
|
||||
var pop_up_list: Array = [] # 记录打开的UI弹出窗口
|
||||
var node_name: String
|
||||
var is_active: bool = false
|
||||
|
||||
# 存储用户在当前配置过程中的临时选择 (使用中文 Key)
|
||||
var task_info: Dictionary = {
|
||||
"平台": "",
|
||||
"玩法": "",
|
||||
"题材": "",
|
||||
"开发策略": "",
|
||||
"预算": 0,
|
||||
"产品侧重点": {},
|
||||
"关键环节负责人": [] # <--- 新增并初始化为空数组
|
||||
}
|
||||
|
||||
# --- 初始化 ---
|
||||
func _ready() -> void:
|
||||
node_name = str(self.name)
|
||||
add_to_group(node_name) # 用于 UI_MAIN 查找
|
||||
main_page.hide()
|
||||
# 连接信号
|
||||
confirm_button.pressed.connect(_on_confirm_button_pressed)
|
||||
platform_button.pressed.connect(_on_category_button_pressed.bind(platform_popup))
|
||||
gameplay_button.pressed.connect(_on_category_button_pressed.bind(gameplay_popup))
|
||||
theme_button.pressed.connect(_on_category_button_pressed.bind(theme_popup))
|
||||
strategy_button.pressed.connect(_on_category_button_pressed.bind(strategy_popup))
|
||||
|
||||
# 注意:不再需要加载静态数据
|
||||
|
||||
# --- 核心显示与关闭逻辑 ---
|
||||
func show_up():
|
||||
if GameState.is_on_task_status():
|
||||
self.visible = true
|
||||
show_dialogue("正在进行其它项目","")
|
||||
return
|
||||
|
||||
print(node_name + ": Showing up.")
|
||||
|
||||
# 1. 设置界面状态
|
||||
main_page.show()
|
||||
self.visible = true
|
||||
is_active = true
|
||||
pop_up_list.clear()
|
||||
pop_up_list.append(self)
|
||||
|
||||
# 2. 设置默认选项 (从 GameState 读取)
|
||||
_set_default_selections()
|
||||
|
||||
# 3. 更新按钮文本和预算 (基于默认选项)
|
||||
update_button_texts()
|
||||
calculate_and_update_budget() # 初始计算预算
|
||||
|
||||
# 4. 暂停游戏并处理输入
|
||||
GameState.pause_game()
|
||||
set_process_input(true)
|
||||
|
||||
func close_all_popups():
|
||||
print(node_name + ": Closing all popups...")
|
||||
while not pop_up_list.is_empty():
|
||||
var popup = pop_up_list.pop_back()
|
||||
if popup and is_instance_valid(popup):
|
||||
popup.visible = false
|
||||
self.visible = false
|
||||
is_active = false
|
||||
if GameState: GameState.resume_game() # 假设 GameState 有此方法
|
||||
set_process_input(false)
|
||||
|
||||
# --- 数据初始化 (从 GameState 设置默认值) ---
|
||||
|
||||
# 根据 GameState 设置默认选项
|
||||
func _set_default_selections() -> void:
|
||||
if not GameState:
|
||||
printerr(node_name + ": GameState not available during _set_default_selections.")
|
||||
# 将所有选项设置为空,让用户必须选择
|
||||
task_info["平台"] = ""
|
||||
task_info["玩法"] = ""
|
||||
task_info["题材"] = ""
|
||||
task_info["开发策略"] = ""
|
||||
return
|
||||
|
||||
var task_dev_data = GameState.get_value("task_development", {})
|
||||
if task_dev_data.is_empty():
|
||||
printerr(node_name + ": Failed to get 'task_development' data from GameState during _set_default_selections.")
|
||||
# 将所有选项设置为空
|
||||
task_info["平台"] = ""
|
||||
task_info["玩法"] = ""
|
||||
task_info["题材"] = ""
|
||||
task_info["开发策略"] = ""
|
||||
return
|
||||
|
||||
# 定义 GameState 中的 Key 和 task_info 中的 Key 的映射
|
||||
var categories_map = {
|
||||
"平台": "platforms",
|
||||
"玩法": "gameplays",
|
||||
"题材": "themes",
|
||||
"开发策略": "strategies"
|
||||
}
|
||||
|
||||
# 为每个类别查找第一个启用的选项
|
||||
for task_key in categories_map:
|
||||
var gamestate_key = categories_map[task_key]
|
||||
var items_data = task_dev_data.get(gamestate_key, {})
|
||||
var default_item_key = _find_first_enabled_key_in_gamestate(items_data)
|
||||
task_info[task_key] = default_item_key # 如果没找到,会是 ""
|
||||
if default_item_key.is_empty():
|
||||
print(node_name + ": No enabled default found for category '%s'." % task_key)
|
||||
|
||||
print(node_name + ": Default selections set from GameState: ", task_info)
|
||||
|
||||
# 辅助函数:在 GameState 的某个类别数据中查找第一个 enabled 的 key (中文名称)
|
||||
func _find_first_enabled_key_in_gamestate(items_data: Dictionary) -> String:
|
||||
if items_data.is_empty():
|
||||
return ""
|
||||
|
||||
# 尝试按某种顺序查找,如果字典是无序的,结果可能不固定
|
||||
# 如果需要固定顺序,可能需要在 GameState 中存储时就排序或提供顺序信息
|
||||
for item_key in items_data:
|
||||
var item_details = items_data[item_key]
|
||||
if typeof(item_details) == TYPE_DICTIONARY and item_details.get("enabled", false) == true:
|
||||
return item_key # 返回第一个找到的 enabled key (中文名称)
|
||||
|
||||
# 如果没有找到 enabled 的
|
||||
return ""
|
||||
|
||||
# --- 预算计算与 UI 更新 ---
|
||||
|
||||
# 计算并更新预算显示 (完全基于 GameState 数据)
|
||||
func calculate_and_update_budget() -> void:
|
||||
if not GameState:
|
||||
printerr(node_name + ": Cannot calculate budget, GameState not available.")
|
||||
task_info["预算"] = 0
|
||||
if budget_button: budget_button.text = "错误"
|
||||
return
|
||||
|
||||
var task_dev_data = GameState.get_value("task_development", {})
|
||||
if task_dev_data.is_empty():
|
||||
printerr(node_name + ": Cannot calculate budget, 'task_development' data not found in GameState.")
|
||||
task_info["预算"] = 0
|
||||
if budget_button: budget_button.text = "错误"
|
||||
return
|
||||
|
||||
var platform_cost: float = 0.0
|
||||
var gameplay_cost: float = 0.0
|
||||
var theme_cost: float = 0.0
|
||||
var strategy_multiplier: float = 0.0 # 策略的 "Cost" 是乘数因子
|
||||
|
||||
# 1. 获取平台成本
|
||||
var platform_key = task_info["平台"]
|
||||
if not platform_key.is_empty():
|
||||
var platform_data = task_dev_data.get("platforms", {}).get(platform_key, {})
|
||||
platform_cost = platform_data.get("Cost", 0.0)
|
||||
else:
|
||||
print(node_name + ": Platform not selected, cost is 0.")
|
||||
|
||||
# 2. 获取玩法成本
|
||||
var gameplay_key = task_info["玩法"]
|
||||
if not gameplay_key.is_empty():
|
||||
var gameplay_data = task_dev_data.get("gameplays", {}).get(gameplay_key, {})
|
||||
gameplay_cost = gameplay_data.get("Cost", 0.0)
|
||||
else:
|
||||
print(node_name + ": Gameplay not selected, cost is 0.")
|
||||
|
||||
# 3. 获取题材成本
|
||||
var theme_key = task_info["题材"]
|
||||
if not theme_key.is_empty():
|
||||
var theme_data = task_dev_data.get("themes", {}).get(theme_key, {})
|
||||
theme_cost = theme_data.get("Cost", 0.0)
|
||||
else:
|
||||
print(node_name + ": Theme not selected, cost is 0.")
|
||||
|
||||
# 4. 获取策略成本乘数
|
||||
var strategy_key = task_info["开发策略"]
|
||||
if not strategy_key.is_empty():
|
||||
var strategy_data = task_dev_data.get("strategies", {}).get(strategy_key, {})
|
||||
# 假设策略的 "Cost" 字段存储的是成本增加的百分比 (例如 0.2 代表增加 20%)
|
||||
strategy_multiplier = strategy_data.get("Cost", 0.0)
|
||||
else:
|
||||
print(node_name + ": Strategy not selected, multiplier is 0.")
|
||||
|
||||
# 计算总预算: (平台 + 玩法 + 题材) * (1 + 策略乘数)
|
||||
var base_cost = platform_cost + gameplay_cost + theme_cost
|
||||
var calculated_budget = int(base_cost * (1.0 + strategy_multiplier)) # 结果取整
|
||||
task_info["预算"] = calculated_budget
|
||||
|
||||
# 更新预算显示
|
||||
if budget_button:
|
||||
budget_button.text = str(calculated_budget)
|
||||
# print(node_name + ": Budget updated to " + str(calculated_budget)) # Debug
|
||||
else:
|
||||
printerr(node_name + ": Budget button not found when updating budget.")
|
||||
|
||||
# 更新所有主界面按钮文本 (直接使用 task_info 中的中文 Key)
|
||||
func update_button_texts() -> void:
|
||||
var placeholder_text = "请选择" # 如果未选择,显示的文本
|
||||
|
||||
platform_button.text = task_info["平台"] if not task_info["平台"].is_empty() else placeholder_text
|
||||
gameplay_button.text = task_info["玩法"] if not task_info["玩法"].is_empty() else placeholder_text
|
||||
theme_button.text = task_info["题材"] if not task_info["题材"].is_empty() else placeholder_text
|
||||
strategy_button.text = task_info["开发策略"] if not task_info["开发策略"].is_empty() else placeholder_text
|
||||
|
||||
# --- 子窗口交互与数据更新 ---
|
||||
|
||||
# 提供给子节点调用的接口,用于启动此节点内的对话框
|
||||
# dialogues: String 或 PackedStringArray - 要显示的对话内容
|
||||
# next_node: Control (可选) - 对话结束后要显示的下一个UI节点
|
||||
func show_dialogue(dialogues, next_node_name: String = "") -> void:
|
||||
if not is_instance_valid(dialogue):
|
||||
printerr(node_name + ": Dialogue node is not valid or ready.")
|
||||
return
|
||||
|
||||
if not dialogue.has_method("_start"):
|
||||
printerr(node_name + ": Dialogue node does not have a _start method.")
|
||||
return
|
||||
|
||||
print(node_name + ": Requesting to show dialogue with content: ", dialogues)
|
||||
# 调用 dialogue 节点的 _start 方法来显示对话框
|
||||
# 注意:这里假设 dialogue 节点的 _start 方法会处理好显示、暂停游戏等逻辑
|
||||
var next_node = get_node_or_null(next_node_name)
|
||||
dialogue._start(dialogues, next_node)
|
||||
|
||||
# 可选:如果希望对话框显示时,task_development 的其他部分(如 main_page 或子弹窗)隐藏,
|
||||
# 可以在这里添加隐藏逻辑,但这取决于具体交互需求。
|
||||
# 例如:
|
||||
# if main_page.visible: main_page.hide()
|
||||
# if not pop_up_list.is_empty() and pop_up_list[-1] != self and is_instance_valid(pop_up_list[-1]):
|
||||
# pop_up_list[-1].hide() # 隐藏最上层的子弹窗
|
||||
|
||||
|
||||
# 处理分类按钮点击的通用函数
|
||||
func _on_category_button_pressed(popup_node: Control) -> void:
|
||||
if not is_instance_valid(popup_node):
|
||||
printerr(node_name + ": Invalid popup node provided for category button.")
|
||||
return
|
||||
if not GameState:
|
||||
printerr(node_name + ": Cannot open popup, GameState not available.")
|
||||
return
|
||||
|
||||
# 子窗口现在自行从 GameState 加载数据,无需父窗口传递
|
||||
# 只需要显示对应的弹窗即可
|
||||
|
||||
# --- 确保子窗口在显示时会刷新其内容 ---
|
||||
# 最好在子窗口的 _on_visibility_changed 或类似方法中处理数据加载
|
||||
# 如果子窗口没有这个逻辑,可以在这里强制调用一下(如果它们有 reset_display 方法)
|
||||
if popup_node.has_method("reset_display"):
|
||||
popup_node.reset_display()
|
||||
elif popup_node.has_method("_on_visibility_changed"): # 备选方案
|
||||
# 注意:直接调用 _on_visibility_changed 可能不符合预期,因为它通常由引擎触发
|
||||
# 更好的方式是确保子窗口的 _ready 或 visibility_changed 信号连接正确并处理加载
|
||||
pass
|
||||
|
||||
main_page.hide()
|
||||
popup_node.show() # 显示弹窗
|
||||
pop_up_list.append(popup_node)
|
||||
print(node_name + ": Showing category popup: ", popup_node.name)
|
||||
|
||||
|
||||
# 提供给子弹出窗口调用的接口函数,用于更新选择
|
||||
# options: 字典,包含更新的类别和对应的 Key
|
||||
func update_task_options(options: Dictionary) -> void:
|
||||
var updated = false
|
||||
for key in options:
|
||||
var new_value = options[key]
|
||||
|
||||
if key == "关键环节负责人":
|
||||
# --- 特殊处理 "关键环节负责人" ---
|
||||
if not task_info.has(key) or not typeof(task_info[key]) == TYPE_ARRAY:
|
||||
task_info[key] = [] # 如果不存在或类型不对,则初始化为空数组
|
||||
|
||||
if not new_value in task_info[key]: # 避免重复添加 (可选,根据需求)
|
||||
task_info[key].append(new_value)
|
||||
updated = true
|
||||
print(node_name + ": Appended '%s' to '%s'. Current: %s" % [new_value, key, task_info[key]])
|
||||
else:
|
||||
print(node_name + ": '%s' already in '%s'. No change." % [new_value, key])
|
||||
|
||||
elif task_info.has(key):
|
||||
# --- 原有逻辑处理其他普通键值对 ---
|
||||
if task_info[key] != new_value:
|
||||
task_info[key] = new_value
|
||||
updated = true
|
||||
print(node_name + ": Option '%s' updated to '%s'." % [key, new_value])
|
||||
else:
|
||||
printerr(node_name + ": Invalid key '%s' provided in update_task_options and not handled as a special case." % key)
|
||||
|
||||
if updated:
|
||||
# 对于 "关键环节负责人" 的更新,通常不需要更新按钮文本或重新计算预算
|
||||
# 但如果其他选项更新了,则需要执行
|
||||
if not (options.has("关键环节负责人") and options.size() == 1): # 如果不仅仅是更新负责人
|
||||
update_button_texts()
|
||||
calculate_and_update_budget()
|
||||
|
||||
print(node_name + ": Task info updated: ", task_info)
|
||||
|
||||
# 处理子弹出窗口确认后关闭并返回主页面的逻辑
|
||||
func _close_child_popup_and_return(child_popup_node: Control) -> void:
|
||||
if not is_instance_valid(child_popup_node):
|
||||
printerr(node_name + ": Invalid child popup node passed.")
|
||||
return
|
||||
|
||||
print(node_name + ": Request received to close child popup '%s' and return." % child_popup_node.name)
|
||||
|
||||
if child_popup_node in pop_up_list:
|
||||
pop_up_list.erase(child_popup_node)
|
||||
else:
|
||||
printerr(node_name + ": Child popup '%s' was not found in pop_up_list during close request." % child_popup_node.name)
|
||||
|
||||
child_popup_node.hide()
|
||||
main_page.show()
|
||||
print(node_name + ": Hid child popup '%s' and showed main_page." % child_popup_node.name)
|
||||
|
||||
|
||||
# --- 输入处理 ---
|
||||
# (保持不变)
|
||||
func _input(event):
|
||||
if not is_active: return
|
||||
|
||||
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT and event.is_pressed():
|
||||
if pop_up_list.size() > 0:
|
||||
var last_popup = pop_up_list.pop_back()
|
||||
if last_popup and is_instance_valid(last_popup):
|
||||
if last_popup != self:
|
||||
last_popup.visible = false
|
||||
print(node_name + ": Closed popup via right-click: ", last_popup.name)
|
||||
# 检查是否需要重显主页面
|
||||
if not pop_up_list.is_empty() and pop_up_list[-1] == self and not main_page.visible:
|
||||
main_page.show()
|
||||
print(node_name + ": Re-showing main_page after closing sub-popup.")
|
||||
get_viewport().set_input_as_handled()
|
||||
else:
|
||||
# 在主界面右键点击,关闭整个界面
|
||||
print(node_name + ": Right-click on main page. Closing task_development.")
|
||||
pop_up_list.append(last_popup) # 把 self 放回去,让下面的判断处理关闭
|
||||
|
||||
# 如果列表为空(或只剩 self 且刚刚弹出的是 self),则关闭所有
|
||||
if pop_up_list.is_empty() or (pop_up_list.size() == 1 and pop_up_list[0] == self and last_popup == self):
|
||||
print(node_name + ": Closing task_development due to right-click logic.")
|
||||
close_all_popups()
|
||||
# 不需要 set_input_as_handled,因为界面关闭了
|
||||
|
||||
# --- 确认与后续流程 ---
|
||||
func _on_confirm_button_pressed():
|
||||
print(node_name + ": Confirmed with task_info: ", task_info)
|
||||
# 检查是否所有选项都已选择 (Key 不为空)
|
||||
if task_info["平台"].is_empty() or \
|
||||
task_info["玩法"].is_empty() or \
|
||||
task_info["题材"].is_empty() or \
|
||||
task_info["开发策略"].is_empty():
|
||||
printerr(node_name + ": Cannot confirm, not all options are selected.")
|
||||
# 此处可以添加用户提示
|
||||
var ui_main = get_tree().get_first_node_in_group("UI_MAIN")
|
||||
if ui_main and ui_main.has_method("show_notification"):
|
||||
ui_main.show_notification("请确保所有开发选项都已选择!")
|
||||
return
|
||||
|
||||
# --- 触发后续流程 ---
|
||||
product_focus.show()
|
||||
main_page.hide()
|
||||
|
||||
# 发出开始任务的信号
|
||||
func start_task():
|
||||
print(node_name + ": start task with info: ", task_info)
|
||||
GameState.set_system_status_value("is_on_task", true)
|
||||
1
UI/popup/task_development_bak/task_development.gd.uid
Normal file
1
UI/popup/task_development_bak/task_development.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://chgujg3vq0jbl
|
||||
548
UI/popup/task_development_bak/task_development.tscn
Normal file
548
UI/popup/task_development_bak/task_development.tscn
Normal file
@ -0,0 +1,548 @@
|
||||
[gd_scene load_steps=33 format=3 uid="uid://b4ll7wwg1s0qc"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://pucudatqrcrq" path="res://UI/popup/popup_bg_1.png" id="1_57348"]
|
||||
[ext_resource type="Script" uid="uid://chgujg3vq0jbl" path="res://UI/popup/task_development_bak/task_development.gd" id="1_v0qi7"]
|
||||
[ext_resource type="Texture2D" uid="uid://bk8155f5le6k4" path="res://UI/main/icon_money.png" id="3_lcrvn"]
|
||||
[ext_resource type="Theme" uid="uid://bau80ps6kx783" path="res://UI/tres/Bottom_Info_button_theme.tres" id="4_sqys5"]
|
||||
[ext_resource type="LabelSettings" uid="uid://cvwpqds25xnfs" path="res://UI/tres/ui_main_label_number.tres" id="4_xtl2p"]
|
||||
[ext_resource type="FontFile" uid="uid://egugs822n8gr" path="res://UI/font/AlimamaFangYuanTiVF-Thin.ttf" id="5_qrj6y"]
|
||||
[ext_resource type="PackedScene" uid="uid://blv6i6w651pcs" path="res://UI/popup/task_development_bak/platform/platform.tscn" id="6_eatmm"]
|
||||
[ext_resource type="PackedScene" uid="uid://c7brdhj8ybu1y" path="res://UI/popup/task_development_bak/gameplay/gameplay.tscn" id="7_xfbvu"]
|
||||
[ext_resource type="PackedScene" uid="uid://bej6f0cqirn4j" path="res://UI/popup/task_development_bak/theme/theme.tscn" id="8_nckjb"]
|
||||
[ext_resource type="PackedScene" uid="uid://ctcbxvgljrkvi" path="res://UI/popup/task_development_bak/strategy/strategy.tscn" id="9_6r1e0"]
|
||||
[ext_resource type="PackedScene" uid="uid://dpshanwm4o3by" path="res://UI/popup/task_development_bak/product_focus/product_focus.tscn" id="10_at31c"]
|
||||
[ext_resource type="PackedScene" uid="uid://be000l53jxash" path="res://UI/popup/task_development_bak/key_output/proposal.tscn" id="12_v0qi7"]
|
||||
[ext_resource type="PackedScene" uid="uid://dtywh0m5odikx" path="res://UI/popup/dialogue.tscn" id="13_kctqw"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_xtl2p"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_sqys5"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ts1uk"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ka0mh"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_4dqyo"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_k5x0l"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_rl8fy"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ka0mh"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_sqys5"]
|
||||
bg_color = Color(0.639216, 0.639216, 0.639216, 1)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_4dqyo"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ln7qd"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_iashq"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_kfl1n"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_20m4o"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_rl25l"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_tndxe"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_xx8ge"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ep6fu"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ci4su"]
|
||||
|
||||
[node name="task_development" type="Control"]
|
||||
custom_minimum_size = Vector2(1000, 600)
|
||||
layout_mode = 3
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -500.0
|
||||
offset_top = -300.0
|
||||
offset_right = 500.0
|
||||
offset_bottom = 300.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_v0qi7")
|
||||
|
||||
[node name="main_page" type="NinePatchRect" parent="."]
|
||||
custom_minimum_size = Vector2(500, 350)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -250.0
|
||||
offset_top = -175.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 175.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("1_57348")
|
||||
region_rect = Rect2(1, 35, 86, 53)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 35
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 32
|
||||
|
||||
[node name="Part_1" type="NinePatchRect" parent="main_page"]
|
||||
custom_minimum_size = Vector2(500, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -250.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 44.0
|
||||
grow_horizontal = 2
|
||||
texture = ExtResource("1_57348")
|
||||
region_rect = Rect2(1, 27, 86, 8)
|
||||
patch_margin_left = 8
|
||||
patch_margin_top = 7
|
||||
patch_margin_right = 8
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Title" type="Label" parent="main_page/Part_1"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -34.5
|
||||
offset_top = -18.0
|
||||
offset_right = 34.5
|
||||
offset_bottom = 18.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 27
|
||||
text = "新项目"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="Part_2" type="Control" parent="main_page"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -20.0
|
||||
offset_top = 34.0
|
||||
offset_right = 20.0
|
||||
offset_bottom = 53.0
|
||||
grow_horizontal = 2
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="main_page/Part_2"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -24.0
|
||||
offset_top = 5.0
|
||||
offset_right = 208.0
|
||||
offset_bottom = 39.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="Label" type="Label" parent="main_page/Part_2/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 24
|
||||
text = "预算"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Button" type="Button" parent="main_page/Part_2/HBoxContainer"]
|
||||
custom_minimum_size = Vector2(180, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_disabled_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_hover_pressed_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_hover_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_focus_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_pressed_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_xtl2p")
|
||||
theme_override_styles/disabled = SubResource("StyleBoxEmpty_sqys5")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxEmpty_ts1uk")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_ka0mh")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_4dqyo")
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_k5x0l")
|
||||
text = "500"
|
||||
icon = ExtResource("3_lcrvn")
|
||||
flat = true
|
||||
alignment = 2
|
||||
icon_alignment = 2
|
||||
|
||||
[node name="Part_3" type="NinePatchRect" parent="main_page"]
|
||||
custom_minimum_size = Vector2(440, 200)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -220.0
|
||||
offset_top = -91.0
|
||||
offset_right = 220.0
|
||||
offset_bottom = 131.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("1_57348")
|
||||
region_rect = Rect2(92, 38, 76, 34)
|
||||
patch_margin_left = 2
|
||||
patch_margin_top = 33
|
||||
patch_margin_right = 2
|
||||
patch_margin_bottom = 33
|
||||
|
||||
[node name="BG" type="NinePatchRect" parent="main_page/Part_3"]
|
||||
custom_minimum_size = Vector2(440, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 7
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -220.0
|
||||
offset_top = -127.0
|
||||
offset_right = 220.0
|
||||
offset_bottom = 2.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
texture = ExtResource("1_57348")
|
||||
region_rect = Rect2(100, 95, 240, 75)
|
||||
|
||||
[node name="Select_List" type="GridContainer" parent="main_page/Part_3"]
|
||||
custom_minimum_size = Vector2(320, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -180.0
|
||||
offset_top = 7.0
|
||||
offset_right = 180.0
|
||||
offset_bottom = 179.0
|
||||
grow_horizontal = 2
|
||||
size_flags_horizontal = 4
|
||||
theme_override_constants/h_separation = 0
|
||||
columns = 2
|
||||
|
||||
[node name="1_left" type="NinePatchRect" parent="main_page/Part_3/Select_List"]
|
||||
custom_minimum_size = Vector2(140, 40)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
texture = ExtResource("1_57348")
|
||||
region_rect = Rect2(1, 95, 36, 24)
|
||||
patch_margin_left = 7
|
||||
patch_margin_top = 6
|
||||
patch_margin_right = 2
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Label" type="Label" parent="main_page/Part_3/Select_List/1_left"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -60.0
|
||||
offset_top = -12.0
|
||||
offset_right = 60.0
|
||||
offset_bottom = 24.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
text = "平台"
|
||||
label_settings = ExtResource("4_xtl2p")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="1_right" type="NinePatchRect" parent="main_page/Part_3/Select_List"]
|
||||
custom_minimum_size = Vector2(220, 40)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
texture = ExtResource("1_57348")
|
||||
region_rect = Rect2(38, 95, 50, 24)
|
||||
patch_margin_top = 6
|
||||
patch_margin_right = 6
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Button" type="Button" parent="main_page/Part_3/Select_List/1_right"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -70.0
|
||||
offset_top = -17.5
|
||||
offset_right = 70.0
|
||||
offset_bottom = 17.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_focus_color = Color(0, 0, 0, 1)
|
||||
theme_override_fonts/font = ExtResource("5_qrj6y")
|
||||
theme_override_font_sizes/font_size = 18
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_rl8fy")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxFlat_ka0mh")
|
||||
theme_override_styles/hover = SubResource("StyleBoxFlat_sqys5")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxFlat_4dqyo")
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_ln7qd")
|
||||
text = "Steam & Epic"
|
||||
|
||||
[node name="2_left" type="NinePatchRect" parent="main_page/Part_3/Select_List"]
|
||||
custom_minimum_size = Vector2(140, 40)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
texture = ExtResource("1_57348")
|
||||
region_rect = Rect2(1, 95, 36, 24)
|
||||
patch_margin_left = 7
|
||||
patch_margin_top = 6
|
||||
patch_margin_right = 2
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Label" type="Label" parent="main_page/Part_3/Select_List/2_left"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -60.0
|
||||
offset_top = -12.0
|
||||
offset_right = 60.0
|
||||
offset_bottom = 24.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
text = "玩法"
|
||||
label_settings = ExtResource("4_xtl2p")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="2_right" type="NinePatchRect" parent="main_page/Part_3/Select_List"]
|
||||
custom_minimum_size = Vector2(220, 40)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
texture = ExtResource("1_57348")
|
||||
region_rect = Rect2(38, 95, 50, 24)
|
||||
patch_margin_top = 6
|
||||
patch_margin_right = 6
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Button" type="Button" parent="main_page/Part_3/Select_List/2_right"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -70.0
|
||||
offset_top = -17.5
|
||||
offset_right = 70.0
|
||||
offset_bottom = 17.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_focus_color = Color(0, 0, 0, 1)
|
||||
theme_override_fonts/font = ExtResource("5_qrj6y")
|
||||
theme_override_font_sizes/font_size = 18
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_iashq")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxFlat_ka0mh")
|
||||
theme_override_styles/hover = SubResource("StyleBoxFlat_sqys5")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxFlat_4dqyo")
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_ln7qd")
|
||||
text = "休闲放置"
|
||||
|
||||
[node name="3_left" type="NinePatchRect" parent="main_page/Part_3/Select_List"]
|
||||
custom_minimum_size = Vector2(140, 40)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
texture = ExtResource("1_57348")
|
||||
region_rect = Rect2(1, 95, 36, 24)
|
||||
patch_margin_left = 7
|
||||
patch_margin_top = 6
|
||||
patch_margin_right = 2
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Label" type="Label" parent="main_page/Part_3/Select_List/3_left"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -60.0
|
||||
offset_top = -12.0
|
||||
offset_right = 60.0
|
||||
offset_bottom = 24.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
text = "题材"
|
||||
label_settings = ExtResource("4_xtl2p")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="3_right" type="NinePatchRect" parent="main_page/Part_3/Select_List"]
|
||||
custom_minimum_size = Vector2(220, 40)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
texture = ExtResource("1_57348")
|
||||
region_rect = Rect2(38, 95, 50, 24)
|
||||
patch_margin_top = 6
|
||||
patch_margin_right = 6
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Button" type="Button" parent="main_page/Part_3/Select_List/3_right"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -70.0
|
||||
offset_top = -17.5
|
||||
offset_right = 70.0
|
||||
offset_bottom = 17.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_focus_color = Color(0, 0, 0, 1)
|
||||
theme_override_fonts/font = ExtResource("5_qrj6y")
|
||||
theme_override_font_sizes/font_size = 18
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_kfl1n")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxFlat_ka0mh")
|
||||
theme_override_styles/hover = SubResource("StyleBoxFlat_sqys5")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxFlat_4dqyo")
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_ln7qd")
|
||||
text = "古装仙侠"
|
||||
|
||||
[node name="4_left" type="NinePatchRect" parent="main_page/Part_3/Select_List"]
|
||||
custom_minimum_size = Vector2(140, 40)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
texture = ExtResource("1_57348")
|
||||
region_rect = Rect2(1, 95, 36, 24)
|
||||
patch_margin_left = 7
|
||||
patch_margin_top = 6
|
||||
patch_margin_right = 2
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Label" type="Label" parent="main_page/Part_3/Select_List/4_left"]
|
||||
custom_minimum_size = Vector2(120, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -60.0
|
||||
offset_top = -12.0
|
||||
offset_right = 60.0
|
||||
offset_bottom = 24.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
text = "开发策略"
|
||||
label_settings = ExtResource("4_xtl2p")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="4_right" type="NinePatchRect" parent="main_page/Part_3/Select_List"]
|
||||
custom_minimum_size = Vector2(220, 40)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
texture = ExtResource("1_57348")
|
||||
region_rect = Rect2(38, 95, 50, 24)
|
||||
patch_margin_top = 6
|
||||
patch_margin_right = 6
|
||||
patch_margin_bottom = 6
|
||||
|
||||
[node name="Button" type="Button" parent="main_page/Part_3/Select_List/4_right"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -70.0
|
||||
offset_top = -17.5
|
||||
offset_right = 70.0
|
||||
offset_bottom = 17.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_focus_color = Color(0, 0, 0, 1)
|
||||
theme_override_fonts/font = ExtResource("5_qrj6y")
|
||||
theme_override_font_sizes/font_size = 18
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_20m4o")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxFlat_ka0mh")
|
||||
theme_override_styles/hover = SubResource("StyleBoxFlat_sqys5")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxFlat_4dqyo")
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_ln7qd")
|
||||
text = "普通开发"
|
||||
|
||||
[node name="Confirm" type="Button" parent="main_page"]
|
||||
custom_minimum_size = Vector2(70, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -25.0
|
||||
offset_top = 131.0
|
||||
offset_right = 25.0
|
||||
offset_bottom = 174.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme = ExtResource("4_sqys5")
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_focus_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 23
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_rl25l")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxFlat_tndxe")
|
||||
theme_override_styles/hover = SubResource("StyleBoxFlat_xx8ge")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_ep6fu")
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_ci4su")
|
||||
text = "确定"
|
||||
|
||||
[node name="platform" parent="." instance=ExtResource("6_eatmm")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
|
||||
[node name="gameplay" parent="." instance=ExtResource("7_xfbvu")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
|
||||
[node name="theme" parent="." instance=ExtResource("8_nckjb")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
|
||||
[node name="strategy" parent="." instance=ExtResource("9_6r1e0")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
|
||||
[node name="product_focus" parent="." instance=ExtResource("10_at31c")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
|
||||
[node name="proposal" parent="." instance=ExtResource("12_v0qi7")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
|
||||
[node name="dialogue" parent="." instance=ExtResource("13_kctqw")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
BIN
UI/popup/task_development_bak/task_general.png
Normal file
BIN
UI/popup/task_development_bak/task_general.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 99 KiB |
34
UI/popup/task_development_bak/task_general.png.import
Normal file
34
UI/popup/task_development_bak/task_general.png.import
Normal file
@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://ihwg8cc3h6ar"
|
||||
path="res://.godot/imported/task_general.png-f911aa653606ea793cc4d95ffef10b5d.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://UI/popup/task_development_bak/task_general.png"
|
||||
dest_files=["res://.godot/imported/task_general.png-f911aa653606ea793cc4d95ffef10b5d.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
369
UI/popup/task_development_bak/theme/theme.gd
Normal file
369
UI/popup/task_development_bak/theme/theme.gd
Normal file
@ -0,0 +1,369 @@
|
||||
# theme.gd (更新版 - 对齐 gameplay.gd 逻辑)
|
||||
extends NinePatchRect
|
||||
|
||||
# UI Node References
|
||||
@onready var list_container = $Option/Info
|
||||
@onready var previous_button = $Title/previous/Button
|
||||
@onready var next_button = $Title/next/Button
|
||||
@onready var title_label = $Title/Title
|
||||
|
||||
# Configuration
|
||||
var items_per_page: int = 7 # 每页显示的选项数量 (保持与原 theme.gd 一致)
|
||||
|
||||
# Data Storage
|
||||
var theme_list_nodes: Array[VBoxContainer] = [] # 存储 List_1, List_2 等节点
|
||||
var option_nodes_per_list: Array = [] # 存储每个 List 对应的 option_X 按钮数组
|
||||
var all_enabled_themes: Array = [] # 存储筛选后的题材数据 { "name": String, "data": Dictionary }
|
||||
|
||||
# State
|
||||
var total_pages: int = 0
|
||||
var current_page_index: int = 0
|
||||
var selected_theme_key: String = "" # 当前逻辑上选中的项的 Key (用于确认)
|
||||
var currently_selected_button: Button = null # 当前高亮/聚焦的按钮节点引用
|
||||
var initial_key_to_highlight: String = "" # 弹窗打开时需要高亮的 Key (由父节点设置)
|
||||
|
||||
func _ready():
|
||||
# 1. 获取 List 节点 (与原版 theme.gd 类似,但使用 gameplay.gd 的错误处理)
|
||||
for i in range(1, 7): # 假设最多有 List_6 (与原 theme.gd 匹配)
|
||||
var list_node = list_container.get_node_or_null("List_" + str(i))
|
||||
if list_node:
|
||||
theme_list_nodes.append(list_node)
|
||||
else:
|
||||
break # 假设 List 节点是连续的
|
||||
|
||||
if theme_list_nodes.is_empty():
|
||||
printerr("错误:在 theme.tscn 中未找到 List 节点!无法显示选项。")
|
||||
set_process(false) # 禁用处理,因为没有UI元素
|
||||
return
|
||||
|
||||
# 2. 获取每个 List 内的 Option 节点 (与原版 theme.gd 类似)
|
||||
for list_node in theme_list_nodes:
|
||||
var current_list_options: Array = []
|
||||
for i in range(1, items_per_page + 1):
|
||||
var option_node = list_node.get_node_or_null("option_" + str(i))
|
||||
if option_node and option_node is Button:
|
||||
current_list_options.append(option_node)
|
||||
else:
|
||||
# 使用 gameplay.gd 的警告格式
|
||||
push_warning("警告:在 %s 中未能找到 option_%d 按钮" % [list_node.name, i])
|
||||
option_nodes_per_list.append(current_list_options)
|
||||
|
||||
# 3. 连接按钮信号 (与 gameplay.gd 一致)
|
||||
if previous_button:
|
||||
if not previous_button.pressed.is_connected(_on_previous_pressed):
|
||||
previous_button.pressed.connect(_on_previous_pressed)
|
||||
else: printerr("错误:在 theme.tscn 中未找到 Previous 按钮")
|
||||
|
||||
if next_button:
|
||||
if not next_button.pressed.is_connected(_on_next_pressed):
|
||||
next_button.pressed.connect(_on_next_pressed)
|
||||
else: printerr("错误:在 theme.tscn 中未找到 Next 按钮")
|
||||
|
||||
# 4. 连接 visibility_changed 信号 (与 gameplay.gd 一致)
|
||||
if not is_connected("visibility_changed", _on_visibility_changed):
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
|
||||
# 5. 移除 _ready 中的初始数据加载和显示更新
|
||||
# 这些逻辑现在完全由 _on_visibility_changed -> reset_display 处理
|
||||
|
||||
# --- Visibility Change Handler (与 gameplay.gd 一致) ---
|
||||
func _on_visibility_changed():
|
||||
if is_visible_in_tree():
|
||||
print("Theme: 弹窗变为可见,调用 reset_display()")
|
||||
reset_display() # 当变为可见时调用 reset
|
||||
# else: # 可选:隐藏时的清理逻辑
|
||||
# print("Theme: 弹窗变为隐藏。")
|
||||
|
||||
# --- 新增:用于父节点设置初始选中项 (与 gameplay.gd 一致) ---
|
||||
func set_initial_selection(key: String):
|
||||
"""
|
||||
由父节点 (task_development) 在显示此弹窗前调用,
|
||||
传递当前在 task_info 中选中的题材 Key。
|
||||
"""
|
||||
initial_key_to_highlight = key
|
||||
print("Theme: 父节点设置初始高亮 Key 为: '%s'" % initial_key_to_highlight)
|
||||
|
||||
|
||||
# --- Data Processing and Display Logic ---
|
||||
|
||||
func _process_theme_data(all_themes_data: Dictionary):
|
||||
"""【修改】根据从 GameState 获取的题材数据,筛选出启用的题材,并计算总页数。"""
|
||||
all_enabled_themes.clear()
|
||||
if all_themes_data.is_empty():
|
||||
push_warning("警告:接收到的题材数据为空。")
|
||||
total_pages = 0
|
||||
return
|
||||
|
||||
# 遍历从 GameState 获取的题材字典
|
||||
for theme_name in all_themes_data:
|
||||
var theme_info = all_themes_data[theme_name]
|
||||
# 检查是否为字典且 "enabled" 字段为 true
|
||||
if typeof(theme_info) == TYPE_DICTIONARY and theme_info.get("enabled", false) == true:
|
||||
all_enabled_themes.append({"name": theme_name, "data": theme_info})
|
||||
# else: # Debugging
|
||||
# print("Theme: 过滤掉未启用或格式错误的题材: ", theme_name)
|
||||
|
||||
# 根据筛选结果计算总页数
|
||||
if items_per_page > 0:
|
||||
total_pages = ceil(float(all_enabled_themes.size()) / items_per_page)
|
||||
else:
|
||||
total_pages = 0
|
||||
printerr("错误:items_per_page 为零,无法计算页数。")
|
||||
|
||||
print("Theme: 处理完成,找到 %d 个启用的题材,共 %d 页。" % [all_enabled_themes.size(), total_pages])
|
||||
|
||||
|
||||
func reset_display():
|
||||
"""【修改】重置状态,从 GameState 重新加载数据,并准备更新显示。"""
|
||||
print("Theme: 重置显示状态 (reset_display)。")
|
||||
# 1. 重置本地状态变量
|
||||
currently_selected_button = null
|
||||
selected_theme_key = ""
|
||||
# initial_key_to_highlight 由 set_initial_selection 设置,这里不清空
|
||||
|
||||
# 2. 【修改】从 GameState 重新加载并处理数据
|
||||
if not GameState:
|
||||
printerr("错误:GameState 在 reset_display 期间不可用。")
|
||||
total_pages = 0
|
||||
all_enabled_themes.clear()
|
||||
_update_display() # 即使没有数据也要更新显示(显示空状态)
|
||||
return
|
||||
|
||||
# --- 获取题材数据 ---
|
||||
var task_dev_data = GameState.get_value("task_development", {})
|
||||
if task_dev_data.is_empty():
|
||||
printerr("错误:从 GameState 获取 'task_development' 数据失败。")
|
||||
total_pages = 0
|
||||
all_enabled_themes.clear()
|
||||
else:
|
||||
# --- 从 task_development 中获取 themes ---
|
||||
var all_themes_data = task_dev_data.get("themes", {})
|
||||
_process_theme_data(all_themes_data) # 重新处理数据,计算 total_pages
|
||||
|
||||
# 3. 【修改】根据 initial_key_to_highlight 确定初始页面
|
||||
current_page_index = 0 # 默认为第一页
|
||||
var found_initial_key = false
|
||||
if total_pages > 0 and not initial_key_to_highlight.is_empty():
|
||||
# 查找 initial_key_to_highlight 所在的索引和页面
|
||||
for i in range(all_enabled_themes.size()):
|
||||
if all_enabled_themes[i].name == initial_key_to_highlight:
|
||||
current_page_index = int(floor(float(i) / items_per_page))
|
||||
found_initial_key = true
|
||||
print("Theme: 找到需要初始高亮的 Key '%s' 在索引 %d, 目标页面 %d" % [initial_key_to_highlight, i, current_page_index])
|
||||
break # 找到了,停止循环
|
||||
if not found_initial_key:
|
||||
print("Theme: 需要初始高亮的 Key '%s' 未在启用的题材中找到,将显示第一页。" % initial_key_to_highlight)
|
||||
# 保持 current_page_index 为 0
|
||||
initial_key_to_highlight = "" # 清空,避免后续 _update_display 尝试高亮不存在的项
|
||||
|
||||
# 确保页面索引有效 (与 gameplay.gd 一致)
|
||||
if total_pages == 0:
|
||||
current_page_index = 0
|
||||
elif current_page_index >= total_pages:
|
||||
current_page_index = total_pages - 1
|
||||
elif current_page_index < 0:
|
||||
current_page_index = 0
|
||||
|
||||
# 4. 触发显示更新
|
||||
_update_display()
|
||||
|
||||
func _update_display():
|
||||
"""【更新版】更新列表的可见性并填充当前页面的内容。
|
||||
现在将“经验”和“成本”显示为整数。
|
||||
"""
|
||||
# --- 处理无数据情况 (与 gameplay.gd 一致) ---
|
||||
if theme_list_nodes.is_empty():
|
||||
print("Theme: 无可用的 List 节点。")
|
||||
if title_label: title_label.text = "题材选择"
|
||||
return
|
||||
|
||||
if total_pages == 0:
|
||||
for list_node in theme_list_nodes: list_node.visible = false
|
||||
print("Theme: 没有启用的题材选项可供显示。")
|
||||
if title_label: title_label.text = "题材选择 (无可用)"
|
||||
if previous_button: previous_button.disabled = true
|
||||
if next_button: next_button.disabled = true
|
||||
return
|
||||
else:
|
||||
if previous_button: previous_button.disabled = (total_pages <= 1)
|
||||
if next_button: next_button.disabled = (total_pages <= 1)
|
||||
|
||||
# --- 更新页面索引 (循环) (与 gameplay.gd 一致) ---
|
||||
if total_pages > 0 :
|
||||
current_page_index = current_page_index % total_pages
|
||||
if current_page_index < 0:
|
||||
current_page_index += total_pages
|
||||
else:
|
||||
current_page_index = 0
|
||||
|
||||
# --- 更新标题 (与 gameplay.gd 一致) ---
|
||||
if title_label:
|
||||
var display_page_number = current_page_index + 1
|
||||
title_label.text = "题材选择 %d/%d" % [display_page_number, total_pages]
|
||||
|
||||
# --- 更新 List 可见性 (与 gameplay.gd 一致) ---
|
||||
for i in range(theme_list_nodes.size()):
|
||||
theme_list_nodes[i].visible = (i == current_page_index)
|
||||
|
||||
# --- 填充可见列表并查找要高亮的按钮 (与 gameplay.gd 类似) ---
|
||||
var button_to_highlight: Button = null
|
||||
var first_enabled_button_on_page: Button = null
|
||||
|
||||
if current_page_index < option_nodes_per_list.size():
|
||||
var current_options = option_nodes_per_list[current_page_index]
|
||||
var start_index = current_page_index * items_per_page
|
||||
|
||||
for i in range(current_options.size()):
|
||||
var option_button = current_options[i]
|
||||
var item_index = start_index + i
|
||||
|
||||
# --- 断开旧信号 ---
|
||||
if option_button.pressed.is_connected(_on_option_selected):
|
||||
option_button.pressed.disconnect(_on_option_selected)
|
||||
|
||||
if item_index < all_enabled_themes.size():
|
||||
var theme_entry = all_enabled_themes[item_index]
|
||||
var theme_name = theme_entry.name
|
||||
var theme_data = theme_entry.data # 包含 Cost, Experience, Popularity 等
|
||||
|
||||
var row = option_button.get_node_or_null("Row")
|
||||
if row:
|
||||
# 填充标签文本
|
||||
var title_label_in_row = row.get_node_or_null("Title")
|
||||
var exp_label = row.get_node_or_null("Experience")
|
||||
var pop_label = row.get_node_or_null("Popularity")
|
||||
var cost_label = row.get_node_or_null("Cost") if row.has_node("Cost") else row.get_node_or_null("cost")
|
||||
|
||||
if title_label_in_row: title_label_in_row.text = theme_name
|
||||
|
||||
# 【修改】设置经验值,显示为整数
|
||||
if exp_label:
|
||||
var experience_value = theme_data.get("Experience", 0.0)
|
||||
exp_label.text = str(int(experience_value))
|
||||
|
||||
# 【保持】设置流行度,保持原始字符串显示
|
||||
if pop_label:
|
||||
var popularity_value = theme_data.get("Popularity", "未知")
|
||||
pop_label.text = str(popularity_value)
|
||||
|
||||
# 【修改】设置成本,显示为整数
|
||||
if cost_label:
|
||||
var cost_value = theme_data.get("Cost", 0.0)
|
||||
cost_label.text = str(int(cost_value))
|
||||
|
||||
option_button.visible = true
|
||||
option_button.disabled = false
|
||||
option_button.set_meta("theme_name", theme_name) # 存储题材名称
|
||||
|
||||
# --- 连接新信号 (使用 bind) ---
|
||||
option_button.pressed.connect(_on_option_selected.bind(theme_name, option_button))
|
||||
|
||||
if first_enabled_button_on_page == null:
|
||||
first_enabled_button_on_page = option_button
|
||||
|
||||
if not initial_key_to_highlight.is_empty() and theme_name == initial_key_to_highlight:
|
||||
button_to_highlight = option_button
|
||||
# print("Theme: 找到需要初始高亮的按钮: ", button_to_highlight.name) # Debug
|
||||
|
||||
else: # 未找到 Row 节点
|
||||
push_warning("警告:在按钮 %s 中未找到 Row 节点" % option_button.get_path())
|
||||
option_button.visible = false
|
||||
option_button.disabled = true
|
||||
else: # 此槽位没有对应的启用题材数据
|
||||
option_button.visible = false
|
||||
option_button.disabled = true
|
||||
else:
|
||||
printerr("错误:当前页面索引 %d 超出 option_nodes_per_list 的范围 (大小 %d)" % [current_page_index, option_nodes_per_list.size()])
|
||||
|
||||
# --- 设置初始高亮和焦点 (与 gameplay.gd 一致) ---
|
||||
if button_to_highlight:
|
||||
_set_initial_highlight(button_to_highlight)
|
||||
elif first_enabled_button_on_page:
|
||||
print("Theme: 初始 Key '%s' 不在本页或为空。高亮本页第一个按钮: %s" % [initial_key_to_highlight, first_enabled_button_on_page.name])
|
||||
_set_initial_highlight(first_enabled_button_on_page)
|
||||
else:
|
||||
print("Theme: 本页没有可供高亮的按钮。")
|
||||
currently_selected_button = null
|
||||
selected_theme_key = ""
|
||||
|
||||
# (Helper) 设置初始高亮和焦点 (与 gameplay.gd 一致)
|
||||
func _set_initial_highlight(button_to_highlight: Button):
|
||||
if not is_instance_valid(button_to_highlight):
|
||||
printerr("错误:传递给 _set_initial_highlight 的按钮无效。")
|
||||
currently_selected_button = null
|
||||
selected_theme_key = ""
|
||||
return
|
||||
|
||||
# print("Theme: 设置高亮按钮: ", button_to_highlight.name) # Debug
|
||||
currently_selected_button = button_to_highlight
|
||||
# --- 修改元数据键名 ---
|
||||
selected_theme_key = button_to_highlight.get_meta("theme_name", "") # 同时设置 Key
|
||||
# print("Theme: currently_selected_button 设置为: ", currently_selected_button.name) # Debug
|
||||
# print("Theme: selected_theme_key 设置为: '", selected_theme_key, "'") # Debug
|
||||
|
||||
if currently_selected_button and currently_selected_button.is_inside_tree():
|
||||
# print("Theme: 尝试为按钮 call_deferred('grab_focus'): ", currently_selected_button.name) # Debug
|
||||
currently_selected_button.call_deferred("grab_focus")
|
||||
else:
|
||||
print("Theme: 按钮无效或不在场景树中,无法获取焦点。")
|
||||
|
||||
|
||||
# --- Signal Handlers ---
|
||||
|
||||
# (与 gameplay.gd 一致)
|
||||
func _on_previous_pressed():
|
||||
if total_pages > 1:
|
||||
current_page_index -= 1
|
||||
_update_display()
|
||||
|
||||
# (与 gameplay.gd 一致)
|
||||
func _on_next_pressed():
|
||||
if total_pages > 1:
|
||||
current_page_index += 1
|
||||
_update_display()
|
||||
|
||||
# 【修改】处理选项按钮按下事件 (与 gameplay.gd 一致)
|
||||
func _on_option_selected(theme_name: String, button_node: Button):
|
||||
"""当选项按钮被按下时调用。"""
|
||||
if not is_instance_valid(button_node):
|
||||
# --- 修改错误信息中的 Key 类型 ---
|
||||
printerr("错误:在 _on_option_selected 中收到无效按钮节点,Key: " + theme_name)
|
||||
return
|
||||
|
||||
if button_node == currently_selected_button:
|
||||
# --- 双击 (或点击已选中的按钮) ---
|
||||
print("Theme: 检测到双击或确认点击: ", theme_name)
|
||||
_confirm_and_close(theme_name) # 确认此选择
|
||||
else:
|
||||
# --- 首次点击或点击不同按钮 ---
|
||||
print("Theme: 选中 (高亮) 题材: ", theme_name)
|
||||
currently_selected_button = button_node
|
||||
selected_theme_key = theme_name # 更新 Key
|
||||
|
||||
# 更新视觉焦点
|
||||
button_node.grab_focus()
|
||||
|
||||
# 【修改】确认选择并关闭弹窗的逻辑 (与 gameplay.gd 一致)
|
||||
func _confirm_and_close(key_to_confirm: String):
|
||||
"""更新父节点并关闭此弹窗。"""
|
||||
if key_to_confirm.is_empty():
|
||||
printerr("错误:尝试确认一个空的题材 Key。")
|
||||
return
|
||||
|
||||
print("Theme: 确认选择: ", key_to_confirm)
|
||||
|
||||
# --- 更新父节点 (Task Development Popup) ---
|
||||
var parent_node = get_parent()
|
||||
if parent_node and parent_node.has_method("update_task_options"):
|
||||
# --- 修改传递给父节点的字典键名 ---
|
||||
parent_node.update_task_options({"题材": key_to_confirm})
|
||||
print("Theme: 已更新父节点的 task_options: 题材 = ", key_to_confirm)
|
||||
else:
|
||||
printerr("错误:Theme: 父节点未找到或缺少 'update_task_options' 方法。")
|
||||
|
||||
# --- 关闭此弹窗 (与 gameplay.gd 一致) ---
|
||||
if parent_node and parent_node.has_method("_close_child_popup_and_return"):
|
||||
parent_node._close_child_popup_and_return(self)
|
||||
else:
|
||||
printerr("错误:Theme: 父节点未找到或缺少 '_close_child_popup_and_return' 方法。")
|
||||
self.hide() # 备选方案
|
||||
1
UI/popup/task_development_bak/theme/theme.gd.uid
Normal file
1
UI/popup/task_development_bak/theme/theme.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://do3rv2hocchy3
|
||||
2492
UI/popup/task_development_bak/theme/theme.tscn
Normal file
2492
UI/popup/task_development_bak/theme/theme.tscn
Normal file
File diff suppressed because it is too large
Load Diff
154
UI/ui_base.gd
Normal file
154
UI/ui_base.gd
Normal file
@ -0,0 +1,154 @@
|
||||
# ui_base.gd
|
||||
class_name UIPage
|
||||
extends Control
|
||||
|
||||
# --- Signals ---
|
||||
signal navigate_requested(target_page_node: Control)
|
||||
signal workflow_end_requested(is_confirm_and_trigger_action: bool)
|
||||
|
||||
# --- Exported Variables for Inspector ---
|
||||
## The page to navigate to when a "next" or "confirm" action is triggered.
|
||||
@export var next_ui_node_path: NodePath
|
||||
## The page to navigate to when a "back" or "cancel" action is triggered.
|
||||
@export var back_ui_node_path: NodePath
|
||||
## For sub-pages, this is their direct parent page (e.g., A is parent of A_1).
|
||||
## Used if back_ui_node_path is not set for a sub-page, to return to its parent.
|
||||
@export var parent_page_node_path: NodePath
|
||||
## If true (default), this page will be hidden when go_next() is called and
|
||||
## a next_ui_node_path is successfully navigated to.
|
||||
## If false, this page will remain visible.
|
||||
@export var hide_on_next: bool = true
|
||||
|
||||
# --- Internal Variables ---
|
||||
var main_controller # Will hold reference to Main.gd
|
||||
|
||||
func _ready():
|
||||
# Attempt to find the Main controller. Assumes Main is the owner or a known path.
|
||||
if owner and owner.has_method("get_shared_data"): # Simple check if owner is Main
|
||||
main_controller = owner
|
||||
|
||||
# --- Godot Input Handling ---
|
||||
func _input(event):
|
||||
# Only process input if the page is currently visible and the feature is enabled
|
||||
if not visible:
|
||||
return
|
||||
|
||||
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT and event.is_pressed():
|
||||
print("UIPage '", name, "' detected right-click. Attempting to go back.")
|
||||
go_back()
|
||||
get_viewport().set_input_as_handled() # Consume the event so other nodes don't process it
|
||||
|
||||
# --- Public Methods ---
|
||||
func show_page():
|
||||
# 仅当页面之前是不可见状态时,才设置 visible = true。
|
||||
# 或者更简单地,总是设置 visible = true,因为重复设置 true 没有副作用。
|
||||
if not visible:
|
||||
visible = true
|
||||
|
||||
func hide_page():
|
||||
# Only call _on_page_deactivated if the page was previously visible.
|
||||
if visible:
|
||||
_on_page_deactivated() # Call the overridable method before hiding
|
||||
visible = false
|
||||
# else:
|
||||
# print("UIPage " + name + " already hidden. Not re-deactivating.")
|
||||
|
||||
func _on_page_activated():
|
||||
# Base implementation can be empty or log
|
||||
print("UIPage activated: " + name)
|
||||
pass
|
||||
|
||||
func _on_page_deactivated():
|
||||
# Base implementation can be empty or log
|
||||
print("UIPage deactivated: " + name)
|
||||
pass
|
||||
|
||||
# --- Navigation Methods (to be called by buttons on this page) ---
|
||||
func go_next():
|
||||
if not next_ui_node_path.is_empty():
|
||||
var target_node = get_node_or_null(next_ui_node_path)
|
||||
if target_node and target_node is Control: # Ensure target_node is a Control, ideally a UIPage
|
||||
emit_signal("navigate_requested", target_node)
|
||||
else:
|
||||
printerr("Next UI node not found or not a Control: ", next_ui_node_path, " from page ", name)
|
||||
emit_signal("workflow_end_requested", true) # Or some error state
|
||||
else:
|
||||
# next_ui_node is null, meaning workflow ends with confirmation
|
||||
emit_signal("workflow_end_requested", true)
|
||||
|
||||
func go_back():
|
||||
var target_path_to_try = back_ui_node_path
|
||||
if target_path_to_try.is_empty() and not parent_page_node_path.is_empty():
|
||||
target_path_to_try = parent_page_node_path
|
||||
|
||||
if not target_path_to_try.is_empty():
|
||||
var target_node = get_node_or_null(target_path_to_try)
|
||||
if target_node and target_node is Control: # Ensure target_node is a Control, ideally a UIPage
|
||||
emit_signal("navigate_requested", target_node)
|
||||
else:
|
||||
printerr("Back/Parent UI node not found or not a Control: ", target_path_to_try, " from page ", name)
|
||||
emit_signal("workflow_end_requested", false) # Or some error state
|
||||
else:
|
||||
emit_signal("workflow_end_requested", false)
|
||||
|
||||
# --- Data Access Methods (Examples) ---
|
||||
func get_main_data(key: String, default = null):
|
||||
if main_controller:
|
||||
return main_controller.get_shared_data(key, default)
|
||||
else: # <--- 修改点: 将警告移入 else 分支
|
||||
push_warning("Cannot get_main_data, Main controller not found from page '", name, "'")
|
||||
return default
|
||||
|
||||
func set_main_data(key: String, value):
|
||||
if main_controller:
|
||||
main_controller.set_shared_data(key, value)
|
||||
else: # <--- 修改点: 将警告移入 else 分支
|
||||
push_warning("Cannot set_main_data, Main controller not found from page '", name, "'. Data not set.")
|
||||
|
||||
# --- Helper function to check if potential_ancestor is an ancestor of node_to_check ---
|
||||
func _is_ancestor_of(potential_ancestor: Node, node_to_check: Node) -> bool:
|
||||
if not potential_ancestor or not node_to_check:
|
||||
return false
|
||||
# Ensure both nodes are in the scene tree to safely use get_parent()
|
||||
if not node_to_check.is_inside_tree() or not potential_ancestor.is_inside_tree():
|
||||
return false
|
||||
|
||||
var current_parent = node_to_check.get_parent()
|
||||
while current_parent:
|
||||
if current_parent == potential_ancestor:
|
||||
return true
|
||||
current_parent = current_parent.get_parent() # Move up the tree
|
||||
return false
|
||||
|
||||
# --- Helper for navigating to a specific child page (MODIFIED) ---
|
||||
func go_to_child_page(child_page_node: Control):
|
||||
# Check if a child_page_node was provided
|
||||
if not child_page_node:
|
||||
printerr("Error in '", name, ".go_to_child_page': Target child_page_node is null.")
|
||||
return
|
||||
|
||||
# This check prevents navigating to an ancestor using this function.
|
||||
# If child_page_node is an ancestor of self, it's considered an invalid target for "go_to_child_page".
|
||||
# Original problematic line: if child_page_node and child_page_node.is_a_parent_of(self):
|
||||
if _is_ancestor_of(child_page_node, self):
|
||||
printerr("Error in '", name, ".go_to_child_page': Navigation target '", child_page_node.name,
|
||||
"' cannot be an ancestor of the current page '", self.name,
|
||||
"'. 'go_to_child_page' is intended for pages that are descendants or unrelated in the scene tree hierarchy.")
|
||||
return
|
||||
|
||||
# Optional: If 'go_to_child_page' strictly means a *direct child* in the scene tree,
|
||||
# you might want to add a check like this:
|
||||
# if child_page_node.get_parent() != self:
|
||||
# printerr("Error in '", name, ".go_to_child_page': Target '", child_page_node.name,
|
||||
# "' is not a direct child of this page '", self.name, "'.")
|
||||
# return
|
||||
|
||||
# Ensure child_page_node is a Control (already type-hinted, but good for safety)
|
||||
if child_page_node is Control:
|
||||
emit_signal("navigate_requested", child_page_node)
|
||||
#self._on_page_deactivated()
|
||||
else:
|
||||
# This case might occur if something other than a Control node is passed,
|
||||
# despite the type hint.
|
||||
printerr("Error in '", name, ".go_to_child_page': Invalid target '", child_page_node,
|
||||
"'. It is not a Control node.")
|
||||
1
UI/ui_base.gd.uid
Normal file
1
UI/ui_base.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://0l12ik4nakcj
|
||||
148
UI/ui_framework.gd
Normal file
148
UI/ui_framework.gd
Normal file
@ -0,0 +1,148 @@
|
||||
# main_controller.gd
|
||||
extends Control
|
||||
|
||||
# --- Signals ---
|
||||
signal workflow_confirmed(final_data: Dictionary)
|
||||
signal workflow_cancelled()
|
||||
|
||||
# --- Exported Variables ---
|
||||
@export var initial_page_path: NodePath
|
||||
@export var gamestate_data_key: String
|
||||
|
||||
# --- Internal Variables ---
|
||||
var current_active_page: UIPage = null
|
||||
var shared_workflow_data: Dictionary = {}
|
||||
|
||||
# --- Godot Lifecycle Methods ---
|
||||
func _ready():
|
||||
shared_workflow_data = GameState.get_value(gamestate_data_key)
|
||||
for child in get_children():
|
||||
if child is UIPage:
|
||||
child.hide_page()
|
||||
_connect_page_signals(child)
|
||||
for sub_child in child.get_children():
|
||||
if sub_child is UIPage:
|
||||
sub_child.hide_page()
|
||||
_connect_page_signals(sub_child)
|
||||
|
||||
# --- Public Methods ---
|
||||
func show_up():
|
||||
GameState.pause_game()
|
||||
shared_workflow_data = GameState.get_value(gamestate_data_key)
|
||||
if not initial_page_path.is_empty():
|
||||
var initial_page_node = get_node_or_null(initial_page_path)
|
||||
if initial_page_node and initial_page_node is UIPage:
|
||||
start_new_workflow(initial_page_node, shared_workflow_data)
|
||||
else:
|
||||
printerr("Main: Initial page not found or not a UIPage: ", initial_page_path)
|
||||
else:
|
||||
self.visible = false
|
||||
|
||||
func start_new_workflow(start_page: UIPage, initial_data: Dictionary = {}):
|
||||
print("Main: Starting new workflow with page: ", start_page.name, " and data: ", initial_data)
|
||||
shared_workflow_data = initial_data.duplicate()
|
||||
|
||||
for child in get_children():
|
||||
if child is UIPage and child != start_page:
|
||||
child.hide_page()
|
||||
for sub_child in child.get_children():
|
||||
if sub_child is UIPage:
|
||||
sub_child.hide_page()
|
||||
|
||||
_switch_to_page(start_page)
|
||||
self.visible = true
|
||||
|
||||
func get_shared_data(key: String, default = null):
|
||||
return shared_workflow_data.get(key, default)
|
||||
|
||||
func set_shared_data(key: String, value):
|
||||
shared_workflow_data[key] = value
|
||||
print("Main: Shared data updated: ", shared_workflow_data)
|
||||
|
||||
# --- Private Helper Methods ---
|
||||
func _connect_page_signals(page: UIPage):
|
||||
if not page.is_connected("navigate_requested", Callable(self, "_on_page_navigate_requested")):
|
||||
page.navigate_requested.connect(self._on_page_navigate_requested)
|
||||
if not page.is_connected("workflow_end_requested", Callable(self, "_on_page_workflow_end_requested")):
|
||||
page.workflow_end_requested.connect(self._on_page_workflow_end_requested)
|
||||
|
||||
func _switch_to_page(target_page: UIPage):
|
||||
var previous_page = current_active_page
|
||||
|
||||
if previous_page:
|
||||
# ... (处理前一页面的隐藏逻辑,包括 hide_on_next 和父页面清理) ...
|
||||
# (这部分逻辑不变)
|
||||
var should_hide_previous_page = true
|
||||
if previous_page.has_meta("hide_on_next"):
|
||||
should_hide_previous_page = previous_page.get_meta("hide_on_next")
|
||||
elif previous_page.has_signal("about_to_show"):
|
||||
if "hide_on_next" in previous_page:
|
||||
should_hide_previous_page = previous_page.hide_on_next
|
||||
else:
|
||||
printerr("MainController: 'hide_on_next' property not found on previous_page '", previous_page.name, "'. Defaulting to hide.")
|
||||
|
||||
if should_hide_previous_page:
|
||||
previous_page.hide_page()
|
||||
|
||||
var old_page_parent_path = previous_page.parent_page_node_path
|
||||
if not old_page_parent_path.is_empty():
|
||||
var old_page_parent_node = previous_page.get_node_or_null(old_page_parent_path) as UIPage
|
||||
if old_page_parent_node:
|
||||
var target_is_old_parent_itself = (target_page == old_page_parent_node)
|
||||
var target_is_sibling_of_previous = false
|
||||
var target_parent = target_page.get_parent()
|
||||
if target_parent and target_parent == old_page_parent_node:
|
||||
target_is_sibling_of_previous = true
|
||||
|
||||
if not target_is_old_parent_itself and not target_is_sibling_of_previous:
|
||||
old_page_parent_node.hide_page()
|
||||
|
||||
current_active_page = target_page
|
||||
current_active_page.show_page() # 调用 UIPage.show_page(),现在它只负责设置 visible = true
|
||||
|
||||
# 确保新页面的 _on_page_activated() 被调用,无论它之前是否可见
|
||||
current_active_page._on_page_activated() # <--- 关键:MainController 负责调用
|
||||
|
||||
# 确保新当前页面的父页面 (如果它是子页面) 也可见并已激活 (如果需要)
|
||||
var new_page_parent_path = current_active_page.parent_page_node_path
|
||||
if not new_page_parent_path.is_empty():
|
||||
var new_page_parent_node = current_active_page.get_node_or_null(new_page_parent_path) as UIPage
|
||||
if new_page_parent_node:
|
||||
# 如果父页面之前不可见,则显示并激活它
|
||||
if not new_page_parent_node.visible:
|
||||
new_page_parent_node.show_page() # 使其可见
|
||||
new_page_parent_node._on_page_activated() # 激活它
|
||||
else:
|
||||
# 如果父页面已经可见 (例如,它从未被隐藏),
|
||||
# 确保其 show_page 至少被调用一次以符合逻辑 (尽管它可能什么都不做)
|
||||
new_page_parent_node.show_page()
|
||||
|
||||
print("Main: Switched to page: ", current_active_page.name)
|
||||
|
||||
# --- Signal Handlers ---
|
||||
func _on_page_navigate_requested(target_page_node: Control): # Changed to Control to match signal
|
||||
if target_page_node is UIPage:
|
||||
_switch_to_page(target_page_node)
|
||||
else:
|
||||
printerr("Main: Navigation requested to a node that is not a UIPage: ", target_page_node)
|
||||
|
||||
func _on_page_workflow_end_requested(is_confirm_and_trigger_action: bool):
|
||||
print("Main: Workflow end requested. Confirm and trigger: ", is_confirm_and_trigger_action)
|
||||
if is_confirm_and_trigger_action:
|
||||
print("Main: Workflow CONFIRMED. Final data: ", shared_workflow_data)
|
||||
emit_signal("workflow_confirmed", shared_workflow_data)
|
||||
else:
|
||||
print("Main: Workflow CANCELLED/BACKED OUT.")
|
||||
emit_signal("workflow_cancelled")
|
||||
|
||||
if current_active_page:
|
||||
current_active_page.hide_page()
|
||||
var parent = current_active_page.get_node_or_null(current_active_page.parent_page_node_path) as UIPage
|
||||
if parent:
|
||||
parent.hide_page()
|
||||
|
||||
current_active_page = null
|
||||
GameState.set_value(gamestate_data_key,shared_workflow_data)
|
||||
GameState.resume_game()
|
||||
self.visible = false
|
||||
print("Main: UI Workflow finished and Main hidden.")
|
||||
1
UI/ui_framework.gd.uid
Normal file
1
UI/ui_framework.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://du4qd5ynhkjs6
|
||||
@ -35,6 +35,7 @@ window/stretch/mode="viewport"
|
||||
UI_MAIN=""
|
||||
dialogue=""
|
||||
notice=""
|
||||
task_development=""
|
||||
|
||||
[rendering]
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user