NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Framework/Audio/AudioPlayer.cs

487 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Collections.Generic;
using PhxhSDK;
using UnityEngine;
using UnityEngine.Networking;
public class AudioPlayer: AudioBase
{
// 静态字段已迁移到 AudioVolumeSettings 类
// 为了向后兼容,保留静态属性(委托到 AudioVolumeSettings
public static float GlobalVolume
{
get => AudioVolumeSettings.Instance.GlobalVolume;
set => AudioVolumeSettings.Instance.GlobalVolume = value;
}
public static float GlobalMusicVolume
{
get => AudioVolumeSettings.Instance.MusicVolume;
set => AudioVolumeSettings.Instance.MusicVolume = value;
}
public static float GlobalSoundVolume
{
get => AudioVolumeSettings.Instance.SoundVolume;
set => AudioVolumeSettings.Instance.SoundVolume = value;
}
public static float GlobalSpeakVolume
{
get => AudioVolumeSettings.Instance.SpeakVolume;
set => AudioVolumeSettings.Instance.SpeakVolume = value;
}
private float normalizeVolume = 1f;
protected AudioSource _audioSource;
private bool _isSpeak;
private static long _curPlayID;
private long _playID = -1; //播放ID越小越早
private AudioClip _clip;
private long _playTime; //最近一次播放的时间戳
public static Dictionary<string, int> LoadedPath = new();
public long playTime => _playTime;
public AudioClip Clip => _clip;
public long PlayID => _playID;
public bool IsSpeak => _isSpeak;
public float Volume => _audioSource.volume;
// 淡入淡出效果(使用独立的效果类)
private AudioFadeEffect _fadeEffect;
// 空间音效控制器(使用独立的控制器类)
private AudioSpatialController _spatialController;
private bool _isPlayEnd
{
get
{
if (!_audioSource || !_clip)
{
return false;
}
if (_audioSource.isPlaying)
return _audioSource.time > _clip.length;
else
return true;
}
}
#region Construct
public AudioPlayer(AudioType audioType, GameObject rootGo, GameObject posGo, AudioInfo audioInfo,
bool loop = false, bool is3D = false)
{
this.audioType = audioType;
_rootGo = rootGo;
_audioSource = _GetSource();
_audioSource.volume = AudioVolumeSettings.Instance.GlobalVolume;
targetVolume = 1f;
_isSpeak = audioInfo.isSpeak;
// 初始化淡入淡出效果
_fadeEffect = new AudioFadeEffect(fadeInDuration: 4f, fadeOutDuration: 4f);
// 初始化空间音效控制器
_spatialController = new AudioSpatialController(_rootGo.transform, _audioSource);
// 如果构造时指定了跟随对象,设置跟随
if (posGo != null)
{
_spatialController.SetFollowTarget(posGo);
}
}
private AudioSource _GetSource()
{
var source = _rootGo.GetComponent<AudioSource>();
if (!source)
{
source = _rootGo.AddComponent<AudioSource>();
}
return source;
}
#endregion
#region Inherit
public override void Update(float dt)
{
if (!_audioSource || !_clip)
{
return;
}
// 更新淡入淡出效果
bool shouldStop = _fadeEffect.Update(dt);
if (playState == PlayState.Playing || _audioSource.isPlaying)
{
switch (audioType)
{
case (AudioType.Music):
{
_SetMusicVolume();
break;
}
case (AudioType.Sound):
{
if (_isSpeak)
{
_SetSpeakVolume();
}
else
{
_SetSoundVolume();
}
break;
}
default:
break;
}
}
if (playState == PlayState.Paused)
{
return;
}
// 更新空间位置跟随
if (playState == PlayState.Playing)
{
_spatialController.Update();
}
// 更新播放状态
// 检查是否应该停止(播放结束或淡出完成)
if (_isPlayEnd || shouldStop || playState == PlayState.Stopped)
{
if (playState == PlayState.Loading)
return;
Stop();
}
}
public override void Pause()
{
_audioSource.Pause();
playState = PlayState.Paused;
}
public override void Resume()
{
_audioSource.UnPause();
playState = PlayState.Playing;
}
public override void Play(float volume = 1f)
{
playState = PlayState.Playing;
_fadeEffect.Stop(); // 停止任何淡入淡出效果
targetVolume = 1f;
_audioSource.Play();
_playID = _GenPlayID();
_playTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
AudioManager.Instance.AudioMgrObj.Add2Playing(audioType, audioID, _isSpeak);
}
public void PlayWithFade(float volume = 1f)
{
playState = PlayState.Playing;
_audioSource.Play();
_playID = _GenPlayID();
AudioManager.Instance.AudioMgrObj.RemovePlaying(audioType, audioID);
}
public new void Stop()
{
_fadeEffect.Stop(); // 停止淡入淡出效果
AudioManager.Instance.AudioMgrObj.RemovePlaying(audioType, audioID);
if (_isPlayEnd)
{
playState = PlayState.Stopped;
return;
}
if (_audioSource)
{
_audioSource.Stop();
}
base.Stop();
}
public void StopWithFade(float fadeOutTime = 1f)
{
_fadeEffect.StartFadeOut(fadeOutTime);
}
#endregion
#region Utils
private long _GenPlayID()
{
return ++_curPlayID;
}
public static void ResetPlayID()
{
_curPlayID = 0;
}
public AudioSource GetAudioSource()
{
return _audioSource;
}
private void _SetMusicVolume()
{
var settings = AudioVolumeSettings.Instance;
var fadeValue = _fadeEffect.FadeValue;
_audioSource.volume = fadeValue * settings.MusicVolume * settings.GlobalVolume * targetVolume * normalizeVolume;
}
private void _SetSoundVolume()
{
var settings = AudioVolumeSettings.Instance;
var fadeValue = _fadeEffect.FadeValue;
_audioSource.volume = fadeValue * settings.SoundVolume * settings.GlobalVolume * targetVolume * normalizeVolume;
}
private void _SetSpeakVolume()
{
var settings = AudioVolumeSettings.Instance;
var fadeValue = _fadeEffect.FadeValue;
_audioSource.volume = fadeValue * settings.SpeakVolume * settings.GlobalVolume * targetVolume * normalizeVolume;
}
#endregion
#region API
public void Play(string cueName, AudioInfo audioInfo, bool isLoop = false)
{
targetVolume = 1f;
_fadeEffect.Stop(); // 停止任何淡入淡出效果
playState = PlayState.Playing;
_playID = _GenPlayID();
AudioManager.Instance.AudioMgrObj.Add2Playing(audioType, audioID, _isSpeak);
}
public void Play(string path)
{
playState = PlayState.Loading;
PlayAsync(path);
}
private async void PlayAsync(string path)
{
_clip = await AssetManager.Instance.LoadAssetAsync<AudioClip>(path, null, true);
if (LoadedPath.ContainsKey(path))
{
++LoadedPath[path];
}
else
{
LoadedPath.TryAdd(path, 1);
}
if (!_clip)
{
playState = PlayState.Stopped;
return;
}
_audioSource.clip = _clip;
_fadeEffect.Stop(); // 停止任何淡入淡出效果
targetVolume = 1f;
_playID = _GenPlayID();
AudioManager.Instance.AudioMgrObj.Add2Playing(audioType, audioID, _isSpeak);
_audioSource.Play();
playState = PlayState.Playing;
}
public async void PlayWithFade(string path, float fadeInTime = 4f, float fadeOutTime = 4f)
{
_clip = await AssetManager.Instance.LoadAssetAsync<AudioClip>(path, null, true);
if (LoadedPath.ContainsKey(path))
{
++LoadedPath[path];
}
else
{
LoadedPath.TryAdd(path, 1);
}
if (!_clip)
{
return;
}
_audioSource.clip = _clip;
// 设置淡入淡出时长并启动淡入
_fadeEffect.FadeInDuration = fadeInTime;
_fadeEffect.FadeOutDuration = fadeOutTime;
_fadeEffect.StartFadeIn();
targetVolume = 1f;
_audioSource.volume = 0f;
playState = PlayState.Playing;
_playID = _GenPlayID();
AudioManager.Instance.AudioMgrObj.Add2Playing(audioType, audioID, _isSpeak);
_audioSource.Play();
}
/// <summary>
/// 设置是否启用 3D 空间音效
/// </summary>
public void SetIs3D(bool is3D = false)
{
if (is3D)
{
_spatialController.Enable3D();
}
else
{
_spatialController.Disable3D();
}
}
/// <summary>
/// 设置跟随对象(自动启用 3D
/// </summary>
public void SetPosObj(GameObject go = null)
{
_spatialController.SetFollowTarget(go);
}
/// <summary>
/// 设置静态位置
/// </summary>
public void SetPos(Vector3 position)
{
_spatialController.SetStaticPosition(position, enable3D: true);
}
public void SetIsLoop(bool isLoop)
{
loop = isLoop;
_audioSource.loop = isLoop;
}
public void SetIsSpeak(bool isSpeak)
{
_isSpeak = isSpeak;
}
public void SetNormalizeVolume(float vol = 1f)
{
normalizeVolume = vol;
}
/// <summary>
/// 启动淡入效果(已弃用,建议直接使用 PlayWithFade
/// </summary>
[System.Obsolete("Use PlayWithFade instead")]
public void SetIsFadeIn(bool isFadeIn)
{
if (isFadeIn)
{
_fadeEffect.StartFadeIn();
}
else
{
_fadeEffect.Stop();
}
}
public string GetCueSheetName()
{
if (_audioSource)
{
return _clip.name;
}
return "";
}
public float GetCurPlayLength()
{
if (_audioSource)
{
return _audioSource.time;
}
return -1;
}
public float GetTime()
{
if (!_audioSource)
return -1;
return _audioSource.time;
}
public static void ReleaseLoadedAssets()
{
foreach (var kv in LoadedPath)
{
var key = kv.Key;
var count = kv.Value;
while (count > 0)
{
AssetManager.Instance.Unload(key, false, true);
--count;
}
}
}
/// <summary>
/// 获取音频频谱数据(用于可视化)
/// </summary>
public void GetSpectrumData(float[] spectrums)
{
if (_audioSource != null)
{
_audioSource.GetSpectrumData(spectrums, 0, FFTWindow.Blackman);
}
}
#endregion
}
public class AudioConstant
{
/// <summary>
/// 最大音乐播放数
/// </summary>
public const int MaxMusicCount = 1;
/// <summary>
/// 最大音频播放数
/// </summary>
public const int MaxSoundCount = 100;
/// <summary>
/// 最大语音播放数
/// </summary>
public const int MaxSpeakCount = 1;
/// <summary>
/// 优先级
/// </summary>
public const int MaxPriority = 99;
public const int MinPriority = 0;
public const int DefaultPriority = 29;
public const int LowPriority = 30;
}