Godot对话框音效异常:关卡启动自动播放、关闭后仍持续播放问题
问题根因
问题1(启动自动播放音效)
你在对话框的_ready()生命周期方法中直接调用了load_dialog(),只要对话框节点被加载到场景中,就会自动把test标记设为true,触发后续的音效播放逻辑,不需要任何触发条件。
问题2(快速按回车后音效持续播放)
你把音效播放方法MusicController.dialogsfx.play()放在了_physics_process中,每帧都会执行一次播放请求,一秒内会触发几十次播放。就算你调用了停止方法,后续帧的播放请求还会继续执行,导致音效停不下来;快速按回车触发对话切换时,还会出现上一个对话的播放逻辑没结束、新的对话播放逻辑又启动的叠加问题。
修复方案
1. 移除自动触发的对话加载逻辑
删掉对话框_ready()方法中的load_dialog()调用,改为在满足触发条件(比如NPC交互)时,从外部主动调用load_dialog()启动对话。
2. 重构音效播放逻辑
不要在帧循环中处理音效播放,仅在对话开始时调用一次播放,对话结束/中断时调用一次停止即可。
修改后代码
对话框代码
extends Control var dialog = [ 'test1', 'test2', ] var dialog_index = 0 var finished = false var test = false func _ready(): MusicController.dialogsfx.stop() # 移除了自动调用的load_dialog() Global.DialogBox = self func _exit_tree(): # 节点销毁前强制停止音效,避免漏停 MusicController.dialogsfx.stop() Global.DialogBox = null func _physics_process(delta): $"Ind".visible = finished if Input.is_action_just_pressed("ui_accept"): # 未播放完时按回车直接跳过当前对话 if not finished: $Tween.stop_all() $RichTextLabel.percent_visible = 1 finished = true MusicController.dialogsfx.stop() return load_dialog() if Global.player.can_move: MusicController.dialogsfx.stop() func load_dialog(): # 加载新对话前先清空上一个对话的状态 $Tween.stop_all() MusicController.dialogsfx.stop() if dialog_index < dialog.size(): test = true finished = false $RichTextLabel.bbcode_text = dialog[dialog_index] $RichTextLabel.percent_visible = 0 $Tween.interpolate_property( $RichTextLabel, "percent_visible", 0, 1, 1, Tween.TRANS_LINEAR, Tween.EASE_IN_OUT ) $Tween.start() # 仅调用一次音效播放 MusicController.dialogsfx.play() else: Global.npc1.dialogsoundstop = true MusicController.dialogsfx.stop() Global.player.can_move = true Global.npc1.done = true test = false queue_free() dialog_index += 1 func _on_Tween_tween_completed(object, key): finished = true # 对话播放完成直接停止音效 MusicController.dialogsfx.stop()
可选优化:逐字播放短音效
如果你的音效是单字短音效,需要每显示一个字播放一次,可替换为如下逐字显示逻辑,替代原来的Tween动画:
# 替换原来的Tween动画逻辑 func load_dialog(): $Tween.stop_all() MusicController.dialogsfx.stop() if dialog_index < dialog.size(): test = true finished = false $RichTextLabel.bbcode_text = "" # 启动逐字显示协程 _show_text_by_char(dialog[dialog_index]) else: Global.npc1.dialogsoundstop = true MusicController.dialogsfx.stop() Global.player.can_move = true Global.npc1.done = true test = false queue_free() dialog_index += 1 # 逐字显示方法 async func _show_text_by_char(text: String, char_interval: float = 0.05): for char in text: $RichTextLabel.bbcode_text += char MusicController.dialogsfx.play() await get_tree().create_timer(char_interval).timeout finished = true MusicController.dialogsfx.stop()
内容的提问来源于stack exchange,提问作者Ajajajaj
相关产品推荐
相关产品推荐

