xiandie/scene/entity/general/sfx.gd
2025-06-16 12:48:38 +08:00

134 lines
3.3 KiB
GDScript

@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