D5/UI/popup/task_development_bak/task_development.gd

382 lines
15 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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)