TH1/Unity/Assets/Scripts/TH1Audio/AudioManager.cs

308 lines
9.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @Author: 白哉
* @Description:
* @Date: 2025年05月22日 星期四 14:05:32
* @Modify:
*/
using System.Collections.Generic;
using Logic.CrashSight;
using RuntimeData;
using UnityEngine;
namespace Logic.Audio
{
public class AudioManager
{
public static AudioManager Instance = new AudioManager();
private AudioPlayer _musicPlayer;
private List<AudioPlayer> _allPlayer;
private Dictionary<string, List<AudioClip>> _clips;
private GameObject AudioRoot;
public float MusicVolume
{
get { return _musicVolume; }
set { _musicVolume = value; }
}
public float AudioVolume
{
get { return _audioVolume; }
set { _audioVolume = value; }
}
private float _musicVolume = 1;
private float _audioVolume = 1;
public void Init()
{
_allPlayer = new List<AudioPlayer>();
_clips = new Dictionary<string, List<AudioClip>>();
var path = new Dictionary<string, string>();
path["Main"] = "Audio/Main";
path["RemiliaEgyptian"] = "Audio/RemiliaEgyptian";
path["SatoriIndian"] = "Audio/SatoriIndian";
path["KanakoGermany"] = "Audio/KanakoGermany";
path["KaguyaFrench"] = "Audio/KaguyaFrench";
path["SFX/UI_buttonHover"] = "Audio/SFX/UI_buttonHover";
path["SFX/UI_buttonClick"] = "Audio/SFX/UI_buttonClick";
path["SFX/UNIT_click"] = "Audio/SFX/UNIT_click";
path["SFX/UNIT_bomb"] = "Audio/SFX/UNIT_bomb";
path["SFX/UNIT_archer"] = "Audio/SFX/UNIT_archer";
path["SFX/UNIT_hurt"] = "Audio/SFX/UNIT_hurt";
path["SFX/UNIT_move"] = "Audio/SFX/UNIT_move";
path["SFX/UNIT_attack"] = "Audio/SFX/UNIT_attack";
path["SFX/ENV_sea"] = "Audio/SFX/ENV_sea";
path["SFX/ENV_forest"] = "Audio/SFX/ENV_forest";
foreach (var kv in path)
{
_clips[kv.Key] = new List<AudioClip>();
_clips[kv.Key].Add(Resources.Load<AudioClip>(kv.Value));
}
if (!AudioRoot) AudioRoot = new GameObject();
AudioRoot.name = "AudioRoot";
var cfg = Object.FindObjectOfType<AudioClipConfig>();
if (cfg != null)
{
foreach (var clip in cfg.Clips)
{
_clips[clip.name] = new List<AudioClip>();
_clips[clip.name].Add(clip);
}
}
}
public void Update()
{
foreach (var player in _allPlayer)
{
player.Update();
if (player.State != PlayerState.Finished) continue;
if (!player.Clip) continue;
if (!_clips.ContainsKey(player.MusicName)) _clips[player.MusicName] = new List<AudioClip>();
_clips[player.MusicName].Add(player.Clip);
player.Clip = null;
}
}
public void PlayMusic(string musicName, float fadeIn, float fadeOut, bool isLoop)
{
if (!_clips.ContainsKey(musicName) || _clips[musicName].Count == 0) return;
if (_musicPlayer != null) _musicPlayer.Stop();
else _musicPlayer = GetPlayer();
if (_clips[musicName].Count > 1)
{
_musicPlayer.Clip = _clips[musicName][1];
_clips[musicName].RemoveAt(1);
}
else _musicPlayer.Clip = Object.Instantiate(_clips[musicName][0]);
if (!_musicPlayer.Clip)
{
LogSystem.LogError($"音乐资源 {musicName} 未找到或加载失败!");
return;
}
_musicPlayer.MusicName = musicName;
_musicPlayer.IsLoop = isLoop;
_musicPlayer.Length = _musicPlayer.Clip.length;
_musicPlayer.FadeInDuration = fadeIn;
_musicPlayer.FadeOutDuration = fadeOut;
_musicPlayer.VolumeRatio = MusicVolume;
_musicPlayer.Play();
}
public void StopMusic()
{
_musicPlayer?.Stop();
}
public void PlayAudio(string musicName, float fadeIn = 0f, float fadeOut = 0f, bool isLoop = false)
{
if (!_clips.ContainsKey(musicName)) return;
var player = GetPlayer();
if (_clips[musicName].Count > 1)
{
player.Clip = _clips[musicName][1];
_clips[musicName].RemoveAt(1);
}
else player.Clip = Object.Instantiate(_clips[musicName][0]);
if (!player.Clip)
{
LogSystem.LogError($"音频资源 {musicName} 未找到或加载失败!");
return;
}
player.MusicName = musicName;
player.IsLoop = isLoop;
player.Length = _musicPlayer.Clip.length;
player.FadeInDuration = fadeIn;
player.FadeOutDuration = fadeOut;
_musicPlayer.VolumeRatio = AudioVolume;
player.Play();
}
private AudioPlayer GetPlayer()
{
foreach (var player in _allPlayer)
{
if (player.State == PlayerState.Finished || player.State == PlayerState.Prepare) return player;
}
var sourceObj = new GameObject();
sourceObj.transform.SetParent(AudioRoot.transform);
var source = sourceObj.AddComponent<AudioSource>();
var newPlayer = new AudioPlayer(source);
_allPlayer.Add(newPlayer);
return newPlayer;
}
//----- InGame部分的音频 -------
private Main _main;
private MapData _map;
public void InGameAudioInit(Main main, MapData map)
{
_main = main;
_map = map;
}
public void CalculateAndPlayAmbient()
{
if (_map == null) return;
//播放环境音效。如果领土内有海洋则60%概率播放海洋。否则必播放forest
bool isForest = true;
var player = _map.PlayerMap.SelfPlayerData;
var gset = _map.GetPlayerTerritoryGridIdSet(player.Id);
foreach (var g in gset)
{
if (!_map.GridMap.GetGridDataByGid(g, out var grid)) continue;
if (grid.Terrain != TerrainType.Land)
{
isForest = Random.Range(0, 100) < 50 ? true : false;
break;
}
}
if(isForest)
PlayAudio("SFX/ENV_forest",1f);
else
PlayAudio("SFX/ENV_sea",1f);
}
public void InGameOnTurnStart()
{
CalculateAndPlayAmbient();
}
}
public enum PlayerState
{
Prepare,
FadeIn,
FadeOut,
Playing,
Finished,
}
public class AudioPlayer
{
public string MusicName;
public AudioSource Source;
public AudioClip Clip;
public bool IsLoop;
public float Length;
public float FadeInDuration;
public float FadeOutDuration;
// 音量 0-1
public float VolumeRatio;
public float StartTime;
public float EndTime;
public PlayerState State;
public AudioPlayer(AudioSource source)
{
Source = source;
State = PlayerState.Prepare;
}
public void Play()
{
StartTime = Time.time;
Source.time = 0;
Source.clip = Clip;
Source.volume = 0;
Source.loop = IsLoop;
Source.Play();
State = PlayerState.FadeIn;
}
public void Update()
{
if (Source == null) return;
UpdateSourceVolume();
}
public void Stop()
{
if (State == PlayerState.Finished || State == PlayerState.Prepare) return;
State = PlayerState.FadeOut;
EndTime = Time.time;
}
private void UpdateSourceVolume()
{
if (State == PlayerState.Finished || State == PlayerState.Prepare) return;
if (State == PlayerState.FadeIn)
{
if (Time.time - StartTime < FadeInDuration)
{
Source.volume = (Time.time - StartTime) / FadeInDuration * VolumeRatio;
}
else
{
Source.volume = 1 * VolumeRatio;
State = PlayerState.Playing;
}
}
if (State == PlayerState.Playing && !IsLoop)
{
if (Time.time - StartTime >= Length - FadeOutDuration)
{
EndTime = Time.time;
State = PlayerState.FadeOut;
}
}
if (State == PlayerState.FadeOut)
{
if (Time.time - EndTime >= FadeOutDuration)
{
Source.volume = 0;
Source.Stop();
State = PlayerState.Finished;
}
else
{
Source.volume = (FadeOutDuration - Time.time + EndTime) / FadeOutDuration * VolumeRatio;
}
}
}
}
}