@tool class_name Sfx extends AudioStreamPlayer @export_enum("交互与效果音", "BGM", "场景背景音") var mode := "交互与效果音": set(value): mode = value notify_property_list_changed() # 默认 stream 会变成 default 值 @export var audio_dict = {} as Dictionary[String, AudioStream] # 当前播放状态注册;节点销毁前卸载 # TODO BGM 过程抑制场景音效;场景音效随玩家运动呼吸 (结合 Sfx2D) # 感应玩家移动:装饰音 var default_db := 0.0 # 只有 场景背景音 生效 var scene_loop := true var scene_autostart := true var scene_sense_player_mov := false func _ready() -> void: bus = &"game_sfx" default_db = volume_db if Engine.is_editor_hint(): audio_dict.erase("default") return if stream: audio_dict["default"] = stream finished.connect(_on_finished) func switch_stream(stream_name: String, play_next:= false, easing_duration := 1.0): if not audio_dict.has(stream_name): printerr("Audio stream not found in audio_dict: ", stream_name) return if easing_duration > 0: easing_kill(easing_duration).tween_callback(func(): stream = audio_dict[stream_name] if play_next: play() ) else: stream = audio_dict[stream_name] if play_next: play() func _on_finished() -> void: if mode == "场景背景音" and scene_loop: play() func resart(ease_duration := 1.0): easing_kill(ease_duration).tween_callback(play) # queue free 导致 sfx 无法播放,使用全局声源 func global_play() -> void: if stream: AudioManager.play_sfx(stream) # 注意:会导致 volume db 变化 func easing_kill(duration: float = 2.0) -> Tween: # stop with easing var tween = create_tween() if playing: tween.tween_property(self, "volume_db", -80.0, duration) tween.tween_callback(stop) # set volume_db back to default tween.tween_callback(func(): volume_db = default_db) return tween func _get_property_list() -> Array[Dictionary]: if mode != "场景背景音": return [] # # 只有 场景背景音 生效 # var scene_loop := true # var scene_autostart := true # var scene_sense_player_mov := false return [ { "name": "场景背景音配置项", "type": TYPE_NIL, "usage": PROPERTY_USAGE_GROUP, }, {"name": "自动开始", "type": TYPE_BOOL}, {"name": "循环播放", "type": TYPE_BOOL}, {"name": "感应玩家操作", "type": TYPE_BOOL} ] func _property_can_revert(property: StringName) -> bool: return property == "自动开始" or property == "循环播放" or property == "感应玩家操作" func _property_get_revert(property: StringName) -> Variant: if property == "自动开始" or property == "循环播放": return true elif property == "感应玩家操作": return false return null func _set(property: StringName, value: Variant) -> bool: if mode != "场景背景音": return false if property == "自动开始": if value != null: autoplay = value scene_autostart = value return true elif property == "循环播放": scene_loop = value return true elif property == "感应玩家操作": scene_sense_player_mov = value return true return false func _get(property: StringName) -> Variant: if mode != "场景背景音": return null if property == "自动开始": return scene_autostart elif property == "循环播放": return scene_loop elif property == "感应玩家操作": return scene_sense_player_mov return null