xiandie/scene/entity/audio/sfx.gd

157 lines
4.0 KiB
GDScript3
Raw Normal View History

@tool
2025-01-07 10:54:50 +00:00
class_name Sfx extends AudioStreamPlayer
2025-07-19 07:02:32 +00:00
const META_ORIGINAL_STREAM = &"original_stream"
@export_enum("交互与效果音", "BGM", "场景背景音") var mode := "交互与效果音":
set(value):
2025-07-19 07:02:32 +00:00
_set_up_process_mode_by_mode()
mode = value
notify_property_list_changed()
# 当前播放状态注册;节点销毁前卸载
# TODO BGM 过程抑制场景音效;场景音效随玩家运动呼吸 (结合 Sfx2D)
# 感应玩家移动:装饰音
var default_db := 0.0
# 只有 场景背景音 生效
var scene_loop := true
var scene_sense_player_mov := false
func _ready() -> void:
2025-01-07 10:54:50 +00:00
bus = &"game_sfx"
default_db = volume_db
if Engine.is_editor_hint():
return
2025-07-19 07:02:32 +00:00
# 记录原 stream
if stream:
set_meta(META_ORIGINAL_STREAM, stream)
else:
set_meta(META_ORIGINAL_STREAM, null)
_set_up_process_mode_by_mode()
finished.connect(_on_finished)
2025-07-03 09:49:00 +00:00
# ground 退出时process mode 切换为 alwaysease out
SceneManager.ground_transition_pre_paused.connect(_on_ground_transition_pre_paused)
2025-07-19 07:02:32 +00:00
SceneManager.pause_counter_updated.connect(_on_pause_counter_updated)
2025-07-20 10:58:20 +00:00
var playing_on_debugging_paused = false
2025-07-19 07:02:32 +00:00
func _on_pause_counter_updated() -> void:
_set_up_process_mode_by_mode()
func _set_up_process_mode_by_mode():
# 如果是 debug panel则 pause
2025-07-21 09:25:04 +00:00
if mode == "场景背景音" and (SceneManager.is_node_ready() and not SceneManager.pause_counter_arr.has("debugging")):
2025-07-19 07:02:32 +00:00
process_mode = Node.PROCESS_MODE_ALWAYS
else:
2025-07-20 10:58:20 +00:00
if SceneManager.pause_counter_arr.has("debugging"):
playing_on_debugging_paused = playing
2025-07-19 07:02:32 +00:00
process_mode = Node.PROCESS_MODE_PAUSABLE
2025-07-03 09:49:00 +00:00
func _on_ground_transition_pre_paused():
if not playing:
return
print("[GroundTransition] Sfx %s ease killing..." % name)
easing_kill(1.0)
func _on_finished() -> void:
if mode == "场景背景音" and scene_loop:
play()
2025-07-19 07:02:32 +00:00
func reset_original_stream(ignore_null := true):
var original_stream = get_meta(META_ORIGINAL_STREAM)
if original_stream != null:
replace_stream(original_stream)
elif not ignore_null:
stream = null
func replace_stream(new_stream: AudioStream) -> void:
stream = new_stream
2025-07-20 10:58:20 +00:00
if (playing_on_debugging_paused or autoplay) and is_node_ready():
2025-07-19 07:02:32 +00:00
play()
func stream_was_replaced() -> bool:
return get_meta(META_ORIGINAL_STREAM) != stream
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)
func easing_kill(duration: float = 2.0) -> Tween:
# stop with easing
var tween = create_tween()
2025-07-03 09:49:00 +00:00
tween.bind_node(self)
if playing:
2025-06-27 03:43:23 +00:00
tween.tween_property(self, "volume_linear", 0.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
2025-06-16 04:43:09 +00:00
# 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}
]
func _property_can_revert(property: StringName) -> bool:
2025-07-19 07:02:32 +00:00
return property == "循环播放" or property == "感应玩家操作"
func _property_get_revert(property: StringName) -> Variant:
2025-07-19 07:02:32 +00:00
if property == "循环播放":
return true
elif property == "感应玩家操作":
return false
return null
func _set(property: StringName, value: Variant) -> bool:
if mode != "场景背景音":
return false
elif property == "循环播放":
scene_loop = value
return true
elif property == "感应玩家操作":
scene_sense_player_mov = value
return true
return false
2025-01-21 10:52:36 +00:00
func _get(property: StringName) -> Variant:
if mode != "场景背景音":
return null
elif property == "循环播放":
return scene_loop
elif property == "感应玩家操作":
return scene_sense_player_mov
return null