优化 npc hook speaking 表现

This commit is contained in:
cakipaul 2025-07-17 16:43:30 +08:00
parent 4e3183b013
commit d465857737
6 changed files with 60 additions and 26 deletions

View File

@ -1,6 +1,7 @@
class_name GlobalConfig extends Resource class_name GlobalConfig extends Resource
static var DEBUG = false static var DEBUG = false
const DEBUG_CHARACTER_PREFIX = "[debug]"
# .res would be binary encoded, .tres is text encoded # .res would be binary encoded, .tres is text encoded
const RES_FILE_FORMAT = ".tres" const RES_FILE_FORMAT = ".tres"

View File

@ -148,7 +148,7 @@ func pop_debug_dialog_info(character: String, content: String) -> void:
debug_balloon_node.queue_free() debug_balloon_node.queue_free()
var title = "title" var title = "title"
var body = "~ " + title + "\n" var body = "~ " + title + "\n"
body += character + ": " + content + "\n" body += GlobalConfig.DEBUG_CHARACTER_PREFIX + character + ": " + content + "\n"
body += "=> END" body += "=> END"
var res = DialogueManager.create_resource_from_text(body) var res = DialogueManager.create_resource_from_text(body)
debug_balloon_node = DialogueManager.show_dialogue_balloon_scene( debug_balloon_node = DialogueManager.show_dialogue_balloon_scene(

View File

@ -44,6 +44,10 @@ enum SpeakingSignMode { HIDDEN = 0, SILENT = 1, SPEAKING = 2 }
if is_node_ready(): if is_node_ready():
_update_collision_shape() _update_collision_shape()
# DialogueLine 播放 hook_character_name 的对话时,显示 speaking 标志
# 为空时不 hook
@export var hook_character_name := ""
# 节点引用 # 节点引用
@onready var speaking_animation = %SpeakingAnimationPlayer @onready var speaking_animation = %SpeakingAnimationPlayer
@onready var speaking_sign = %SpeakingSign2D as Node2D @onready var speaking_sign = %SpeakingSign2D as Node2D
@ -89,6 +93,34 @@ func _ready() -> void:
_setup_game_mode() _setup_game_mode()
_align_signs_status() _align_signs_status()
DialogueManager.dialogue_ended.connect(_on_dialogue_ended)
DialogueManager.got_dialogue.connect(_on_got_dialogue)
var _last_line_session := -1
func _on_got_dialogue(line: DialogueLine) -> void:
if not hook_character_name:
return
# 去除 debug
if line.character.begins_with(GlobalConfig.DEBUG_CHARACTER_PREFIX):
return
# 其他角色说话时会自动停止
if line.character == hook_character_name:
# 未在 speaking 状态
if _last_line_session < 0:
_last_line_session = hook_speaking()
if GlobalConfig.DEBUG:
print("[Npc2D] Hook speaking for character: ", hook_character_name, " line.character:", line.character)
elif _last_line_session >= 0:
if GlobalConfig.DEBUG:
print("[Npc2D] Unhook speaking for character: ", hook_character_name, " line.character:", line.character)
unhook_speaking(_last_line_session)
_last_line_session = -1
# dialog 结束时会自动 unhook 从 line 播放的 speaking
func _on_dialogue_ended(_res) -> void:
unhook_speaking(_last_line_session)
func _initialize_components() -> void: func _initialize_components() -> void:
@ -214,6 +246,9 @@ func _on_visibility_changed() -> void:
func _align_signs_status() -> void: func _align_signs_status() -> void:
if not is_node_ready(): if not is_node_ready():
return return
if Engine.is_editor_hint():
_setup_editor_preview()
return
var is_active = enabled and is_visible_in_tree() var is_active = enabled and is_visible_in_tree()
if sign_mark: if sign_mark:
sign_mark.enabled = is_active sign_mark.enabled = is_active
@ -281,7 +316,7 @@ func hook_speaking() -> int:
func unhook_speaking(session_id: int = -1) -> void: func unhook_speaking(session_id: int = -1) -> void:
# 退出强制播放模式 # 退出强制播放模式
# 参数: # 参数:
# session_id: hook会话ID如果不匹配则忽略此次unhook # session_id: hook会话ID如果不匹配则忽略此次unhook
# 如果已经不在hook状态或session_id不匹配则忽略 # 如果已经不在hook状态或session_id不匹配则忽略
if not is_hooked or (session_id != -1 and session_id != hook_id): if not is_hooked or (session_id != -1 and session_id != hook_id):
return return
@ -305,7 +340,7 @@ func _cancel_hook() -> void:
# 新增检查是否正在hook播放 # 新增检查是否正在hook播放
func is_hook_speaking() -> bool: func is_hook_speaking() -> bool:
"""返回当前是否处于强制播放状态""" # 返回当前是否处于强制播放状态
return is_hooked return is_hooked

View File

@ -94,10 +94,8 @@ func pre_game_intro():
var p = $"../DeployLayer/四小孩画鬼差的对话ambush/FocusPoint" var p = $"../DeployLayer/四小孩画鬼差的对话ambush/FocusPoint"
camera.focus_node(p, 3.0) camera.focus_node(p, 3.0)
await Util.wait(2.0) await Util.wait(2.0)
_hook_npc3_speaking()
DialogueManager.show_dialogue_balloon(dialogue_c01, "c01_s06_四个小孩画鬼差的对话") DialogueManager.show_dialogue_balloon(dialogue_c01, "c01_s06_四个小孩画鬼差的对话")
await DialogueManager.dialogue_ended await DialogueManager.dialogue_ended
_unhook_npc3_speaking()
# 重置镜头 # 重置镜头
SceneManager.focus_player_and_reset_zoom(2.5) SceneManager.focus_player_and_reset_zoom(2.5)
await Util.wait(2.5) await Util.wait(2.5)
@ -120,25 +118,28 @@ func game_intro() -> void:
# 只有 1、2 是跟班3 不参与 # 只有 1、2 是跟班3 不参与
# standing_kid3.play("【站立小孩-3】转身") # standing_kid3.play("【站立小孩-3】转身")
game_kid.play("【胖小孩背着残疾小孩】侧面呼吸") game_kid.play("【胖小孩背着残疾小孩】侧面呼吸")
# 转身后,大胖 speaking sign 也跟随过去
game_kid.get_node("Npc大胖").position.x += 18
game_kid.get_node("Npc对话3").position.x -= 5
SceneManager.get_player().set_facing_direction(Vector2.LEFT) SceneManager.get_player().set_facing_direction(Vector2.LEFT)
SceneManager.freeze_player(0) SceneManager.freeze_player(0)
# DialogueManager.show_dialogue_balloon( # DialogueManager.show_dialogue_balloon(
# dialogue_c01, "c01_s06_谈论鬼差与猫鼠游戏", [GlobalConfig.DIALOG_IGNORE_INPUT] # dialogue_c01, "c01_s06_谈论鬼差与猫鼠游戏", [GlobalConfig.DIALOG_IGNORE_INPUT]
# ) # )
_hook_npc3_speaking()
DialogueManager.show_dialogue_balloon(dialogue_c01, "c01_s06_谈论鬼差与猫鼠游戏") DialogueManager.show_dialogue_balloon(dialogue_c01, "c01_s06_谈论鬼差与猫鼠游戏")
await DialogueManager.dialogue_ended await DialogueManager.dialogue_ended
_game_counting_down() # BGM 开始后小段对话
func _game_counting_down(_res = null):
$"Sfx猫鼠游戏".play() $"Sfx猫鼠游戏".play()
DialogueManager.show_dialogue_balloon(dialogue_c01, "c01_s06_猫鼠游戏BGM开始") DialogueManager.show_dialogue_balloon(dialogue_c01, "c01_s06_猫鼠游戏BGM开始")
await DialogueManager.dialogue_ended await DialogueManager.dialogue_ended
_unhook_npc3_speaking()
# 重置镜头 # 重置镜头
SceneManager.focus_player_and_reset_zoom(2.5) SceneManager.focus_player_and_reset_zoom(2.5)
SceneManager.release_player() SceneManager.release_player()
# 倒计时开始,无需展示 hook speaking 气泡
game_kid.get_node("Npc对话3").hook_character_name = ""
game_kid.get_node("Npc对话3").unhook_speaking()
game_kid.get_node("Npc大胖").hook_character_name = ""
game_kid.get_node("Npc大胖").unhook_speaking()
DialogueManager.show_dialogue_balloon(dialogue_c01, "c01_s06_猫鼠游戏倒计时") DialogueManager.show_dialogue_balloon(dialogue_c01, "c01_s06_猫鼠游戏倒计时")
# 禁止玩家向左移动,同时可以使右侧腾出空间,玩家可以继续向右移动 # 禁止玩家向左移动,同时可以使右侧腾出空间,玩家可以继续向右移动
var player = SceneManager.get_player() as MainPlayer var player = SceneManager.get_player() as MainPlayer
@ -150,14 +151,6 @@ func _game_counting_down(_res = null):
cat.get_node("猫咪嘶吼音效").play() cat.get_node("猫咪嘶吼音效").play()
func _hook_npc3_speaking(_res = null) -> void:
game_kid.get_node("Npc对话3").hook_speaking()
func _unhook_npc3_speaking(_res = null) -> void:
game_kid.get_node("Npc对话3").unhook_speaking()
# 玩家与三个小孩的互动计数 # 玩家与三个小孩的互动计数
func _on_talked(id: int): func _on_talked(id: int):
#talk count #talk count

View File

@ -448,6 +448,7 @@ shape = SubResource("RectangleShape2D_7cdhx")
[node name="Npc对话1" parent="Ground/DeployLayer/【站立小孩-1】" instance=ExtResource("24_phfqg")] [node name="Npc对话1" parent="Ground/DeployLayer/【站立小孩-1】" instance=ExtResource("24_phfqg")]
position = Vector2(0, 71) position = Vector2(0, 71)
speaking_sign_height = 39.23 speaking_sign_height = 39.23
hook_character_name = "小肉圆"
dialogue_title = "c01_s06_四个小孩_对话1" dialogue_title = "c01_s06_四个小孩_对话1"
[node name="【站立小孩-2】" parent="Ground/DeployLayer" index="15" instance=ExtResource("8_ouldg")] [node name="【站立小孩-2】" parent="Ground/DeployLayer" index="15" instance=ExtResource("8_ouldg")]
@ -511,6 +512,7 @@ shape = SubResource("RectangleShape2D_7cdhx")
[node name="Npc对话2" parent="Ground/DeployLayer/【站立小孩-2】" instance=ExtResource("24_phfqg")] [node name="Npc对话2" parent="Ground/DeployLayer/【站立小孩-2】" instance=ExtResource("24_phfqg")]
position = Vector2(2, 52) position = Vector2(2, 52)
speaking_sign_height = 34.95 speaking_sign_height = 34.95
hook_character_name = "小竹竿"
dialogue_title = "c01_s06_四个小孩_对话2" dialogue_title = "c01_s06_四个小孩_对话2"
[node name="【墙上黑猫】" parent="Ground/DeployLayer" index="16" instance=ExtResource("8_ouldg")] [node name="【墙上黑猫】" parent="Ground/DeployLayer" index="16" instance=ExtResource("8_ouldg")]
@ -631,10 +633,17 @@ enabled = false
shape = SubResource("RectangleShape2D_7cdhx") shape = SubResource("RectangleShape2D_7cdhx")
[node name="Npc对话3" parent="Ground/DeployLayer/【胖小孩背着残疾小孩】" instance=ExtResource("24_phfqg")] [node name="Npc对话3" parent="Ground/DeployLayer/【胖小孩背着残疾小孩】" instance=ExtResource("24_phfqg")]
position = Vector2(3, 53) position = Vector2(4, 53)
speaking_sign_height = 39.23 speaking_sign_height = 39.23
hook_character_name = "孩子王"
dialogue_title = "c01_s06_四个小孩_对话3" dialogue_title = "c01_s06_四个小孩_对话3"
[node name="Npc大胖" parent="Ground/DeployLayer/【胖小孩背着残疾小孩】" instance=ExtResource("24_phfqg")]
position = Vector2(-6, 63)
enabled = false
speaking_sign_height = 38.52
hook_character_name = "大胖"
[node name="猫鼠游戏胜利ambush" parent="Ground/DeployLayer" index="19" instance=ExtResource("11_tudob")] [node name="猫鼠游戏胜利ambush" parent="Ground/DeployLayer" index="19" instance=ExtResource("11_tudob")]
position = Vector2(4546, 45) position = Vector2(4546, 45)
one_shot = false one_shot = false

View File

@ -101,10 +101,6 @@ func jiandu_dialog_triggered() -> void:
var jiandu = $"../DeployLayer/举碗小孩/Npc监督小孩" var jiandu = $"../DeployLayer/举碗小孩/Npc监督小孩"
jiandu.hook_speaking() jiandu.hook_speaking()
SceneManager.hold_player() SceneManager.hold_player()
DialogueManager.dialogue_ended.connect(_on_jiandu_dialog_ended, CONNECT_ONE_SHOT) await DialogueManager.dialogue_ended
func _on_jiandu_dialog_ended(_res) -> void:
var jiandu = $"../DeployLayer/举碗小孩/Npc监督小孩"
jiandu.unhook_speaking()
SceneManager.unhold_player() SceneManager.unhold_player()
jiandu.unhook_speaking()