研究归属: Project Vampirefall - Audio
创建日期: 2025-12-04
优先级: ⭐⭐⭐ (中)
动态音乐 (Adaptive Music) 指随游戏状态(战斗强度、剧情进展、玩家位置)实时变化的背景音乐。它打破了传统”循环播放一首曲子”的模式,使听觉体验与玩家的情绪曲线同步。
两大核心技术:
音乐必须匹配塔防的波次节奏:
我们采用 垂直分层为主,水平切换为辅 的混合架构。
对于每一首战斗曲,我们需要作曲家提供 4 个同步轨道:
| 轨道 | 内容 | 触发条件 |
|---|---|---|
| Layer 1: Base | 氛围 Pad、低音 Bass | 始终播放 (建造阶段) |
| Layer 2: Rhythm | 鼓组、打击乐 | 战斗开始 (第一只怪刷出) |
| Layer 3: Melody | 主旋律 (弦乐/合成器) | 怪物数量 > 20 或 精英怪出现 |
| Layer 4: Hype | 高潮乐器 (电吉他/人声) | Boss 战 或 基地血量 < 30% |
虽然 Wwise/FMOD 很强大,但对于独立游戏,Unity 原生 AudioSource 配合简单的管理器已足够。
public class MusicManager : MonoBehaviour
{
[Header("Audio Sources")]
public AudioSource layerBase;
public AudioSource layerRhythm;
public AudioSource layerMelody;
public AudioSource layerHype;
[Header("Settings")]
public float fadeSpeed = 2.0f;
// 目标音量 (0 或 1)
private float[] targetVolumes = new float[4];
void Update()
{
// 1. 获取当前游戏强度 (0-100)
float intensity = GameDirector.Instance.GetCombatIntensity();
// 2. 决定各轨道开关
targetVolumes[0] = 1.0f; // Base 始终开启
targetVolumes[1] = intensity > 0 ? 1.0f : 0.0f;
targetVolumes[2] = intensity > 40 ? 1.0f : 0.0f;
targetVolumes[3] = intensity > 80 ? 1.0f : 0.0f;
// 3. 平滑过渡音量
layerBase.volume = Mathf.Lerp(layerBase.volume, targetVolumes[0], Time.deltaTime * fadeSpeed);
layerRhythm.volume = Mathf.Lerp(layerRhythm.volume, targetVolumes[1], Time.deltaTime * fadeSpeed);
layerMelody.volume = Mathf.Lerp(layerMelody.volume, targetVolumes[2], Time.deltaTime * fadeSpeed);
layerHype.volume = Mathf.Lerp(layerHype.volume, targetVolumes[3], Time.deltaTime * fadeSpeed);
}
// 确保所有轨道完全同步播放
public void PlayTrack(MusicTrack track)
{
double dspTime = AudioSettings.dspTime + 0.1; // 稍微延迟以保证同步
layerBase.clip = track.stemBase;
layerRhythm.clip = track.stemRhythm;
// ... 赋值其他轨道
layerBase.PlayScheduled(dspTime);
layerRhythm.PlayScheduled(dspTime);
// ... 播放其他轨道
}
}
为了让视觉特效(如屏幕震动、UI跳动)踩在点上,我们需要简单的 BPM 系统。
public class BeatSynchronizer : MonoBehaviour
{
public float bpm = 120f;
private float secondsPerBeat;
private float nextBeatTime;
public event Action OnBeat; // 节拍事件
void Start()
{
secondsPerBeat = 60f / bpm;
nextBeatTime = AudioSettings.dspTime + secondsPerBeat;
}
void Update()
{
if (AudioSettings.dspTime >= nextBeatTime)
{
OnBeat?.Invoke();
nextBeatTime += secondsPerBeat;
}
}
}
CombatIntensityEvaluator,根据屏幕内怪物数量、精英怪权重、玩家血量计算一个 0-100 的强度值。文档版本: v1.0
最后更新: 2025-12-04
维护者: Vampirefall Audio Team