优化 prop hud 逻辑
This commit is contained in:
parent
3be55f41e7
commit
740620a1d4
@ -175,10 +175,10 @@ func checkout_prop_inventory(character: String) -> void:
|
|||||||
else:
|
else:
|
||||||
printerr("checkout_prop_inventory: PropHud node not found")
|
printerr("checkout_prop_inventory: PropHud node not found")
|
||||||
|
|
||||||
|
# 无效参数
|
||||||
func get_current_prop(must_selected: bool) -> String:
|
func get_current_prop(_must_selected = null) -> String:
|
||||||
var prop_hud = get_prop_hud()
|
var prop_hud = get_prop_hud()
|
||||||
if prop_hud and (not must_selected or prop_hud.selected):
|
if prop_hud:
|
||||||
return prop_hud.inventory.current_item_key()
|
return prop_hud.inventory.current_item_key()
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
@ -3,6 +3,14 @@ class_name PropHud extends Control
|
|||||||
|
|
||||||
signal current_item_changed(prop_key: String)
|
signal current_item_changed(prop_key: String)
|
||||||
|
|
||||||
|
# 常量定义
|
||||||
|
const PROP_CONTAINER_X = 130.0
|
||||||
|
const PROP_CONTROL_X = 110.0
|
||||||
|
const TWEEN_DURATION = 0.5
|
||||||
|
const SHAKE_FPS = 15.0
|
||||||
|
const SHAKE_DURATION = 0.8
|
||||||
|
const SHAKE_DELTA = 12.0
|
||||||
|
|
||||||
@export_group("DebugItem")
|
@export_group("DebugItem")
|
||||||
@export var enable_item := false:
|
@export var enable_item := false:
|
||||||
set(value):
|
set(value):
|
||||||
@ -10,12 +18,18 @@ signal current_item_changed(prop_key: String)
|
|||||||
enable_item = false
|
enable_item = false
|
||||||
enable_prop_item(item_key)
|
enable_prop_item(item_key)
|
||||||
@export var item_key: String
|
@export var item_key: String
|
||||||
|
|
||||||
@export_group("Inventory")
|
@export_group("Inventory")
|
||||||
@export var inventory: PropInventory:
|
@export var inventory: PropInventory:
|
||||||
set(value):
|
set(value):
|
||||||
|
if inventory == value:
|
||||||
|
return
|
||||||
|
if inventory and inventory.current_item_changed.is_connected(_emit_changed):
|
||||||
|
inventory.current_item_changed.disconnect(_emit_changed)
|
||||||
inventory = value
|
inventory = value
|
||||||
if inventory and not inventory.current_item_changed.is_connected(_emit_changed):
|
if inventory and not inventory.current_item_changed.is_connected(_emit_changed):
|
||||||
inventory.current_item_changed.connect(_emit_changed)
|
inventory.current_item_changed.connect(_emit_changed)
|
||||||
|
|
||||||
@export_group("UI-UX")
|
@export_group("UI-UX")
|
||||||
@export var display_time := 2.5 # 不包含渐入渐出(约 0.6s)的时长
|
@export var display_time := 2.5 # 不包含渐入渐出(约 0.6s)的时长
|
||||||
@export var locked := false:
|
@export var locked := false:
|
||||||
@ -45,10 +59,8 @@ signal current_item_changed(prop_key: String)
|
|||||||
@onready var props_bag_scroll = %PropsBagScroll as ScrollContainer
|
@onready var props_bag_scroll = %PropsBagScroll as ScrollContainer
|
||||||
@onready var props_bag = %PropsBag as HBoxContainer
|
@onready var props_bag = %PropsBag as HBoxContainer
|
||||||
@onready var select_mark = %SelectMark as TextureRect
|
@onready var select_mark = %SelectMark as TextureRect
|
||||||
var prop_containers = [] #CenterContainer
|
|
||||||
const PROP_CONTAINER_X = 130.0
|
|
||||||
const PROP_CONTROL_X = 110.0
|
|
||||||
|
|
||||||
|
var prop_containers: Array[CenterContainer] = []
|
||||||
var items_dict := {}
|
var items_dict := {}
|
||||||
var items_description_dict = {}
|
var items_description_dict = {}
|
||||||
# 从配置文件加载 prop items
|
# 从配置文件加载 prop items
|
||||||
@ -62,10 +74,16 @@ var displaying = false
|
|||||||
var timer := Timer.new()
|
var timer := Timer.new()
|
||||||
var display_tween: Tween
|
var display_tween: Tween
|
||||||
var container_tween: Tween
|
var container_tween: Tween
|
||||||
|
var prop_blink: Tween
|
||||||
|
var tween_scroll: Tween
|
||||||
|
var shake_tween: Tween
|
||||||
|
|
||||||
# hud 是否监听快捷键
|
# hud 是否监听快捷键
|
||||||
var listening_hotkey = true
|
var listening_hotkey = true
|
||||||
|
|
||||||
|
# 缓存的占位符纹理
|
||||||
|
var placeholder_texture: Texture2D
|
||||||
|
|
||||||
|
|
||||||
func _emit_changed(prop_key := ""):
|
func _emit_changed(prop_key := ""):
|
||||||
if not selected:
|
if not selected:
|
||||||
@ -77,33 +95,43 @@ func _emit_changed(prop_key := ""):
|
|||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
if Engine.is_editor_hint():
|
if Engine.is_editor_hint():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# 初始化占位符纹理
|
||||||
|
placeholder_texture = preload("res://asset/art/ui/hud/placeholder.png")
|
||||||
|
|
||||||
# read prop containers
|
# read prop containers
|
||||||
for id in range(props_bag.get_child_count()):
|
for id in range(props_bag.get_child_count()):
|
||||||
var container = props_bag.get_child(id)
|
var container = props_bag.get_child(id)
|
||||||
prop_containers.append(container)
|
prop_containers.append(container)
|
||||||
container.get_child(0).get_child(0).gui_input.connect(_on_prop_gui_input.bind(id))
|
var button = container.get_child(0).get_child(0)
|
||||||
|
if button:
|
||||||
|
button.gui_input.connect(_on_prop_gui_input.bind(id))
|
||||||
|
|
||||||
display_prop.gui_input.connect(_on_prop_gui_input.bind(-1))
|
display_prop.gui_input.connect(_on_prop_gui_input.bind(-1))
|
||||||
|
|
||||||
_load_items_config_to_dict("ImportantPropItems")
|
_load_items_config_to_dict("ImportantPropItems")
|
||||||
_load_items_config_to_dict("PropItems")
|
_load_items_config_to_dict("PropItems")
|
||||||
_reload_cache_and_realign_display()
|
_reload_cache_and_realign_display()
|
||||||
|
|
||||||
selecting_bg.modulate.a = 0.0
|
selecting_bg.modulate.a = 0.0
|
||||||
prop_scroll.scroll_horizontal = PROP_CONTAINER_X
|
prop_scroll.scroll_horizontal = PROP_CONTAINER_X
|
||||||
props_bag_scroll.scroll_horizontal = 0.0
|
props_bag_scroll.scroll_horizontal = 0.0
|
||||||
props_bag_scroll.custom_minimum_size.x = 0.0
|
props_bag_scroll.custom_minimum_size.x = 0.0
|
||||||
# focus_exited.connect(_on_focus_exited)
|
|
||||||
# 存档更新时,从存档加载 prop
|
# 存档更新时,从存档加载 prop
|
||||||
ArchiveManager.archive_loaded.connect(_reload_cache_and_realign_display)
|
ArchiveManager.archive_loaded.connect(_reload_cache_and_realign_display)
|
||||||
|
|
||||||
# tween timer
|
# tween timer
|
||||||
timer.wait_time = display_time
|
timer.wait_time = display_time
|
||||||
timer.one_shot = true
|
timer.one_shot = true
|
||||||
timer.autostart = false
|
timer.autostart = false
|
||||||
timer.timeout.connect(_on_timer_timeout)
|
timer.timeout.connect(_on_timer_timeout)
|
||||||
add_child(timer)
|
add_child(timer)
|
||||||
|
|
||||||
# connect signals
|
# connect signals
|
||||||
left_btn.pressed.connect(on_left_pressed)
|
left_btn.pressed.connect(on_left_pressed)
|
||||||
right_btn.pressed.connect(on_right_pressed)
|
right_btn.pressed.connect(on_right_pressed)
|
||||||
title_label.modulate.a = 0.0
|
title_label.modulate.a = 0.0
|
||||||
# _toggle_btn_ability(false)
|
|
||||||
left_btn.modulate.a = 0.5
|
left_btn.modulate.a = 0.5
|
||||||
right_btn.modulate.a = 0.5
|
right_btn.modulate.a = 0.5
|
||||||
mouse_entered.connect(_on_mouse_entered)
|
mouse_entered.connect(_on_mouse_entered)
|
||||||
@ -111,51 +139,36 @@ func _ready() -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _load_items_config_to_dict(title: String):
|
func _load_items_config_to_dict(title: String):
|
||||||
|
if not item_config_res or not item_config_res.titles.has(title):
|
||||||
|
return
|
||||||
|
|
||||||
var id = item_config_res.titles[title]
|
var id = item_config_res.titles[title]
|
||||||
var current_line = item_config_res.lines[id]
|
var current_line = item_config_res.lines.get(id)
|
||||||
|
|
||||||
while current_line:
|
while current_line:
|
||||||
if current_line.has("tags") and current_line.has("translation_key"):
|
if current_line.has("tags") and current_line.has("translation_key"):
|
||||||
var wrapped_texture := "texture="
|
|
||||||
var wrapped_inspect := "inspect="
|
|
||||||
var texture_path = ""
|
var texture_path = ""
|
||||||
var inspect_path = ""
|
var inspect_path = ""
|
||||||
for t in current_line.tags:
|
|
||||||
if t.begins_with(wrapped_texture):
|
for tag in current_line.tags:
|
||||||
texture_path = t.replace(wrapped_texture, "").strip_edges()
|
if tag.begins_with("texture="):
|
||||||
elif t.begins_with(wrapped_inspect):
|
texture_path = tag.substr(8).strip_edges()
|
||||||
inspect_path = t.replace(wrapped_inspect, "").strip_edges()
|
elif tag.begins_with("inspect="):
|
||||||
|
inspect_path = tag.substr(8).strip_edges()
|
||||||
|
|
||||||
var item = PropItem.new()
|
var item = PropItem.new()
|
||||||
item.key = current_line.translation_key
|
item.key = current_line.translation_key
|
||||||
if texture_path:
|
if texture_path:
|
||||||
item.texture_path = path_prefix + texture_path
|
item.texture_path = path_prefix + texture_path
|
||||||
if inspect_path:
|
if inspect_path:
|
||||||
item.inspect_path = path_prefix + inspect_path
|
item.inspect_path = path_prefix + inspect_path
|
||||||
|
|
||||||
items_dict[item.key] = item
|
items_dict[item.key] = item
|
||||||
# # 检查是否是重要物品,如果是,则添加到 items_description_dict
|
|
||||||
items_description_dict[item.key] = tr(item.key + "_说明").replace("{br}", "\n")
|
items_description_dict[item.key] = tr(item.key + "_说明").replace("{br}", "\n")
|
||||||
|
|
||||||
# if item_config_res.titles.has(item.key):
|
|
||||||
# var important_item_line_id = item_config_res.titles[item.key]
|
|
||||||
# items_description_dict[item.key] = get_import_item_content(important_item_line_id)
|
|
||||||
if not current_line.has("next_id") or current_line.next_id == "end":
|
if not current_line.has("next_id") or current_line.next_id == "end":
|
||||||
break
|
break
|
||||||
current_line = item_config_res.lines[current_line.next_id]
|
current_line = item_config_res.lines.get(current_line.next_id)
|
||||||
|
|
||||||
|
|
||||||
# func get_import_item_content(line_id) -> String:
|
|
||||||
# var current_line = item_config_res.lines[line_id]
|
|
||||||
# var content = ""
|
|
||||||
# while current_line:
|
|
||||||
# if current_line.has("text"):
|
|
||||||
# if current_line.has("translation_key"):
|
|
||||||
# content += tr(current_line.translation_key) + "\n"
|
|
||||||
# else:
|
|
||||||
# content += current_line.text + "\n"
|
|
||||||
# if not current_line.has("next_id") or current_line.next_id == "end":
|
|
||||||
# break
|
|
||||||
# current_line = item_config_res.lines[current_line.next_id]
|
|
||||||
# content.replace("{br}", "\n")
|
|
||||||
# return content
|
|
||||||
|
|
||||||
|
|
||||||
func _reload_cache_and_realign_display() -> void:
|
func _reload_cache_and_realign_display() -> void:
|
||||||
@ -174,57 +187,90 @@ func checkout_inventory(character: String) -> void:
|
|||||||
_reload_cache_and_realign_display()
|
_reload_cache_and_realign_display()
|
||||||
|
|
||||||
|
|
||||||
func hide_hud():
|
const HUD_FADE_DURATION = 0.3
|
||||||
# 隐藏 hud 并静音
|
|
||||||
hide()
|
# 在变量定义区域添加
|
||||||
|
var hud_visibility_tween: Tween
|
||||||
|
|
||||||
|
func hide_hud(duration: float = HUD_FADE_DURATION):
|
||||||
|
if not visible:
|
||||||
|
return
|
||||||
listening_hotkey = false
|
listening_hotkey = false
|
||||||
|
# 清理之前的补间动画
|
||||||
|
if hud_visibility_tween and hud_visibility_tween.is_running():
|
||||||
|
hud_visibility_tween.kill()
|
||||||
|
# 创建渐变动画
|
||||||
|
hud_visibility_tween = create_tween()
|
||||||
|
hud_visibility_tween.tween_property(self, "modulate:a", 0.0, duration)
|
||||||
|
hud_visibility_tween.tween_callback(hide)
|
||||||
|
|
||||||
|
|
||||||
func display_hud():
|
func display_hud(duration: float = HUD_FADE_DURATION):
|
||||||
# 显示 hud 并取消静音
|
if visible and modulate.a >= 1.0:
|
||||||
show()
|
return
|
||||||
listening_hotkey = true
|
# 清理之前的补间动画
|
||||||
|
if hud_visibility_tween and hud_visibility_tween.is_running():
|
||||||
|
hud_visibility_tween.kill()
|
||||||
|
# 确保节点可见但透明
|
||||||
|
if not visible:
|
||||||
|
modulate.a = 0.0
|
||||||
|
show()
|
||||||
|
# 创建渐变动画
|
||||||
|
hud_visibility_tween = create_tween()
|
||||||
|
hud_visibility_tween.tween_property(self, "modulate:a", 1.0, duration)
|
||||||
|
hud_visibility_tween.tween_callback(func(): listening_hotkey = true)
|
||||||
|
|
||||||
|
|
||||||
func _load_texture_cache() -> void:
|
func _load_texture_cache() -> void:
|
||||||
if not inventory:
|
if not inventory:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# 移除无效纹理
|
||||||
|
var keys_to_remove = []
|
||||||
for k in cached_inventory_textures:
|
for k in cached_inventory_textures:
|
||||||
# remove invalid textures
|
|
||||||
if not k in inventory.enabled_items:
|
if not k in inventory.enabled_items:
|
||||||
cached_inventory_textures.erase(k)
|
keys_to_remove.append(k)
|
||||||
|
|
||||||
|
for k in keys_to_remove:
|
||||||
|
cached_inventory_textures.erase(k)
|
||||||
|
|
||||||
|
# 加载新纹理
|
||||||
for key in inventory.enabled_items:
|
for key in inventory.enabled_items:
|
||||||
if cached_inventory_textures.has(key):
|
if cached_inventory_textures.has(key):
|
||||||
continue
|
continue
|
||||||
# 以 items_dict 为准,如果 enabled_items 中的 key 不存在,则删除
|
|
||||||
if not key in items_dict:
|
if not items_dict.has(key):
|
||||||
inventory.disable_item(key)
|
inventory.disable_item(key)
|
||||||
printerr(
|
printerr(
|
||||||
"PropHud _load_texture_cache: key not found in items_dict:", key, ". remove item."
|
"PropHud _load_texture_cache: key not found in items_dict:", key, ". remove item."
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
var path = items_dict[key].texture_path
|
var path = items_dict[key].texture_path
|
||||||
if not path:
|
if not path:
|
||||||
var placeholder = preload("res://asset/art/ui/hud/placeholder.png")
|
cached_inventory_textures[key] = placeholder_texture
|
||||||
cached_inventory_textures[key] = placeholder
|
|
||||||
print("Cache load prop placeholder key=", key)
|
print("Cache load prop placeholder key=", key)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
var texture = load(path) as Texture2D
|
var texture = load(path) as Texture2D
|
||||||
if texture:
|
if texture:
|
||||||
if GlobalConfig.DEBUG:
|
if GlobalConfig.DEBUG:
|
||||||
print("Cache load prop texture key=", key)
|
print("Cache load prop texture key=", key)
|
||||||
cached_inventory_textures[key] = texture
|
cached_inventory_textures[key] = texture
|
||||||
|
|
||||||
# wrap index
|
# wrap index
|
||||||
inventory.current_index = wrapi(inventory.current_index, 0, inventory.enabled_items.size())
|
if inventory.enabled_items.size() > 0:
|
||||||
|
inventory.current_index = wrapi(inventory.current_index, 0, inventory.enabled_items.size())
|
||||||
|
|
||||||
|
|
||||||
func _update_prop_display_with_texture():
|
func _update_prop_display_with_texture():
|
||||||
if not inventory:
|
if not inventory:
|
||||||
return
|
return
|
||||||
|
|
||||||
var key = ""
|
var key = ""
|
||||||
# 在没有道具时,展示空手 placeholder
|
# 在没有道具时,展示空手 placeholder
|
||||||
if inventory.enabled_items.is_empty():
|
if inventory.enabled_items.is_empty():
|
||||||
display_prop.texture_normal = preload("res://asset/art/ui/hud/placeholder.png")
|
display_prop.texture_normal = placeholder_texture
|
||||||
display_prop.size = Vector2(PROP_CONTROL_X, PROP_CONTROL_X)
|
display_prop.size = Vector2(PROP_CONTROL_X, PROP_CONTROL_X)
|
||||||
display_prop.scale = Vector2(1.0, 1.0)
|
display_prop.scale = Vector2(1.0, 1.0)
|
||||||
title_label.text = tr("prop_空手")
|
title_label.text = tr("prop_空手")
|
||||||
@ -232,36 +278,48 @@ func _update_prop_display_with_texture():
|
|||||||
key = inventory.current_item_key()
|
key = inventory.current_item_key()
|
||||||
_display_texture_by_key(display_prop, key)
|
_display_texture_by_key(display_prop, key)
|
||||||
title_label.text = tr(key)
|
title_label.text = tr(key)
|
||||||
|
|
||||||
# 如果当前是 prop_小猫玩具完整,尝试点亮玩家的灯效;否则无需点亮
|
# 如果当前是 prop_小猫玩具完整,尝试点亮玩家的灯效;否则无需点亮
|
||||||
var player = SceneManager.get_player()
|
var player = SceneManager.get_player()
|
||||||
if player:
|
if player:
|
||||||
player.set_catty_light(key == "prop_小猫玩具完整")
|
player.set_catty_light(key == "prop_小猫玩具完整")
|
||||||
|
|
||||||
if GlobalConfig.DEBUG:
|
if GlobalConfig.DEBUG:
|
||||||
print("[PropHud] current display prop:", key)
|
print("[PropHud] current display prop:", key)
|
||||||
# 选中标记 select_mark; 如果被 free 掉,则重新创建
|
|
||||||
if select_mark and is_instance_valid(select_mark):
|
# 选中标记处理
|
||||||
var parent = select_mark.get_parent()
|
_update_select_mark()
|
||||||
if parent:
|
|
||||||
parent.remove_child(select_mark)
|
# bag更新
|
||||||
else:
|
|
||||||
select_mark = TextureRect.new()
|
|
||||||
select_mark.custom_minimum_size = Vector2(PROP_CONTAINER_X, PROP_CONTAINER_X)
|
|
||||||
select_mark.texture = preload("res://asset/art/ui/hud/select_mark.png")
|
|
||||||
# bag
|
|
||||||
for i in range(inventory.enabled_items.size()):
|
for i in range(inventory.enabled_items.size()):
|
||||||
var id = wrapi(i, 0, inventory.enabled_items.size())
|
var id = wrapi(i, 0, inventory.enabled_items.size())
|
||||||
var k = inventory.enabled_items[id]
|
var k = inventory.enabled_items[id]
|
||||||
var button = prop_containers[i].get_child(0).get_child(0) as TextureButton
|
var container = prop_containers[i]
|
||||||
|
var button = container.get_child(0).get_child(0) as TextureButton
|
||||||
_display_texture_by_key(button, k)
|
_display_texture_by_key(button, k)
|
||||||
if id == inventory.current_index:
|
if id == inventory.current_index:
|
||||||
prop_containers[i].get_child(0).add_child(select_mark)
|
container.get_child(0).add_child(select_mark)
|
||||||
|
|
||||||
prop_scroll.scroll_horizontal = PROP_CONTAINER_X
|
prop_scroll.scroll_horizontal = PROP_CONTAINER_X
|
||||||
# props_bag_scroll.scroll_horizontal = 0.0
|
|
||||||
|
|
||||||
|
|
||||||
func _display_texture_by_key(button, key) -> void:
|
func _update_select_mark():
|
||||||
if not key:
|
if not is_instance_valid(select_mark):
|
||||||
button.texture_normal = null
|
select_mark = TextureRect.new()
|
||||||
|
select_mark.custom_minimum_size = Vector2(PROP_CONTAINER_X, PROP_CONTAINER_X)
|
||||||
|
select_mark.texture = preload("res://asset/art/ui/hud/select_mark.png")
|
||||||
|
else:
|
||||||
|
var parent = select_mark.get_parent()
|
||||||
|
if parent:
|
||||||
|
parent.remove_child(select_mark)
|
||||||
|
|
||||||
|
|
||||||
|
func _display_texture_by_key(button: TextureButton, key: String) -> void:
|
||||||
|
if not key or not button:
|
||||||
|
if button:
|
||||||
|
button.texture_normal = null
|
||||||
|
return
|
||||||
|
if not items_dict.has(key):
|
||||||
return
|
return
|
||||||
var item = items_dict[key]
|
var item = items_dict[key]
|
||||||
var texture = cached_inventory_textures.get(item.key)
|
var texture = cached_inventory_textures.get(item.key)
|
||||||
@ -270,14 +328,15 @@ func _display_texture_by_key(button, key) -> void:
|
|||||||
texture = load(item.texture_path) as Texture2D
|
texture = load(item.texture_path) as Texture2D
|
||||||
if not texture:
|
if not texture:
|
||||||
printerr("PropHud _display_texture_by_key: No texture found for item:", item)
|
printerr("PropHud _display_texture_by_key: No texture found for item:", item)
|
||||||
|
return
|
||||||
else:
|
else:
|
||||||
cached_inventory_textures[item.key] = texture
|
cached_inventory_textures[item.key] = texture
|
||||||
button.texture_normal = texture
|
button.texture_normal = texture
|
||||||
var t_size = button.texture_normal.get_size()
|
var t_size = texture.get_size()
|
||||||
var max_x = max(t_size.x, t_size.y)
|
var max_dimension = max(t_size.x, t_size.y)
|
||||||
var p_scale = min(PROP_CONTROL_X / t_size.x, PROP_CONTROL_X / t_size.y)
|
var p_scale = min(PROP_CONTROL_X / t_size.x, PROP_CONTROL_X / t_size.y)
|
||||||
button.scale = Vector2(p_scale, p_scale)
|
button.scale = Vector2(p_scale, p_scale)
|
||||||
button.size = Vector2(max_x, max_x)
|
button.size = Vector2(max_dimension, max_dimension)
|
||||||
|
|
||||||
|
|
||||||
func on_left_pressed() -> void:
|
func on_left_pressed() -> void:
|
||||||
@ -305,34 +364,37 @@ func on_right_pressed() -> void:
|
|||||||
func _tween_container(left_to_right := true) -> void:
|
func _tween_container(left_to_right := true) -> void:
|
||||||
if container_tween and container_tween.is_running():
|
if container_tween and container_tween.is_running():
|
||||||
container_tween.kill()
|
container_tween.kill()
|
||||||
|
|
||||||
container_tween = create_tween()
|
container_tween = create_tween()
|
||||||
if left_to_right:
|
prop_scroll.scroll_horizontal = 2 * PROP_CONTAINER_X if left_to_right else 0.0
|
||||||
prop_scroll.scroll_horizontal = 2 * PROP_CONTAINER_X
|
|
||||||
else:
|
|
||||||
prop_scroll.scroll_horizontal = 0.0
|
|
||||||
# 通过 Head 与 Tail 占位符,实现滚动效果;否则会导致卡在边界上,无法滚动
|
|
||||||
container_tween.tween_property(prop_scroll, "scroll_horizontal", PROP_CONTAINER_X, 0.2)
|
container_tween.tween_property(prop_scroll, "scroll_horizontal", PROP_CONTAINER_X, 0.2)
|
||||||
|
|
||||||
|
|
||||||
func _on_prop_gui_input(event: InputEvent, id) -> void:
|
func _on_prop_gui_input(event: InputEvent, id: int) -> void:
|
||||||
if locked:
|
if locked or not event is InputEventMouseButton:
|
||||||
return
|
return
|
||||||
if event is InputEventMouseButton and event.is_pressed():
|
|
||||||
event = event as InputEventMouseButton
|
var mouse_event = event as InputEventMouseButton
|
||||||
if event.button_index == MOUSE_BUTTON_LEFT:
|
if not mouse_event.is_pressed():
|
||||||
|
return
|
||||||
|
|
||||||
|
match mouse_event.button_index:
|
||||||
|
MOUSE_BUTTON_LEFT:
|
||||||
_on_prop_pressed(id)
|
_on_prop_pressed(id)
|
||||||
elif event.button_index == MOUSE_BUTTON_RIGHT:
|
MOUSE_BUTTON_RIGHT:
|
||||||
_on_prop_inspected(id)
|
_on_prop_inspected(id)
|
||||||
|
|
||||||
|
|
||||||
func _on_prop_inspected(id := 0) -> void:
|
func _on_prop_inspected(id := 0) -> void:
|
||||||
if locked:
|
if locked:
|
||||||
return
|
return
|
||||||
|
|
||||||
var prop_key = ""
|
var prop_key = ""
|
||||||
if id >= 0:
|
if id >= 0 and id < inventory.enabled_items.size():
|
||||||
prop_key = inventory.enabled_items[id]
|
prop_key = inventory.enabled_items[id]
|
||||||
else:
|
else:
|
||||||
prop_key = inventory.current_item_key()
|
prop_key = inventory.current_item_key()
|
||||||
|
|
||||||
if prop_key:
|
if prop_key:
|
||||||
sfx_inspect.play()
|
sfx_inspect.play()
|
||||||
print("[PropHud] inspect prop:", prop_key)
|
print("[PropHud] inspect prop:", prop_key)
|
||||||
@ -342,37 +404,37 @@ func _on_prop_inspected(id := 0) -> void:
|
|||||||
func _on_prop_pressed(id := 0) -> void:
|
func _on_prop_pressed(id := 0) -> void:
|
||||||
if locked:
|
if locked:
|
||||||
return
|
return
|
||||||
|
|
||||||
sfx_click.play()
|
sfx_click.play()
|
||||||
if GlobalConfig.DEBUG:
|
if GlobalConfig.DEBUG:
|
||||||
print("PropHUD Panel pressed.")
|
print("PropHUD Panel pressed.")
|
||||||
|
|
||||||
focus_mode = FOCUS_ALL
|
focus_mode = FOCUS_ALL
|
||||||
grab_focus()
|
grab_focus()
|
||||||
selected = true
|
selected = true
|
||||||
if id >= 0:
|
|
||||||
|
if id >= 0 and id < inventory.enabled_items.size():
|
||||||
inventory.current_index = id
|
inventory.current_index = id
|
||||||
|
|
||||||
_update_prop_display_with_texture()
|
_update_prop_display_with_texture()
|
||||||
_mouse_moved_on_listening(true)
|
_mouse_moved_on_listening(true)
|
||||||
|
|
||||||
|
|
||||||
var prop_blink: Tween
|
|
||||||
var tween_scroll: Tween
|
|
||||||
|
|
||||||
|
|
||||||
func _toggle_scroll(fold := true) -> void:
|
func _toggle_scroll(fold := true) -> void:
|
||||||
if prop_blink and prop_blink.is_running():
|
if prop_blink and prop_blink.is_running():
|
||||||
prop_blink.kill()
|
prop_blink.kill()
|
||||||
if tween_scroll and tween_scroll.is_running():
|
if tween_scroll and tween_scroll.is_running():
|
||||||
tween_scroll.kill()
|
tween_scroll.kill()
|
||||||
# PROP_CONTAINER_X + 10. 为hud的两侧留出的空间
|
|
||||||
if fold:
|
if fold:
|
||||||
# kill blink
|
# kill blink
|
||||||
select_mark.modulate.a = 1.0
|
select_mark.modulate.a = 1.0
|
||||||
selecting_bg.modulate.a = 0.0
|
selecting_bg.modulate.a = 0.0
|
||||||
# fold
|
# fold
|
||||||
tween_scroll = create_tween()
|
tween_scroll = create_tween()
|
||||||
tween_scroll.tween_property(props_bag_scroll, "custom_minimum_size:x", 0.0, 0.5)
|
tween_scroll.tween_property(props_bag_scroll, "custom_minimum_size:x", 0.0, TWEEN_DURATION)
|
||||||
tween_scroll.parallel().tween_property(
|
tween_scroll.parallel().tween_property(
|
||||||
hud_rect, "custom_minimum_size:x", PROP_CONTAINER_X + 10., 0.5
|
hud_rect, "custom_minimum_size:x", PROP_CONTAINER_X + 10., TWEEN_DURATION
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# blink
|
# blink
|
||||||
@ -388,12 +450,17 @@ func _toggle_scroll(fold := true) -> void:
|
|||||||
prop_blink.parallel().tween_property(selecting_bg, "modulate:a", .6, 1.).set_ease(
|
prop_blink.parallel().tween_property(selecting_bg, "modulate:a", .6, 1.).set_ease(
|
||||||
Tween.EASE_IN_OUT
|
Tween.EASE_IN_OUT
|
||||||
)
|
)
|
||||||
|
|
||||||
# unfold
|
# unfold
|
||||||
var bag_x = prop_containers.size() * PROP_CONTAINER_X
|
var bag_x = prop_containers.size() * PROP_CONTAINER_X
|
||||||
var hud_x = bag_x + PROP_CONTAINER_X + 10.
|
var hud_x = bag_x + PROP_CONTAINER_X + 10.
|
||||||
tween_scroll = create_tween()
|
tween_scroll = create_tween()
|
||||||
tween_scroll.tween_property(props_bag_scroll, "custom_minimum_size:x", bag_x, 0.5)
|
tween_scroll.tween_property(
|
||||||
tween_scroll.parallel().tween_property(hud_rect, "custom_minimum_size:x", hud_x, 0.5)
|
props_bag_scroll, "custom_minimum_size:x", bag_x, TWEEN_DURATION
|
||||||
|
)
|
||||||
|
tween_scroll.parallel().tween_property(
|
||||||
|
hud_rect, "custom_minimum_size:x", hud_x, TWEEN_DURATION
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
func _on_mouse_entered() -> void:
|
func _on_mouse_entered() -> void:
|
||||||
@ -410,9 +477,11 @@ func _on_mouse_exited() -> void:
|
|||||||
func _mouse_moved_on_listening(unfold_scroll := false) -> void:
|
func _mouse_moved_on_listening(unfold_scroll := false) -> void:
|
||||||
if unfold_scroll:
|
if unfold_scroll:
|
||||||
_toggle_scroll(false)
|
_toggle_scroll(false)
|
||||||
|
|
||||||
if not displaying:
|
if not displaying:
|
||||||
_toggle_details(true)
|
_toggle_details(true)
|
||||||
return
|
return
|
||||||
|
|
||||||
timer.start(display_time)
|
timer.start(display_time)
|
||||||
|
|
||||||
|
|
||||||
@ -424,6 +493,7 @@ func _on_timer_timeout() -> void:
|
|||||||
func _unhandled_input(event: InputEvent) -> void:
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
if locked or not listening_hotkey:
|
if locked or not listening_hotkey:
|
||||||
return
|
return
|
||||||
|
|
||||||
if event.is_action_pressed("prop_left"):
|
if event.is_action_pressed("prop_left"):
|
||||||
on_left_pressed()
|
on_left_pressed()
|
||||||
get_viewport().set_input_as_handled()
|
get_viewport().set_input_as_handled()
|
||||||
@ -431,17 +501,21 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||||||
on_right_pressed()
|
on_right_pressed()
|
||||||
get_viewport().set_input_as_handled()
|
get_viewport().set_input_as_handled()
|
||||||
elif event is InputEventMouseButton:
|
elif event is InputEventMouseButton:
|
||||||
if event.button_index == MOUSE_BUTTON_WHEEL_DOWN and event.pressed:
|
var mouse_event = event as InputEventMouseButton
|
||||||
on_left_pressed()
|
if mouse_event.pressed:
|
||||||
get_viewport().set_input_as_handled()
|
match mouse_event.button_index:
|
||||||
elif event.button_index == MOUSE_BUTTON_WHEEL_UP and event.pressed:
|
MOUSE_BUTTON_WHEEL_DOWN:
|
||||||
on_right_pressed()
|
on_left_pressed()
|
||||||
get_viewport().set_input_as_handled()
|
get_viewport().set_input_as_handled()
|
||||||
|
MOUSE_BUTTON_WHEEL_UP:
|
||||||
|
on_right_pressed()
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
|
|
||||||
|
|
||||||
func _input(event: InputEvent) -> void:
|
func _input(event: InputEvent) -> void:
|
||||||
if locked:
|
if locked:
|
||||||
return
|
return
|
||||||
|
|
||||||
if listen_mouse and (event is InputEventMouseMotion or event is InputEventScreenTouch):
|
if listen_mouse and (event is InputEventMouseMotion or event is InputEventScreenTouch):
|
||||||
_mouse_moved_on_listening()
|
_mouse_moved_on_listening()
|
||||||
|
|
||||||
@ -462,7 +536,6 @@ func _toggle_details(display := true) -> void:
|
|||||||
display_tween.parallel().tween_property(title_label, "modulate:a", 0.0, 0.6)
|
display_tween.parallel().tween_property(title_label, "modulate:a", 0.0, 0.6)
|
||||||
display_tween.parallel().tween_property(left_btn, "modulate:a", 0.5, 0.5)
|
display_tween.parallel().tween_property(left_btn, "modulate:a", 0.5, 0.5)
|
||||||
display_tween.parallel().tween_property(right_btn, "modulate:a", 0.5, 0.5)
|
display_tween.parallel().tween_property(right_btn, "modulate:a", 0.5, 0.5)
|
||||||
# display_tween.tween_callback(_toggle_btn_ability.bind(false))
|
|
||||||
timer.stop()
|
timer.stop()
|
||||||
|
|
||||||
|
|
||||||
@ -474,11 +547,14 @@ func _toggle_btn_ability(v: bool) -> void:
|
|||||||
func enable_important_item(prop_key: String, display_inspector: bool) -> void:
|
func enable_important_item(prop_key: String, display_inspector: bool) -> void:
|
||||||
if not inventory or not prop_key:
|
if not inventory or not prop_key:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not items_dict.has(prop_key):
|
if not items_dict.has(prop_key):
|
||||||
push_error("ImportantPropItem not found! key=" + prop_key)
|
push_error("ImportantPropItem not found! key=" + prop_key)
|
||||||
return
|
return
|
||||||
|
|
||||||
inventory.enable_important_item(prop_key)
|
inventory.enable_important_item(prop_key)
|
||||||
SceneManager.pop_notification("ui_notify_important_item_update")
|
SceneManager.pop_notification("ui_notify_important_item_update")
|
||||||
|
|
||||||
if display_inspector:
|
if display_inspector:
|
||||||
sfx_inspect.play()
|
sfx_inspect.play()
|
||||||
inspect_item(prop_key, true, true)
|
inspect_item(prop_key, true, true)
|
||||||
@ -488,13 +564,17 @@ func enable_prop_item(prop_key: String, inspect := true) -> void:
|
|||||||
if not inventory or not prop_key:
|
if not inventory or not prop_key:
|
||||||
printerr("PropHUD Enable prop item: No inventory or prop_key provided.")
|
printerr("PropHUD Enable prop item: No inventory or prop_key provided.")
|
||||||
return
|
return
|
||||||
|
|
||||||
if not items_dict.has(prop_key):
|
if not items_dict.has(prop_key):
|
||||||
push_error("PropItem not found! key=" + prop_key)
|
push_error("PropItem not found! key=" + prop_key)
|
||||||
return
|
return
|
||||||
|
|
||||||
inventory.enable_item(prop_key)
|
inventory.enable_item(prop_key)
|
||||||
_reload_cache_and_realign_display()
|
_reload_cache_and_realign_display()
|
||||||
|
|
||||||
if GlobalConfig.DEBUG:
|
if GlobalConfig.DEBUG:
|
||||||
print("PropHUD Enable prop item:", prop_key)
|
print("PropHUD Enable prop item:", prop_key)
|
||||||
|
|
||||||
if inspect:
|
if inspect:
|
||||||
sfx_new_prop.play()
|
sfx_new_prop.play()
|
||||||
inspect_item(prop_key)
|
inspect_item(prop_key)
|
||||||
@ -502,27 +582,31 @@ func enable_prop_item(prop_key: String, inspect := true) -> void:
|
|||||||
|
|
||||||
func inspect_item(prop_key: String, display_obtained := true, as_important_item := false):
|
func inspect_item(prop_key: String, display_obtained := true, as_important_item := false):
|
||||||
var inspector = SceneManager.get_inspector()
|
var inspector = SceneManager.get_inspector()
|
||||||
if inspector:
|
if not inspector or not items_dict.has(prop_key):
|
||||||
var texture_path = items_dict[prop_key].texture_path
|
return
|
||||||
var inspect_path = items_dict[prop_key].inspect_path
|
|
||||||
# 是否有独立的 inspect 图片
|
var item = items_dict[prop_key]
|
||||||
if inspect_path:
|
var texture: Texture2D = null
|
||||||
var texture = load(inspect_path) as Texture2D
|
var is_inspect_texture = false
|
||||||
inspector.pop_prop_inspection(
|
|
||||||
prop_key, texture, false, display_obtained, as_important_item
|
# 检查是否有独立的 inspect 图片
|
||||||
)
|
if item.inspect_path:
|
||||||
else:
|
texture = load(item.inspect_path) as Texture2D
|
||||||
var texture = cached_inventory_textures.get(prop_key)
|
is_inspect_texture = true
|
||||||
if not texture:
|
else:
|
||||||
texture = load(texture_path) as Texture2D
|
texture = cached_inventory_textures.get(prop_key)
|
||||||
if texture:
|
if not texture and item.texture_path:
|
||||||
cached_inventory_textures[prop_key] = texture
|
texture = load(item.texture_path) as Texture2D
|
||||||
else:
|
if texture:
|
||||||
printerr("prophud inspect_item invalid texture_path:", texture_path)
|
cached_inventory_textures[prop_key] = texture
|
||||||
return
|
|
||||||
inspector.pop_prop_inspection(
|
if not texture:
|
||||||
prop_key, texture, true, display_obtained, as_important_item
|
printerr("prophud inspect_item invalid texture for key:", prop_key)
|
||||||
)
|
return
|
||||||
|
|
||||||
|
inspector.pop_prop_inspection(
|
||||||
|
prop_key, texture, not is_inspect_texture, display_obtained, as_important_item
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
func disable_prop_item(prop_key: String) -> void:
|
func disable_prop_item(prop_key: String) -> void:
|
||||||
@ -533,16 +617,21 @@ func disable_prop_item(prop_key: String) -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _align_container_size() -> void:
|
func _align_container_size() -> void:
|
||||||
# 判断是否需要添加新的 prop container
|
if not inventory:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 添加新容器
|
||||||
while inventory.enabled_items.size() > prop_containers.size():
|
while inventory.enabled_items.size() > prop_containers.size():
|
||||||
append_prop_container()
|
append_prop_container()
|
||||||
# 判断是否需要删除 prop container,不保留余数
|
|
||||||
|
# 删除多余容器
|
||||||
while inventory.enabled_items.size() < prop_containers.size():
|
while inventory.enabled_items.size() < prop_containers.size():
|
||||||
remove_prop_container()
|
remove_prop_container()
|
||||||
|
|
||||||
if displaying:
|
if displaying:
|
||||||
_mouse_moved_on_listening()
|
_mouse_moved_on_listening()
|
||||||
# 如果正在展示,则更新 scroll 长度
|
# 如果正在展示,则更新 scroll 长度
|
||||||
if displaying and props_bag_scroll.custom_minimum_size.x > 0.0:
|
if props_bag_scroll.custom_minimum_size.x > 0.0:
|
||||||
_toggle_scroll(false)
|
_toggle_scroll(false)
|
||||||
|
|
||||||
|
|
||||||
@ -550,58 +639,65 @@ func append_prop_container() -> void:
|
|||||||
var container = CenterContainer.new()
|
var container = CenterContainer.new()
|
||||||
container.custom_minimum_size = Vector2(PROP_CONTAINER_X, PROP_CONTAINER_X)
|
container.custom_minimum_size = Vector2(PROP_CONTAINER_X, PROP_CONTAINER_X)
|
||||||
container.set_anchors_preset(Control.PRESET_FULL_RECT)
|
container.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
prop_containers.append(container)
|
|
||||||
var control = Control.new()
|
var control = Control.new()
|
||||||
control.custom_minimum_size = Vector2(PROP_CONTROL_X, PROP_CONTROL_X)
|
control.custom_minimum_size = Vector2(PROP_CONTROL_X, PROP_CONTROL_X)
|
||||||
control.set_anchors_preset(Control.PRESET_FULL_RECT)
|
control.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
container.add_child(control)
|
container.add_child(control)
|
||||||
|
|
||||||
var prop = TextureButton.new()
|
var prop = TextureButton.new()
|
||||||
prop.stretch_mode = TextureButton.STRETCH_KEEP_ASPECT_CENTERED
|
prop.stretch_mode = TextureButton.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
control.add_child(prop)
|
control.add_child(prop)
|
||||||
# 添加到 hbox: container -> control -> prop
|
|
||||||
props_bag.add_child(container)
|
props_bag.add_child(container)
|
||||||
prop.gui_input.connect(_on_prop_gui_input.bind(prop_containers.size() - 1))
|
prop_containers.append(container)
|
||||||
|
|
||||||
|
var index = prop_containers.size() - 1
|
||||||
|
prop.gui_input.connect(_on_prop_gui_input.bind(index))
|
||||||
|
|
||||||
|
|
||||||
func remove_prop_container() -> void:
|
func remove_prop_container() -> void:
|
||||||
if prop_containers.size() == 0:
|
if prop_containers.is_empty():
|
||||||
return
|
return
|
||||||
|
|
||||||
var container = prop_containers.pop_back()
|
var container = prop_containers.pop_back()
|
||||||
props_bag.remove_child(container)
|
if container and is_instance_valid(container):
|
||||||
container.queue_free()
|
props_bag.remove_child(container)
|
||||||
|
container.queue_free()
|
||||||
|
|
||||||
|
|
||||||
var shake_tween
|
|
||||||
|
|
||||||
|
|
||||||
# 使用无效道具,抖动提示
|
|
||||||
func on_toggle_invalid_prop():
|
func on_toggle_invalid_prop():
|
||||||
if not inventory or not inventory.current_item_key():
|
if not inventory or not inventory.current_item_key():
|
||||||
return
|
return
|
||||||
|
|
||||||
if GlobalConfig.DEBUG:
|
if GlobalConfig.DEBUG:
|
||||||
print("使用无效道具. invalid_prop shake. current prop:", inventory.current_item_key())
|
print("使用无效道具. invalid_prop shake. current prop:", inventory.current_item_key())
|
||||||
if shake_tween:
|
|
||||||
|
if shake_tween and shake_tween.is_running():
|
||||||
shake_tween.kill()
|
shake_tween.kill()
|
||||||
# 抖动效果,逐渐减弱
|
|
||||||
|
# 抖动效果
|
||||||
shake_tween = create_tween()
|
shake_tween = create_tween()
|
||||||
var fps := 15.0
|
var count = int(SHAKE_DURATION * SHAKE_FPS)
|
||||||
var duration := 0.8
|
var delta_t = 1.0 / SHAKE_FPS
|
||||||
var delta := 12.0
|
|
||||||
var origin_pos = Vector2.ZERO
|
var origin_pos = Vector2.ZERO
|
||||||
var count = int(duration * fps)
|
|
||||||
var delta_t = 1.0 / fps
|
|
||||||
var prop = display_prop
|
var prop = display_prop
|
||||||
# var prop = prop_containers[0].get_child(0)
|
|
||||||
prop.modulate = Color(1.0, 0.6, 0.6, 1.0)
|
prop.modulate = Color(1.0, 0.6, 0.6, 1.0)
|
||||||
|
|
||||||
for i in range(count):
|
for i in range(count):
|
||||||
var offset = Vector2(randf_range(-delta, delta), randf_range(-delta, delta)) * exp(-i)
|
var decay = exp(-i)
|
||||||
|
var offset = Vector2(
|
||||||
|
randf_range(-SHAKE_DELTA, SHAKE_DELTA) * decay,
|
||||||
|
randf_range(-SHAKE_DELTA, SHAKE_DELTA) * decay
|
||||||
|
)
|
||||||
shake_tween.tween_property(prop, "position", origin_pos + offset, delta_t).set_trans(
|
shake_tween.tween_property(prop, "position", origin_pos + offset, delta_t).set_trans(
|
||||||
Tween.TRANS_CUBIC
|
Tween.TRANS_CUBIC
|
||||||
)
|
)
|
||||||
|
|
||||||
shake_tween.tween_callback(_reset_prop_modulate)
|
shake_tween.tween_callback(_reset_prop_modulate)
|
||||||
|
|
||||||
|
|
||||||
func _reset_prop_modulate():
|
func _reset_prop_modulate():
|
||||||
var prop = display_prop
|
if display_prop:
|
||||||
# var prop = prop_containers[0].get_child(0)
|
display_prop.modulate = Color.WHITE
|
||||||
prop.modulate = Color(1.0, 1.0, 1.0, 1.0)
|
|
||||||
|
Loading…
Reference in New Issue
Block a user