Unity:在所有场景中管理音频管理器



我使用以下代码创建了一个AudioManager

using System;
using UnityEngine.Audio;
using UnityEngine;
public class AudioManager : MonoBehaviour
{
public Sound[] sounds;
public static AudioManager instance;
void Awake()
{
if (instance == null)
{
instance = this;
}
else
{
Destroy(gameObject);
return;
}
DontDestroyOnLoad(gameObject);
}
public void Play(SoundType soundType)
{
Sound s = Array.Find(this.sounds, sound => sound.soundType == soundType);
s.source = gameObject.AddComponent<AudioSource>();
s.source.clip = s.clip;
// We define volume and pitch here to be able to change them in real time
s.source.volume = s.volume;
s.source.pitch = s.pitch;
s.source.Play();
}
}

只要我在定义gameObject(包含此MonoBehaviour(的场景中启动它,它就非常有效。 但是,出于某些调试目的,我确实单独启动了一些场景,并且未定义包含AudioManagergameObject。我应该如何解决这个问题?

所以有两个任务:

  • 您需要AudioManager或实际上更好地说AudioSource实例才能访问/实例到任何场景中
  • 您想要填充List<Audio clip>

为了将两者结合在一起,我会使用ScriptableObject

[CreateAssetMenu]
public class AudioData : ScriptableObject
{
public List<Sound> sounds = new List<Sound>();
}

通过右键单击资产 &右箭头;创建&向右箭头;音频数据来创建实例

在这里,您可以填充Sounds列表 .

然后我直接使用带有延迟实例化的单例,以便在场景中找不到的情况下初始化一个,甚至可以与[RuntimeInitializeOnLoadMethod]结合使用

标记为[RuntimeInitializeOnLoadMethod]的方法在游戏加载后调用。

这是在所有调用完成后调用的Awake因此要么当时存在实例,要么现在创建实例。

例如

public class AudioManager : MonoBehaviour
{
// if you have it in the scene you can reference these right away
[SerializeField] private AudioData audioData;
[SerializeField] private AudioSource audioSource;
// backing field for actually store the Singleton instance
private static AudioManager _instance;
// public access for the Singleton
// and lazy instantiation if not exists
public static AudioManager Instance
{
get
{
// if exists directly return
if(_instance) return instance;
// otherwise search it in the scene
_instance = FindObjectOfType<AudioManager>();
// found it?
if(_instance) return instance;
// otherwise create and initialize it
CreateInstance();
return _instance;
}
}
private void Awake()
{
if (_instance && _instance != this)
{
Destroy(gameObject);
return;
}
InitializeInstance(this);
}
[RuntimeInitializeOnLoadMethod]
private static void CreateInstance()
{
// skip if already exists
if(_instance) return;
InitializeInstance(new GameObject (nameof(AudioManager)).AddComponent<AudioManager>());         
}
private static void InitializeInstance(AudioManager instance)
{
_instance = instance;
DontDestroyOnLoad(gameObject);
if(!_instance.audioSource) _instance.audioSource = _instance.AddComponent<AudioSource>();
if(_instance.audioData) return;
var audioDatas = Resources.FindObjectsOfType<AudioData>();
if(audioDatas.Length == 0)
{
Debug.LogError("No Instance of AudioData found! Don't forget to create that ScriptableObject!");
return;
}
_instance.audioData = audioDatas[0];
}
public void Play(SoundType soundType)
{
Sound s = audioData.sounds.First(sound => sound.soundType == soundType);
s.source = audioSource;
s.source.clip = s.clip;
// We define volume and pitch here to be able to change them in real time
s.source.volume = s.volume;
s.source.pitch = s.pitch;
s.source.Play();
}
}

您可以使用自动构造的单例。首次调用AudioManager.Instance时,它将生成一个新的游戏对象并将AudioManager脚本附加到该对象。

public class AudioManager : MonoBehaviour
{
static AudioManager instance;
public static AudioManager Instance => instance ?? (instance = new GameObject("AudioManager", typeof(AudioManager)).GetComponent<AudioManager>());
public void PlaySound(SoundType soundType)
{
Debug.Log("Play Sound: " + soundType);
}
}

使音频管理器成为单例,并在您需要的每个场景中访问它。
使用此模式:http://wiki.unity3d.com/index.php/Singleton

请注意,您将不想执行

s.source = gameObject.AddComponent<AudioSource>();

每次玩。 当您播放声音时,您最终会得到一堆音频源。 您应该检查是否存在,然后在需要时创建它。 此外,如果您一次只播放一种声音,则可以只使用一个音频源。

最新更新