2025-07-21 17:04:43 +08:00
|
|
|
|
using System;
|
2025-07-23 12:59:57 +08:00
|
|
|
|
using System.Collections.Generic;
|
2025-03-10 13:12:05 +08:00
|
|
|
|
using PhxhSDK;
|
|
|
|
|
|
using UnityEngine;
|
2025-11-14 19:35:19 +08:00
|
|
|
|
using PlayState = PhxhSDK.PlayState;
|
2025-03-10 13:12:05 +08:00
|
|
|
|
|
2025-11-14 15:57:36 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 音频播放器
|
2025-11-17 14:37:45 +08:00
|
|
|
|
/// 功能:异步加载、播放控制、3D空间音效、淡入淡出效果
|
|
|
|
|
|
/// 实现接口:IAudioPlayer, IAudioSpatial, IAudioFade
|
2025-11-14 15:57:36 +08:00
|
|
|
|
/// </summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
public class AudioPlayer : IAudioPlayer, IAudioSpatial, IAudioFade
|
2025-03-10 13:12:05 +08:00
|
|
|
|
{
|
2025-11-17 14:37:45 +08:00
|
|
|
|
#region Static - ID Generation & Resource Tracking
|
2025-11-14 19:10:22 +08:00
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
private static int _audioIDCounter;
|
2025-11-14 19:35:19 +08:00
|
|
|
|
private static Dictionary<string, int> _loadedAssetPaths = new();
|
2025-11-14 19:10:22 +08:00
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 生成唯一的 AudioID
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static int GenAudioID() => ++_audioIDCounter;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 重置 AudioID 计数器
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static void ReleaseAudioIDs() => _audioIDCounter = 0;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 释放所有已加载的资源
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static void ReleaseLoadedAssets()
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var kv in _loadedAssetPaths)
|
|
|
|
|
|
{
|
|
|
|
|
|
var key = kv.Key;
|
|
|
|
|
|
var count = kv.Value;
|
|
|
|
|
|
while (count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
AssetManager.Instance.Unload(key, false, true);
|
|
|
|
|
|
--count;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
_loadedAssetPaths.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-14 19:10:22 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
#region Fields
|
2025-11-14 19:10:22 +08:00
|
|
|
|
|
2025-11-14 19:35:19 +08:00
|
|
|
|
// Unity 组件
|
2025-11-17 14:37:45 +08:00
|
|
|
|
private readonly GameObject _rootGo;
|
|
|
|
|
|
private readonly AudioSource _audioSource;
|
2025-11-14 19:35:19 +08:00
|
|
|
|
private AudioClip _clip;
|
|
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
// 状态
|
2025-11-14 19:35:19 +08:00
|
|
|
|
private PlayState _playState;
|
2025-11-17 14:37:45 +08:00
|
|
|
|
private readonly int _audioID;
|
2025-11-17 19:37:24 +08:00
|
|
|
|
private EAudioType _eAudioType;
|
2025-11-14 19:35:19 +08:00
|
|
|
|
private bool _loop;
|
|
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
// 音量控制
|
|
|
|
|
|
private float _targetVolume = 1f;
|
2025-11-14 19:35:19 +08:00
|
|
|
|
private float _normalizeVolume = 1f;
|
|
|
|
|
|
private bool _isSpeak;
|
2025-11-14 19:10:22 +08:00
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
// 效果控制器
|
|
|
|
|
|
private readonly AudioFadeEffect _fadeEffect;
|
|
|
|
|
|
private readonly AudioSpatialController _spatialController;
|
2025-11-14 19:10:22 +08:00
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
#region Properties
|
2025-11-14 19:10:22 +08:00
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
// IAudioPlayer 接口属性
|
2025-11-14 19:35:19 +08:00
|
|
|
|
public int AudioId => _audioID;
|
|
|
|
|
|
public PlayState State => _playState;
|
|
|
|
|
|
public bool IsPlaying => _playState == PlayState.Playing;
|
|
|
|
|
|
public AudioClip Clip => _clip;
|
|
|
|
|
|
public float Volume => _audioSource?.volume ?? 0f;
|
2025-11-14 19:10:22 +08:00
|
|
|
|
|
2025-11-17 14:50:15 +08:00
|
|
|
|
// 公开属性
|
2025-11-17 19:37:24 +08:00
|
|
|
|
public EAudioType EAudioType
|
2025-11-14 19:35:19 +08:00
|
|
|
|
{
|
2025-11-17 19:37:24 +08:00
|
|
|
|
get => _eAudioType;
|
|
|
|
|
|
set => _eAudioType = value;
|
2025-11-14 19:35:19 +08:00
|
|
|
|
}
|
2025-11-14 19:10:22 +08:00
|
|
|
|
|
2025-11-14 19:35:19 +08:00
|
|
|
|
public bool loop
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _loop;
|
|
|
|
|
|
set => _loop = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
// 其他公开属性
|
2025-11-14 19:35:19 +08:00
|
|
|
|
public GameObject RootGo => _rootGo;
|
2025-03-10 13:12:05 +08:00
|
|
|
|
public bool IsSpeak => _isSpeak;
|
2025-11-13 19:08:07 +08:00
|
|
|
|
|
2025-11-14 19:35:19 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
#region Constructor & Initialization
|
2025-03-10 13:12:05 +08:00
|
|
|
|
|
2025-11-17 19:37:24 +08:00
|
|
|
|
public AudioPlayer(EAudioType eAudioType, GameObject rootGo, GameObject posGo, AudioInfo audioInfo,
|
2025-03-10 13:12:05 +08:00
|
|
|
|
bool loop = false, bool is3D = false)
|
|
|
|
|
|
{
|
2025-11-17 14:37:45 +08:00
|
|
|
|
_audioID = GenAudioID();
|
2025-11-17 19:37:24 +08:00
|
|
|
|
_eAudioType = eAudioType;
|
2025-03-10 13:12:05 +08:00
|
|
|
|
_rootGo = rootGo;
|
2025-11-17 14:37:45 +08:00
|
|
|
|
_audioSource = GetOrAddAudioSource(rootGo);
|
2025-11-13 18:36:05 +08:00
|
|
|
|
_audioSource.volume = AudioVolumeSettings.Instance.GlobalVolume;
|
2025-03-10 13:12:05 +08:00
|
|
|
|
_isSpeak = audioInfo.isSpeak;
|
2025-11-17 14:37:45 +08:00
|
|
|
|
_loop = loop;
|
2025-11-13 18:55:54 +08:00
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
// 初始化效果控制器
|
2025-11-14 19:35:19 +08:00
|
|
|
|
_fadeEffect = new AudioFadeEffect(
|
|
|
|
|
|
fadeInDuration: AudioConstant.DefaultFadeInDuration,
|
|
|
|
|
|
fadeOutDuration: AudioConstant.DefaultFadeOutDuration);
|
2025-11-13 19:08:07 +08:00
|
|
|
|
|
|
|
|
|
|
_spatialController = new AudioSpatialController(_rootGo.transform, _audioSource);
|
|
|
|
|
|
|
|
|
|
|
|
// 如果构造时指定了跟随对象,设置跟随
|
|
|
|
|
|
if (posGo != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_spatialController.SetFollowTarget(posGo);
|
|
|
|
|
|
}
|
2025-03-10 13:12:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
private AudioSource GetOrAddAudioSource(GameObject go)
|
2025-03-10 13:12:05 +08:00
|
|
|
|
{
|
2025-11-17 14:37:45 +08:00
|
|
|
|
var source = go.GetComponent<AudioSource>();
|
2025-03-10 13:12:05 +08:00
|
|
|
|
if (!source)
|
|
|
|
|
|
{
|
2025-11-17 14:37:45 +08:00
|
|
|
|
source = go.AddComponent<AudioSource>();
|
2025-03-10 13:12:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
return source;
|
|
|
|
|
|
}
|
2025-11-14 19:35:19 +08:00
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
#region Lifecycle & Update
|
2025-03-10 13:12:05 +08:00
|
|
|
|
|
2025-11-14 19:10:22 +08:00
|
|
|
|
public void Update(float dt)
|
2025-03-10 13:12:05 +08:00
|
|
|
|
{
|
2025-11-17 14:37:45 +08:00
|
|
|
|
if (_audioSource == null || _clip == null)
|
2025-03-10 13:12:05 +08:00
|
|
|
|
return;
|
|
|
|
|
|
|
2025-11-13 18:55:54 +08:00
|
|
|
|
// 更新淡入淡出效果
|
|
|
|
|
|
bool shouldStop = _fadeEffect.Update(dt);
|
|
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
// 更新音量
|
2025-11-14 19:35:19 +08:00
|
|
|
|
if (_playState == PlayState.Playing || _audioSource.isPlaying)
|
2025-03-10 13:12:05 +08:00
|
|
|
|
{
|
2025-11-17 14:37:45 +08:00
|
|
|
|
UpdateVolume();
|
2025-03-10 13:12:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
// 暂停状态不更新
|
2025-11-14 19:35:19 +08:00
|
|
|
|
if (_playState == PlayState.Paused)
|
2025-06-24 15:43:11 +08:00
|
|
|
|
return;
|
2025-11-13 18:55:54 +08:00
|
|
|
|
|
2025-11-13 19:08:07 +08:00
|
|
|
|
// 更新空间位置跟随
|
2025-11-14 19:35:19 +08:00
|
|
|
|
if (_playState == PlayState.Playing)
|
2025-03-10 13:12:05 +08:00
|
|
|
|
{
|
2025-11-13 19:08:07 +08:00
|
|
|
|
_spatialController.Update();
|
2025-03-10 13:12:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-13 18:55:54 +08:00
|
|
|
|
// 检查是否应该停止(播放结束或淡出完成)
|
2025-11-17 14:37:45 +08:00
|
|
|
|
if (IsPlaybackEnded() || shouldStop || _playState == PlayState.Stopped)
|
2025-03-10 13:12:05 +08:00
|
|
|
|
{
|
2025-11-14 19:35:19 +08:00
|
|
|
|
if (_playState == PlayState.Loading)
|
2025-08-20 14:39:40 +08:00
|
|
|
|
return;
|
|
|
|
|
|
|
2025-03-10 13:12:05 +08:00
|
|
|
|
Stop();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-17 14:37:45 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 判断播放是否已结束
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private bool IsPlaybackEnded()
|
2025-03-10 13:12:05 +08:00
|
|
|
|
{
|
2025-11-17 14:37:45 +08:00
|
|
|
|
if (_audioSource == null || _clip == null)
|
|
|
|
|
|
return false;
|
2025-03-10 13:12:05 +08:00
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
return _audioSource.isPlaying
|
|
|
|
|
|
? _audioSource.time > _clip.length
|
|
|
|
|
|
: true;
|
2025-03-10 13:12:05 +08:00
|
|
|
|
}
|
2025-11-17 14:37:45 +08:00
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Playback Control
|
2025-03-10 13:12:05 +08:00
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 播放音频(需要先设置 Clip)
|
|
|
|
|
|
/// </summary>
|
2025-11-14 19:10:22 +08:00
|
|
|
|
public void Play()
|
2025-03-10 13:12:05 +08:00
|
|
|
|
{
|
2025-11-17 14:37:45 +08:00
|
|
|
|
if (_clip == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
DebugUtil.LogError("AudioPlayer: Cannot play without clip");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-14 19:35:19 +08:00
|
|
|
|
_playState = PlayState.Playing;
|
2025-11-17 14:37:45 +08:00
|
|
|
|
_fadeEffect.Stop();
|
2025-11-14 19:35:19 +08:00
|
|
|
|
_targetVolume = 1f;
|
2025-03-10 13:12:05 +08:00
|
|
|
|
_audioSource.Play();
|
2025-11-17 14:37:45 +08:00
|
|
|
|
NotifyPlayStarted();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 暂停播放
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void Pause()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_audioSource != null)
|
|
|
|
|
|
_audioSource.Pause();
|
|
|
|
|
|
_playState = PlayState.Paused;
|
2025-03-10 13:12:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 恢复播放
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void Resume()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_audioSource != null)
|
|
|
|
|
|
_audioSource.UnPause();
|
|
|
|
|
|
_playState = PlayState.Playing;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 停止播放
|
|
|
|
|
|
/// </summary>
|
2025-11-14 19:10:22 +08:00
|
|
|
|
public void Stop()
|
2025-03-10 13:12:05 +08:00
|
|
|
|
{
|
2025-11-17 14:37:45 +08:00
|
|
|
|
_fadeEffect.Stop();
|
2025-11-17 19:37:24 +08:00
|
|
|
|
AudioManager.Instance.AudioMgrObj.RemovePlaying(_audioID);
|
2025-11-13 18:55:54 +08:00
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
if (IsPlaybackEnded())
|
2025-03-10 13:12:05 +08:00
|
|
|
|
{
|
2025-11-14 19:35:19 +08:00
|
|
|
|
_playState = PlayState.Stopped;
|
2025-03-10 13:12:05 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-03-24 15:59:50 +08:00
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
if (_audioSource != null)
|
2025-03-24 15:59:50 +08:00
|
|
|
|
{
|
|
|
|
|
|
_audioSource.Stop();
|
|
|
|
|
|
}
|
2025-11-14 19:35:19 +08:00
|
|
|
|
_playState = PlayState.Stopped;
|
2025-03-10 13:12:05 +08:00
|
|
|
|
}
|
2025-11-14 15:57:36 +08:00
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Async Loading & Play
|
2025-03-10 13:12:05 +08:00
|
|
|
|
|
2025-11-14 18:21:45 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 异步加载并播放音频(不带淡入淡出)
|
|
|
|
|
|
/// </summary>
|
2025-08-19 18:12:10 +08:00
|
|
|
|
public void Play(string path)
|
|
|
|
|
|
{
|
2025-11-14 19:35:19 +08:00
|
|
|
|
_playState = PlayState.Loading;
|
2025-11-17 14:37:45 +08:00
|
|
|
|
LoadAndPlayInternal(path, useFade: false);
|
2025-11-14 18:21:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 异步加载并播放音频(带淡入淡出)
|
|
|
|
|
|
/// </summary>
|
2025-11-14 19:35:19 +08:00
|
|
|
|
public void PlayWithFade(string path,
|
|
|
|
|
|
float fadeInTime = AudioConstant.DefaultFadeInDuration,
|
|
|
|
|
|
float fadeOutTime = AudioConstant.DefaultFadeOutDuration)
|
2025-11-14 18:21:45 +08:00
|
|
|
|
{
|
2025-11-14 19:35:19 +08:00
|
|
|
|
_playState = PlayState.Loading;
|
2025-11-17 14:37:45 +08:00
|
|
|
|
LoadAndPlayInternal(path, useFade: true, fadeInTime, fadeOutTime);
|
2025-08-19 18:12:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-14 18:21:45 +08:00
|
|
|
|
/// <summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
/// 统一的异步加载和播放逻辑
|
2025-11-14 18:21:45 +08:00
|
|
|
|
/// </summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
private async void LoadAndPlayInternal(string path, bool useFade,
|
2025-11-14 19:35:19 +08:00
|
|
|
|
float fadeInTime = AudioConstant.DefaultFadeInDuration,
|
|
|
|
|
|
float fadeOutTime = AudioConstant.DefaultFadeOutDuration)
|
2025-03-10 13:12:05 +08:00
|
|
|
|
{
|
2025-11-14 18:21:45 +08:00
|
|
|
|
// 1. 异步加载音频资源
|
2025-04-18 13:39:19 +08:00
|
|
|
|
_clip = await AssetManager.Instance.LoadAssetAsync<AudioClip>(path, null, true);
|
2025-11-14 18:21:45 +08:00
|
|
|
|
|
|
|
|
|
|
// 2. 跟踪已加载的资源(用于后续卸载)
|
2025-11-17 14:37:45 +08:00
|
|
|
|
TrackLoadedAsset(path);
|
2025-11-14 18:21:45 +08:00
|
|
|
|
|
|
|
|
|
|
// 3. 加载失败处理
|
|
|
|
|
|
if (_clip == null)
|
2025-03-10 13:12:05 +08:00
|
|
|
|
{
|
2025-11-14 19:35:19 +08:00
|
|
|
|
_playState = PlayState.Stopped;
|
2025-03-10 13:12:05 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-11-14 18:21:45 +08:00
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
// 4. 设置 AudioSource
|
2025-03-10 13:12:05 +08:00
|
|
|
|
_audioSource.clip = _clip;
|
2025-11-14 19:35:19 +08:00
|
|
|
|
_targetVolume = 1f;
|
2025-11-14 18:21:45 +08:00
|
|
|
|
|
|
|
|
|
|
// 5. 根据是否需要淡入淡出设置音量
|
|
|
|
|
|
if (useFade)
|
|
|
|
|
|
{
|
|
|
|
|
|
_fadeEffect.FadeInDuration = fadeInTime;
|
|
|
|
|
|
_fadeEffect.FadeOutDuration = fadeOutTime;
|
|
|
|
|
|
_fadeEffect.StartFadeIn();
|
|
|
|
|
|
_audioSource.volume = 0f;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
_fadeEffect.Stop();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 6. 开始播放
|
2025-03-10 13:12:05 +08:00
|
|
|
|
_audioSource.Play();
|
2025-11-14 19:35:19 +08:00
|
|
|
|
_playState = PlayState.Playing;
|
2025-11-14 18:21:45 +08:00
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
// 7. 通知 Manager
|
|
|
|
|
|
NotifyPlayStarted();
|
2025-03-10 13:12:05 +08:00
|
|
|
|
}
|
2025-11-14 18:21:45 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 跟踪已加载的资源(用于引用计数)
|
|
|
|
|
|
/// </summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
private void TrackLoadedAsset(string path)
|
2025-03-10 13:12:05 +08:00
|
|
|
|
{
|
2025-11-13 20:14:42 +08:00
|
|
|
|
if (_loadedAssetPaths.ContainsKey(path))
|
|
|
|
|
|
++_loadedAssetPaths[path];
|
2025-07-23 12:59:57 +08:00
|
|
|
|
else
|
2025-11-13 20:14:42 +08:00
|
|
|
|
_loadedAssetPaths.TryAdd(path, 1);
|
2025-11-14 18:21:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
/// 通知 Manager 播放已开始
|
2025-11-14 18:21:45 +08:00
|
|
|
|
/// </summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
private void NotifyPlayStarted()
|
2025-11-14 18:21:45 +08:00
|
|
|
|
{
|
2025-11-17 19:37:24 +08:00
|
|
|
|
AudioManager.Instance.AudioMgrObj.Add2Playing(_audioID);
|
2025-03-10 13:12:05 +08:00
|
|
|
|
}
|
2025-11-17 14:37:45 +08:00
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Volume & Configuration
|
2025-03-10 13:12:05 +08:00
|
|
|
|
|
2025-11-13 19:08:07 +08:00
|
|
|
|
/// <summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
/// 设置音量(0-1)
|
2025-11-13 19:08:07 +08:00
|
|
|
|
/// </summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
public void SetVolume(float volume)
|
2025-03-10 13:12:05 +08:00
|
|
|
|
{
|
2025-11-17 14:37:45 +08:00
|
|
|
|
_targetVolume = Mathf.Clamp01(volume);
|
2025-03-10 13:12:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-13 19:08:07 +08:00
|
|
|
|
/// <summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
/// 设置归一化音量(配置表中的音量缩放)
|
2025-11-13 19:08:07 +08:00
|
|
|
|
/// </summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
public void SetNormalizeVolume(float vol = 1f)
|
2025-03-10 13:12:05 +08:00
|
|
|
|
{
|
2025-11-17 14:37:45 +08:00
|
|
|
|
_normalizeVolume = vol;
|
2025-03-10 13:12:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-14 19:10:22 +08:00
|
|
|
|
/// <summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
/// 设置是否为语音
|
2025-11-14 19:10:22 +08:00
|
|
|
|
/// </summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
public void SetIsSpeak(bool isSpeak)
|
2025-11-14 19:10:22 +08:00
|
|
|
|
{
|
2025-11-17 14:37:45 +08:00
|
|
|
|
_isSpeak = isSpeak;
|
2025-11-14 19:10:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
/// 设置循环播放
|
2025-11-14 19:10:22 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void SetLoop(bool isLoop)
|
2025-03-10 13:12:05 +08:00
|
|
|
|
{
|
2025-11-17 14:37:45 +08:00
|
|
|
|
_loop = isLoop;
|
2025-11-14 19:10:22 +08:00
|
|
|
|
if (_audioSource != null)
|
|
|
|
|
|
_audioSource.loop = isLoop;
|
2025-03-10 13:12:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-14 15:57:36 +08:00
|
|
|
|
/// <summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
/// 设置音频片段
|
2025-11-14 15:57:36 +08:00
|
|
|
|
/// </summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
public void SetClip(AudioClip clip)
|
|
|
|
|
|
{
|
|
|
|
|
|
_clip = clip;
|
|
|
|
|
|
if (_audioSource != null)
|
|
|
|
|
|
_audioSource.clip = clip;
|
|
|
|
|
|
}
|
2025-11-14 15:57:36 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
/// 统一的音量更新方法
|
|
|
|
|
|
/// 最终音量 = 淡入淡出系数 × 类型音量 × 全局音量 × 目标音量 × 归一化音量
|
2025-11-14 15:57:36 +08:00
|
|
|
|
/// </summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
private void UpdateVolume()
|
|
|
|
|
|
{
|
|
|
|
|
|
var settings = AudioVolumeSettings.Instance;
|
|
|
|
|
|
var fadeValue = _fadeEffect.FadeValue;
|
|
|
|
|
|
|
|
|
|
|
|
// 根据音频类型和是否为语音选择对应的音量系数
|
2025-11-17 19:37:24 +08:00
|
|
|
|
float typeVolume = _eAudioType switch
|
2025-11-17 14:37:45 +08:00
|
|
|
|
{
|
2025-11-17 19:37:24 +08:00
|
|
|
|
EAudioType.Music => settings.MusicVolume,
|
|
|
|
|
|
EAudioType.Sound => _isSpeak ? settings.SpeakVolume : settings.SoundVolume,
|
2025-11-17 14:37:45 +08:00
|
|
|
|
_ => 1f
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
_audioSource.volume = fadeValue * typeVolume * settings.GlobalVolume * _targetVolume * _normalizeVolume;
|
|
|
|
|
|
}
|
2025-03-10 13:12:05 +08:00
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
#endregion
|
2025-11-13 16:59:52 +08:00
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
#region Spatial Audio (3D)
|
|
|
|
|
|
|
2025-11-13 16:59:52 +08:00
|
|
|
|
/// <summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
/// 设置是否启用 3D 空间音效
|
2025-11-13 16:59:52 +08:00
|
|
|
|
/// </summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
public void SetIs3D(bool is3D = false)
|
2025-11-13 16:59:52 +08:00
|
|
|
|
{
|
2025-11-17 14:37:45 +08:00
|
|
|
|
if (is3D)
|
|
|
|
|
|
_spatialController.Enable3D();
|
|
|
|
|
|
else
|
|
|
|
|
|
_spatialController.Disable3D();
|
2025-11-13 16:59:52 +08:00
|
|
|
|
}
|
2025-11-14 15:57:36 +08:00
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 设置跟随对象(自动启用 3D)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void SetFollowTarget(GameObject target = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_spatialController.SetFollowTarget(target);
|
|
|
|
|
|
}
|
2025-11-14 15:57:36 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
/// 设置静态位置(自动启用 3D)
|
2025-11-14 15:57:36 +08:00
|
|
|
|
/// </summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
public void SetPosition(Vector3 position)
|
2025-11-14 15:57:36 +08:00
|
|
|
|
{
|
2025-11-17 14:37:45 +08:00
|
|
|
|
_spatialController.SetStaticPosition(position, enable3D: true);
|
2025-11-14 15:57:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
#endregion
|
2025-11-14 15:57:36 +08:00
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
#region Fade Effects
|
|
|
|
|
|
|
2025-11-14 15:57:36 +08:00
|
|
|
|
/// <summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
/// 淡入播放(需要先设置 Clip)
|
2025-11-14 15:57:36 +08:00
|
|
|
|
/// </summary>
|
2025-11-14 19:35:19 +08:00
|
|
|
|
public void PlayWithFadeIn(float duration = AudioConstant.DefaultFadeInDuration)
|
2025-11-14 15:57:36 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (_clip == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
DebugUtil.LogError("AudioPlayer: Cannot PlayWithFadeIn without clip");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_fadeEffect.FadeInDuration = duration;
|
|
|
|
|
|
_fadeEffect.StartFadeIn();
|
|
|
|
|
|
|
2025-11-14 19:35:19 +08:00
|
|
|
|
_playState = PlayState.Playing;
|
2025-11-14 15:57:36 +08:00
|
|
|
|
_audioSource.volume = 0f;
|
|
|
|
|
|
_audioSource.Play();
|
2025-11-17 14:37:45 +08:00
|
|
|
|
NotifyPlayStarted();
|
2025-11-14 15:57:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-11-17 14:37:45 +08:00
|
|
|
|
/// 淡出停止(淡出完成后自动调用 Stop)
|
2025-11-14 15:57:36 +08:00
|
|
|
|
/// </summary>
|
2025-11-14 19:35:19 +08:00
|
|
|
|
public void StopWithFadeOut(float duration = AudioConstant.DefaultFadeOutDuration)
|
|
|
|
|
|
{
|
|
|
|
|
|
_fadeEffect.StartFadeOut(duration);
|
|
|
|
|
|
}
|
2025-11-17 14:37:45 +08:00
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Query & Debug
|
2025-11-14 15:57:36 +08:00
|
|
|
|
|
2025-11-17 14:37:45 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取 AudioSource 组件
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public AudioSource GetAudioSource() => _audioSource;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取当前播放时间(秒)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public float GetPlaybackTime() => _audioSource ? _audioSource.time : -1f;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取音频频谱数据(用于可视化)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void GetSpectrumData(float[] spectrums)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_audioSource != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_audioSource.GetSpectrumData(spectrums, 0, FFTWindow.Blackman);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
}
|