Unity2D开发入门-资源管理器及音频播放

前言

在游戏的初始场景中 我们创建这样的结构

image-20230725001250160

其中GameObject挂载GameStart脚本并保证不被销毁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using UnityEngine;
using UnityEngine.SceneManagement;

public class GameStart : MonoBehaviour
{
private void Awake()
{
DontDestroyOnLoad(this);
SceneManager.LoadScene("Menu");
}

[RuntimeInitializeOnLoadMethod]
public static void OnGameLoad()
{
if (SceneManager.GetActiveScene().name == "GameStart")
{
return;
}

SceneManager.LoadScene("GameStart");
}
}

这样它的子物体也就不会被销毁了,两个子物体分别挂载下面的两个脚本。

这样我们就可以全局去加载资源和播放音乐了。

资源管理器

加载的资源要放在Assets/Resources目录下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using System.Collections;
using UnityEngine;
using UnityEngine.Events;

public class ResourceManager : MonoBehaviour
{
public static ResourceManager Instance;

private void Awake()
{
Instance = this;
}

/// <summary>
/// 同步加载
/// </summary>
/// <param name="asssetName"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T Load<T>(string asssetName) where T : Object
{
var asset = Resources.Load<T>(asssetName);
return asset is GameObject ? Instantiate(asset) : asset;
}

/// <summary>
/// 异步加载
/// </summary>
/// <param name="assetName"></param>
/// <param name="callback"></param>
/// <typeparam name="T"></typeparam>
public void LoadAsync<T>(string assetName, UnityAction<T> callback) where T : Object
{
StartCoroutine(LoadAsyncCoroutine(assetName, callback));
}


/// <summary>
/// 异步加载
/// </summary>
/// <param name="assetName"></param>
/// <param name="callback"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
private IEnumerator LoadAsyncCoroutine<T>(string assetName, UnityAction<T> callback) where T : Object
{
var request = Resources.LoadAsync<T>(assetName);
yield return request;
if (request.asset is GameObject)
{
callback(Instantiate(request.asset) as T);
}
else
{
callback(request.asset as T);
}
}
}

加载音乐

我们创建一个音效管理器,用来管理音乐的播放和音效的播放。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
using UnityEngine;
using UnityEngine.Events;

public class SoundManager : MonoBehaviour
{
private AudioSource _musicSource;
public float musicVolume = 0.2f;

private AudioSource[] _soundSource;
public float soundVolume = 1f;
private int _soundSourceIndex = 0;

public static SoundManager Instance;

private void Awake()
{
Instance = this;
// Music
MusicInit();
//Sound
SoundInit();
}

#region Music
private void MusicInit()
{
GameObject musicGameObject = new GameObject { name = "Music Source" };
musicGameObject.transform.SetParent(transform);
_musicSource = musicGameObject.AddComponent<AudioSource>();
}

public void PlayMusic(string musicPath)
{
ResourceManager.Instance.LoadAsync<AudioClip>
(
musicPath,
clip =>
{
_musicSource.clip = clip;
_musicSource.loop = true;
_musicSource.volume = musicVolume;
_musicSource.Play();
}
);
}

public void StopMusic()
{
if (_musicSource.isPlaying)
{
_musicSource.Stop();
}
}

#endregion


#region Sound
private void SoundInit()
{
_soundSource = new AudioSource[10];
for (int i = 0; i < _soundSource.Length; i++)
{
GameObject soundGameObject = new GameObject { name = "Sound Source" + i };
soundGameObject.transform.SetParent(transform);
_soundSource[i] = soundGameObject.AddComponent<AudioSource>();
}
}

public void PlaySound
(
string soundPath,
bool isLoop = false,
UnityAction<AudioSource> callback = null
)
{
ResourceManager.Instance.LoadAsync<AudioClip>
(
soundPath,
clip =>
{
AudioSource soundSource = _soundSource[_soundSourceIndex];
soundSource.clip = clip;
soundSource.loop = isLoop;
soundSource.volume = soundVolume;
soundSource.Play();
callback?.Invoke(soundSource);
_soundSourceIndex++;
_soundSourceIndex %= _soundSource.Length;
}
);
}

public void StopSound(string soundName)
{
foreach (var audioSource in _soundSource)
{
if (audioSource.isPlaying && audioSource.clip.name == soundName)
{
audioSource.Stop();
}
}
}

public void StopAllSounds()
{
foreach (var audioSource in _soundSource)
{
if (audioSource.isPlaying)
{
audioSource.Stop();
}
}
}

#endregion
}

这样如果播放背景音乐我们可以调用

1
SoundManager.Instance.PlayMusic("Music/Organix");

如果播放音效可以调用

比如我这里射击键是J,按J的时候播放射击音效

1
2
3
4
if (Input.GetKeyDown(KeyCode.J))
{
SoundManager.Instance.PlaySound("Sound/gun/pistol");
}

注意文件的目录结构为

Assets => Resources => Music => Organix.mp3

Assets => Resources => Sound=> gun => pistol.mp3

也就是说我们必须要把加载的资源放在Assets/Resources目录下