继续完成task_development的ui工作流。
This commit is contained in:
parent
e7d7ebf727
commit
033515a7b6
@ -71,7 +71,6 @@ func get_savable_state() -> Dictionary:
|
||||
# 返回深拷贝,确保存档系统拿到的是快照,不会意外修改当前状态
|
||||
return _state_data.duplicate(true)
|
||||
|
||||
|
||||
# --- 状态访问 (通用 Getter) ---
|
||||
|
||||
# 获取指定键 (key) 的状态值。
|
||||
|
||||
@ -1,28 +1,40 @@
|
||||
{
|
||||
"npc": {
|
||||
"米子一": {
|
||||
"type": "员工",
|
||||
"title": "项目总监",
|
||||
"level": 1,
|
||||
"power": 180,
|
||||
"power_max": 180,
|
||||
"design": 80,
|
||||
"code": 70,
|
||||
"art": 80,
|
||||
"audio": 70,
|
||||
"outsourcing": 0
|
||||
},
|
||||
"塔奇": {
|
||||
"type": "员工",
|
||||
"title": "美术设计师",
|
||||
"level": 3,
|
||||
"power": 150,
|
||||
"power_max": 150,
|
||||
"design": 80,
|
||||
"code": 20,
|
||||
"art": 90,
|
||||
"audio": 80,
|
||||
"outsourcing": 2400
|
||||
}
|
||||
}
|
||||
}
|
||||
"npc": {
|
||||
"米子三": {
|
||||
"type": "员工",
|
||||
"title": "项目总监",
|
||||
"level": 1,
|
||||
"power": 180,
|
||||
"power_max": 180,
|
||||
"design": 80,
|
||||
"code": 70,
|
||||
"art": 80,
|
||||
"audio": 70,
|
||||
"outsourcing": 0
|
||||
},
|
||||
"塔祺": {
|
||||
"type": "员工",
|
||||
"title": "美术设计师",
|
||||
"level": 3,
|
||||
"power": 150,
|
||||
"power_max": 150,
|
||||
"design": 80,
|
||||
"code": 20,
|
||||
"art": 90,
|
||||
"audio": 80,
|
||||
"outsourcing": 2400
|
||||
},
|
||||
"瞎五": {
|
||||
"type": "外包",
|
||||
"title": "策划",
|
||||
"level": 2,
|
||||
"power": 160,
|
||||
"power_max": 160,
|
||||
"design": 90,
|
||||
"code": 50,
|
||||
"art": 70,
|
||||
"audio": 70,
|
||||
"outsourcing": 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,9 +59,7 @@ func _ready() -> void:
|
||||
print("UI_Main 初始化完成:时间、金钱、点子已显示(确保为整数)。")
|
||||
|
||||
GameState.date_changed.connect(_on_date_changed)
|
||||
|
||||
# --- 待办事项 (TODO): 实现动态更新 ---
|
||||
# GameState.state_value_changed.connect(_on_state_value_changed)
|
||||
GameState.state_value_changed.connect(_on_state_value_changed)
|
||||
|
||||
# --- 信号处理函数 (将在后续添加具体实现) ---
|
||||
func _on_date_changed(new_date: Dictionary) -> void:
|
||||
@ -73,10 +71,10 @@ func _on_date_changed(new_date: Dictionary) -> void:
|
||||
else:
|
||||
printerr("警告:接收到的 date_changed 信号数据格式不正确。")
|
||||
|
||||
# func _on_state_value_changed(key: String, new_value: Variant) -> void:
|
||||
# print("接收到 state_value_changed 信号: key=", key, ", value=", new_value)
|
||||
# match key:
|
||||
# "money":
|
||||
# money_button.text = _format_value_as_int_string(new_value, "0")
|
||||
# "idea":
|
||||
# idea_button.text = _format_value_as_int_string(new_value, "0")
|
||||
func _on_state_value_changed(key: String, new_value: Variant) -> void:
|
||||
print("接收到 state_value_changed 信号: key=", key, ", value=", new_value)
|
||||
match key:
|
||||
"money":
|
||||
money_button.text = _format_value_as_int_string(new_value, "0")
|
||||
"idea":
|
||||
idea_button.text = _format_value_as_int_string(new_value, "0")
|
||||
|
||||
@ -1,61 +1,6 @@
|
||||
extends Control
|
||||
extends UIPage
|
||||
|
||||
var node_name: String
|
||||
var next_ui_node = null # 存储下一个要显示的UI节点引用
|
||||
var is_active: bool = false # 活动状态标志
|
||||
|
||||
# 添加一个信号,当notice关闭时发出
|
||||
signal notice_closed
|
||||
@export var notice_text = ''
|
||||
|
||||
func _ready() -> void:
|
||||
node_name = str(self.name)
|
||||
#visible = false # 初始状态为隐藏
|
||||
#set_process_input(false)
|
||||
|
||||
func _start(notice_info, next_node = null) -> void:
|
||||
var label = get_node_or_null("Part_2/Part_3/Label")
|
||||
if label: label.text = notice_info
|
||||
|
||||
# 存储下一个UI节点
|
||||
next_ui_node = next_node
|
||||
|
||||
self.visible = true
|
||||
GameState.pause_game()
|
||||
set_process_input(true)
|
||||
is_active = true # 标记为活动状态
|
||||
print(node_name + ": Activated.")
|
||||
|
||||
# 处理输入事件 (用于右键关闭弹窗)
|
||||
func _input(event):
|
||||
if not is_active: return
|
||||
# 检测鼠标右键点击事件
|
||||
if event is InputEventMouseButton and (event.button_index == MOUSE_BUTTON_LEFT or event.button_index == MOUSE_BUTTON_RIGHT) and event.is_pressed():
|
||||
_close_notice()
|
||||
# 消耗事件,防止它被传递到游戏世界
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
# 新增关闭notice的方法,便于代码复用
|
||||
func _close_notice():
|
||||
if not is_active: return
|
||||
|
||||
self.visible = false
|
||||
print(node_name + ": Closed popup via right-click: ", self.name)
|
||||
|
||||
# 如果所有弹窗都已关闭,恢复游戏并停止输入处理
|
||||
print(node_name + ": resuming game.")
|
||||
if GameState: GameState.resume_game()
|
||||
set_process_input(false)
|
||||
|
||||
# 发出关闭信号
|
||||
emit_signal("notice_closed")
|
||||
|
||||
# 检查是否有下一个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
|
||||
|
||||
$Part_2/Part_3/Label.text = notice_text
|
||||
|
||||
@ -105,6 +105,6 @@ grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_fonts/font = ExtResource("3_gxhc5")
|
||||
theme_override_font_sizes/font_size = 20
|
||||
text = "保存完毕"
|
||||
text = "资金不足"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
@ -1,390 +0,0 @@
|
||||
# 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 +0,0 @@
|
||||
uid://cbiwirr68lspl
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,17 +0,0 @@
|
||||
[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")
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
@ -1,34 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://ctled08bky4mu"
|
||||
path="res://.godot/imported/key_output.png-784f6b35ef722e290819983a5a30c217.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://UI/popup/task_development/key_output/key_output.png"
|
||||
dest_files=["res://.godot/imported/key_output.png-784f6b35ef722e290819983a5a30c217.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
|
||||
@ -19,7 +19,6 @@ extends UIPage # 继承自我们之前创建的 UIPage
|
||||
|
||||
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:
|
||||
@ -34,7 +33,12 @@ func _ready():
|
||||
|
||||
func _on_page_activated():
|
||||
super._on_page_activated() # 调用父类的激活逻辑
|
||||
|
||||
print(name + " 页面已激活")
|
||||
# 当从其它页面退回到当前页面的时候,money恢复show_up起始值
|
||||
if get_main_data("original_money") > GameState.get_value("money"):
|
||||
GameState.set_value("money",get_main_data("original_money"))
|
||||
|
||||
_calculate_and_update_budget()
|
||||
# 从 MainController 加载并显示数据
|
||||
# 例如,加载项目预算
|
||||
@ -174,6 +178,12 @@ func _on_strategy_select_button_pressed():
|
||||
|
||||
func _on_confirm_button_pressed():
|
||||
# 导航到下一个页面或结束工作流
|
||||
# 由于 main_page 在 task_development.tscn 中配置的 next_ui_node_path 为空,
|
||||
# 调用 go_next() 将触发 workflow_end_requested(true) 信号。
|
||||
go_next()
|
||||
if GameState.get_value("money") < get_main_data("预算"):
|
||||
next_ui_node_path = "../notice_1"
|
||||
go_next()
|
||||
return
|
||||
else:
|
||||
next_ui_node_path = "../product_focus"
|
||||
var new_money = GameState.get_value("money")-get_main_data("预算")
|
||||
GameState.set_value("money",new_money)
|
||||
go_next()
|
||||
|
||||
@ -22,6 +22,8 @@ var _power_bar_segments: Array[ColorRect] = [] # 用于存储体力条的各个
|
||||
@onready var next_button: Button = $BG/Title/next/Button
|
||||
@onready var confirm_button: Button = $BG/Confirm
|
||||
|
||||
@export var Suitable_position:Array = []
|
||||
|
||||
# --- 内部状态 ---
|
||||
var _all_npcs_data: Dictionary = {} # 存储从 GameState 加载的所有NPC原始数据
|
||||
var enabled_npc_keys: Array[String] = [] # 存储所有当前可选的NPC的键 (名字)
|
||||
@ -100,10 +102,30 @@ func _load_and_filter_npcs() -> void:
|
||||
|
||||
_all_npcs_data = raw_npcs_data.duplicate(true)
|
||||
|
||||
# Suitable_position 是一个 @export var Array,你需要确保它在编辑器中或通过代码被正确赋值。
|
||||
# 例如: Suitable_position = ["项目经理", "技术总监", "艺术总监"]
|
||||
|
||||
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)
|
||||
|
||||
if typeof(npc_info) == TYPE_DICTIONARY:
|
||||
var npc_type: String = npc_info.get("type", "") # 获取NPC类型,默认为空字符串
|
||||
var npc_title: String = npc_info.get("title", "") # 获取NPC职位,默认为空字符串
|
||||
var npc_outsourcing: float = float(npc_info.get("outsourcing", 0.0)) # 获取外包费用,默认为0.0
|
||||
|
||||
# 检查条件1: type是员工,同时title在Suitable_position中有
|
||||
var condition1_met = false
|
||||
if npc_type == "员工" and Suitable_position.has(npc_title):
|
||||
condition1_met = true
|
||||
|
||||
# 检查条件2: outsourcing>0,同时title在Suitable_position中有
|
||||
var condition2_met = false
|
||||
if npc_outsourcing > 0.0 and Suitable_position.has(npc_title): # 浮点数比较建议与 0.0 比较
|
||||
condition2_met = true
|
||||
|
||||
# 如果任一条件满足,则将该NPC加入到可用列表中
|
||||
if condition1_met or condition2_met:
|
||||
enabled_npc_keys.append(npc_key)
|
||||
|
||||
# 可选:对 enabled_npc_keys进行排序,以确保显示顺序一致
|
||||
# enabled_npc_keys.sort()
|
||||
@ -228,5 +250,14 @@ 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()
|
||||
# 导航到下一个页面或结束工作流
|
||||
if GameState.get_value("money") < int(cost_label.text):
|
||||
next_ui_node_path = "../notice_2"
|
||||
go_next()
|
||||
return
|
||||
else:
|
||||
next_ui_node_path = ""
|
||||
var new_money = GameState.get_value("money")-get_main_data("预算")
|
||||
GameState.set_value("money",new_money)
|
||||
set_main_data("关键环节负责人", selected_npc_key)
|
||||
go_next()
|
||||
|
||||
@ -268,27 +268,32 @@ grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="NPC_Info_1" type="HBoxContainer" parent="BG/Option"]
|
||||
custom_minimum_size = Vector2(380, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -170.0
|
||||
offset_left = -190.0
|
||||
offset_top = 47.0
|
||||
offset_right = 202.0
|
||||
offset_right = 190.0
|
||||
offset_bottom = 87.0
|
||||
grow_horizontal = 2
|
||||
theme_override_constants/separation = 160
|
||||
alignment = 1
|
||||
|
||||
[node name="Name" type="Label" parent="BG/Option/NPC_Info_1"]
|
||||
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 = 24
|
||||
text = "米子一"
|
||||
label_settings = SubResource("LabelSettings_w5gvb")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Sep" type="Control" parent="BG/Option/NPC_Info_1"]
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Staff" type="Label" parent="BG/Option/NPC_Info_1"]
|
||||
custom_minimum_size = Vector2(140, 0)
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_fonts/font = ExtResource("4_mk7go")
|
||||
@ -329,10 +334,9 @@ 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)
|
||||
custom_minimum_size = Vector2(130, 0)
|
||||
layout_mode = 2
|
||||
text = "产品总监"
|
||||
label_settings = SubResource("LabelSettings_kgbbm")
|
||||
@ -347,6 +351,7 @@ 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
|
||||
expand_mode = 2
|
||||
stretch_mode = 5
|
||||
|
||||
[node name="Info_List_1" type="GridContainer" parent="BG/Option/NPC_Info_2"]
|
||||
@ -470,10 +475,10 @@ horizontal_alignment = 1
|
||||
|
||||
[node name="Info_List_2" type="HBoxContainer" parent="BG/Option/NPC_Info_2"]
|
||||
layout_mode = 1
|
||||
offset_left = 49.0
|
||||
offset_left = 58.0
|
||||
offset_top = 164.0
|
||||
offset_right = 169.0
|
||||
offset_bottom = 164.0
|
||||
offset_right = 178.0
|
||||
offset_bottom = 174.0
|
||||
theme_override_constants/separation = 0
|
||||
alignment = 1
|
||||
|
||||
@ -584,7 +589,7 @@ 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)
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
text = "500"
|
||||
label_settings = ExtResource("6_3iojh")
|
||||
|
||||
@ -1,278 +0,0 @@
|
||||
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 +0,0 @@
|
||||
uid://ddadoyxwx3sbh
|
||||
@ -1,488 +0,0 @@
|
||||
[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/platform/platform.gd" id="2_bu5lv"]
|
||||
[ext_resource type="Texture2D" uid="uid://b2n1f22bd06tc" path="res://UI/popup/task_development/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 = "确定"
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.6 KiB |
@ -1,34 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b2n1f22bd06tc"
|
||||
path="res://.godot/imported/platform_1.png-0e1645d04a8add797ec527f1c14cb0a9.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://UI/popup/task_development/platform/platform_1.png"
|
||||
dest_files=["res://.godot/imported/platform_1.png-0e1645d04a8add797ec527f1c14cb0a9.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
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.4 KiB |
@ -1,34 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://c53cngwtsi5hb"
|
||||
path="res://.godot/imported/platform_2.png-f66d0147b3d6ab941ada98eef168dcb4.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://UI/popup/task_development/platform/platform_2.png"
|
||||
dest_files=["res://.godot/imported/platform_2.png-f66d0147b3d6ab941ada98eef168dcb4.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,291 +0,0 @@
|
||||
# 文件名: 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 +0,0 @@
|
||||
uid://b5mfw2kc6lqpd
|
||||
@ -1,351 +0,0 @@
|
||||
[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/strategy/strategy.gd" id="2_rq5uk"]
|
||||
[ext_resource type="Theme" uid="uid://ddq54ba6vwyn0" path="res://UI/popup/task_development/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")
|
||||
@ -1,362 +0,0 @@
|
||||
# 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 = {
|
||||
"平台": "", # 中文 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
|
||||
}
|
||||
|
||||
# --- 初始化 ---
|
||||
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() # 假设 GameState 有此方法
|
||||
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,例如 {"平台": "Switch"}
|
||||
func update_task_options(options: Dictionary) -> void:
|
||||
var updated = false
|
||||
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 + ": Option '%s' updated to '%s'." % [key, new_value_key])
|
||||
else:
|
||||
printerr(node_name + ": Invalid key '%s' provided in update_task_options." % key)
|
||||
|
||||
if updated:
|
||||
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:
|
||||
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 +0,0 @@
|
||||
uid://chgujg3vq0jbl
|
||||
@ -1,548 +0,0 @@
|
||||
[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/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/platform/platform.tscn" id="6_eatmm"]
|
||||
[ext_resource type="PackedScene" uid="uid://c7brdhj8ybu1y" path="res://UI/popup/task_development/gameplay/gameplay.tscn" id="7_xfbvu"]
|
||||
[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/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"]
|
||||
|
||||
[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
|
||||
@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=10 format=3 uid="uid://b5npsmec2fo2w"]
|
||||
[gd_scene load_steps=11 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"]
|
||||
@ -9,6 +9,7 @@
|
||||
[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"]
|
||||
[ext_resource type="PackedScene" uid="uid://b70jleefiaiwi" path="res://UI/popup/notice.tscn" id="10_5pged"]
|
||||
|
||||
[node name="task_development_start" type="Control" groups=["task_development"]]
|
||||
layout_mode = 3
|
||||
@ -62,15 +63,6 @@ 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")
|
||||
|
||||
@ -84,4 +76,19 @@ back_ui_node_path = NodePath("../npc_select_1")
|
||||
[node name="npc_select_1" parent="." instance=ExtResource("9_qpnja")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
Suitable_position = ["项目总监", "策划", "美术设计师"]
|
||||
back_ui_node_path = NodePath("../main_plan")
|
||||
|
||||
[node name="notice_1" parent="." instance=ExtResource("10_5pged")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
notice_text = "资金不足"
|
||||
next_ui_node_path = NodePath("../main_plan")
|
||||
back_ui_node_path = NodePath("../main_plan")
|
||||
|
||||
[node name="notice_2" parent="." instance=ExtResource("10_5pged")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
notice_text = "资金不足"
|
||||
next_ui_node_path = NodePath("../npc_select_1")
|
||||
back_ui_node_path = NodePath("../npc_select_1")
|
||||
|
||||
@ -1,369 +0,0 @@
|
||||
# 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 +0,0 @@
|
||||
uid://do3rv2hocchy3
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,17 +0,0 @@
|
||||
[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")
|
||||
@ -29,6 +29,8 @@ func _ready():
|
||||
func show_up():
|
||||
GameState.pause_game()
|
||||
shared_workflow_data = GameState.get_value(gamestate_data_key)
|
||||
var original_money = GameState.get_value("money") # 记录初始Money
|
||||
shared_workflow_data["original_money"] = int(original_money)
|
||||
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:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user