15、音频系统

第15章 音频系统

15.1 AudioStreamPlayer 基础

gdscript 复制代码
# AudioStreamPlayer:非位置音频(BGM、UI音效)
# AudioStreamPlayer2D:2D 位置音频(距离衰减)
# AudioStreamPlayer3D:3D 位置音频

extends AudioStreamPlayer

func _ready() -> void:
    stream = preload("res://audio/bgm/battle_theme.ogg")
    volume_db = -10  # 音量(分贝)
    pitch_scale = 1.0
    autoplay = false
    bus = "Music"  # 音频总线

func play_bgm() -> void:
    if not playing:
        play()

func stop_bgm() -> void:
    if playing:
        # 淡出
        var tween := create_tween()
        tween.tween_property(self, "volume_db", -40.0, 1.0)
        await tween.finished
        stop()
        volume_db = -10  # 恢复音量

15.2 AudioStreamRandomizer(随机音效变体)

gdscript 复制代码
# AudioStreamRandomizer 自动在多个音效中随机选择
# 避免重复播放同一音效产生机械感

# 设置:
# 1. 创建 AudioStreamRandomizer 资源
# 2. 添加多个 AudioStream(如不同的脚步声)
# 3. 设置 Playback Mode: Random (No Repeat)
# 4. 设置 Random Pitch: 0.9 ~ 1.1(音高随机变化)

# 代码使用
extends AudioStreamPlayer2D

func play_footstep() -> void:
    stream = preload("res://audio/sfx/footstep_randomizer.tres")
    pitch_scale = randf_range(0.9, 1.1)  # 额外随机
    play()

15.3 音频总线(Audio Bus)

gdscript 复制代码
# 音频总线用于分组控制音量和效果
# 设置:底部面板 → Audio → Audio Bus

# 推荐总线布局:
# Bus 0: Master(主音量)
# Bus 1: Music(背景音乐)
# Bus 2: SFX(音效)
# Bus 3: Voice(语音)
# Bus 4: Ambient(环境音)

# 代码控制
func set_music_volume(volume_db: float) -> void:
    var bus_idx := AudioServer.get_bus_index("Music")
    AudioServer.set_bus_volume_db(bus_idx, volume_db)

func set_sfx_mute(muted: bool) -> void:
    var bus_idx := AudioServer.get_bus_index("SFX")
    AudioServer.set_bus_mute(bus_idx, muted)

# 添加音频效果
func add_reverb_to_sfx() -> void:
    var bus_idx := AudioServer.get_bus_index("SFX")
    var reverb := AudioEffectReverb.new()
    reverb.room_size = 0.8
    reverb.damping = 0.5
    AudioServer.add_bus_effect(bus_idx, reverb)

15.4 位置音频(AudioStreamPlayer2D)

gdscript 复制代码
extends AudioStreamPlayer2D

func _ready() -> void:
    # 距离衰减设置
    max_distance = 500.0  # 超过这个距离听不到
    # attenuation 属性在 Godot 4.x 中通过衰减曲线控制
    # 默认使用反距离衰减

# 爆炸音效(在特定位置播放)
func play_explosion_sound(pos: Vector2) -> void:
    var sound := AudioStreamPlayer2D.new()
    sound.stream = preload("res://audio/sfx/explosion.wav")
    sound.global_position = pos
    sound.max_distance = 800.0
    add_child(sound)
    sound.play()
    sound.finished.connect(sound.queue_free)

15.5 动态音乐系统

gdscript 复制代码
extends Node

@onready var exploration_player: AudioStreamPlayer = $ExplorationMusic
@onready var combat_player: AudioStreamPlayer = $CombatMusic

var is_in_combat: bool = false
var crossfade_duration: float = 2.0

func enter_combat() -> void:
    if is_in_combat:
        return
    is_in_combat = true
    
    # 交叉渐变
    combat_player.volume_db = -40
    combat_player.play()
    
    var tween := create_tween().set_parallel(true)
    tween.tween_property(exploration_player, "volume_db", -40, crossfade_duration)
    tween.tween_property(combat_player, "volume_db", 0, crossfade_duration)

func exit_combat() -> void:
    if not is_in_combat:
        return
    is_in_combat = false
    
    var tween := create_tween().set_parallel(true)
    tween.tween_property(combat_player, "volume_db", -40, crossfade_duration)
    tween.tween_property(exploration_player, "volume_db", 0, crossfade_duration)
    await tween.finished
    combat_player.stop()

15.6 对话语音

gdscript 复制代码
extends RichTextLabel

@export var voice_stream: AudioStreamPlayer

var is_typing: bool = false
var typing_speed: float = 0.03  # 每个字符的时间

func show_dialogue(text: String, voice: AudioStream = null) -> void:
    visible_characters = 0
    self.text = text
    is_typing = true
    
    if voice and voice_stream:
        voice_stream.stream = voice
        voice_stream.play()
    
    for i in text.length():
        if not is_typing:
            break
        visible_characters = i + 1
        await get_tree().create_timer(typing_speed).timeout
    
    visible_characters = -1  # 显示全部
    is_typing = false

func skip_typing() -> void:
    is_typing = false
    visible_characters = -1
相关推荐
郝学胜-神的一滴2 天前
游戏设计:原型与开发 08:我们到底在为谁做游戏
程序人生·游戏·游戏引擎·游戏开发·游戏策划
Wanda12143 天前
机器人与机电一体化3D数字孪生机器-Day5
人工智能·unity·游戏引擎·数字孪生
淡海水4 天前
05-02-源码-Boehm GC标记阶段
算法·unity·c#·游戏引擎·gc
淡海水4 天前
05-03-源码-Boehm GC分配与碎片管理
开发语言·算法·unity·c#·游戏引擎·gc
xiaogai_gai8 天前
BOM 物料清单同步实战:金蝶云星空 → 四化智造 MES 修改场景深度拆解
unity·游戏引擎
/**书香门第*/8 天前
Cocos Creator 打螺丝游戏的实现
游戏引擎·cocos2d·螺丝·打螺丝
mxwin9 天前
Unity Shader 光线追踪原理与实战案例
unity·游戏引擎
xcLeigh11 天前
Unity基础:Instantiate实例化——在运行时动态创建游戏物体
游戏·unity·游戏引擎·教程·instantiate
辻弋20116 天前
五年前的旅行视频糊成马赛克?Video2X用Real-ESRGAN逐帧重建细节,但只支持Windows、集显用户建议直接放弃
服务器·数据库·windows·游戏引擎·电脑
狂野小白兔18 天前
AI游戏制作04——Codex 搭配 Godot MCP 全流程教程
人工智能·游戏·godot