@cc-component/cc-core 1.6.7 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,160 +1,181 @@
|
|
|
1
|
-
//AudioUtil.ts
|
|
2
|
-
import { Node, AudioSource, AudioClip,
|
|
1
|
+
// AudioUtil.ts
|
|
2
|
+
import { Node, AudioSource, AudioClip, director } from 'cc';
|
|
3
3
|
import { ResourceManager } from './ResourceManager';
|
|
4
4
|
import { BundleConfigName } from '../config/CommonEnum';
|
|
5
5
|
import { EDITOR } from 'cc/env';
|
|
6
|
+
|
|
6
7
|
/**
|
|
7
8
|
* @en
|
|
8
|
-
*
|
|
9
|
+
* This is a singleton class for audio playback, can be easily called from anywhere in your project.
|
|
9
10
|
* @zh
|
|
10
|
-
*
|
|
11
|
+
* 这是一个用于播放音频的单例类,可以很方便地在项目的任何地方调用。
|
|
11
12
|
*/
|
|
12
13
|
export class AudioUtil {
|
|
13
|
-
|
|
14
|
-
|
|
15
14
|
private _audioSource: AudioSource;
|
|
16
|
-
|
|
15
|
+
public audioSourceShot: AudioSource;
|
|
17
16
|
|
|
17
|
+
// 用于存储背景音乐播放完成的回调
|
|
18
|
+
private _musicCompleteCallback: (() => void) | undefined;
|
|
19
|
+
// 用于存储背景音乐播放完成的回调-音效
|
|
20
|
+
private _musicCompleteCallbackShot: (() => void) | undefined;
|
|
18
21
|
constructor() {
|
|
19
22
|
if (EDITOR) return;
|
|
20
|
-
//@en create a node as AudioUtil
|
|
21
|
-
//@zh 创建一个节点作为 AudioUtil
|
|
22
|
-
let AudioUtil = new Node();
|
|
23
|
-
AudioUtil.name = '__AudioUtil__';
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
// 创建主音频节点
|
|
25
|
+
const audioNode = new Node('__AudioUtil__');
|
|
26
|
+
audioNode.name = '__AudioUtil__';
|
|
27
|
+
director.getScene().addChild(audioNode);
|
|
28
|
+
director.addPersistRootNode(audioNode);
|
|
29
|
+
|
|
30
|
+
// 主 AudioSource(用于背景音乐)
|
|
31
|
+
this._audioSource = audioNode.addComponent(AudioSource);
|
|
32
|
+
this._audioSource.playOnAwake = false;
|
|
33
|
+
this._audioSource.volume = this.music_volume;
|
|
34
|
+
|
|
35
|
+
// 监听播放结束事件(仅对非循环 clip 有效)
|
|
36
|
+
audioNode.on(AudioSource.EventType.ENDED, this.onAudioEnded, this);
|
|
37
|
+
// 初始化音效 AudioSource
|
|
38
|
+
this.AddAudioShot();
|
|
39
|
+
}
|
|
28
40
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
41
|
+
private onAudioEnded() {
|
|
42
|
+
if (this._musicCompleteCallback) {
|
|
43
|
+
this._musicCompleteCallback();
|
|
44
|
+
this._musicCompleteCallback = undefined; // 避免重复触发
|
|
45
|
+
}
|
|
46
|
+
}
|
|
32
47
|
|
|
33
|
-
//@en add AudioSource componrnt to play audios.
|
|
34
|
-
//@zh 添加 AudioSource 组件,用于播放音频。
|
|
35
|
-
this._audioSource = AudioUtil.addComponent(AudioSource);
|
|
36
|
-
this._audioSource.playOnAwake = false
|
|
37
48
|
|
|
38
|
-
|
|
49
|
+
private AddAudioShot() {
|
|
50
|
+
const audioNode2 = new Node('__AudioUtil__2');
|
|
51
|
+
this._audioSource.node.addChild(audioNode2);
|
|
52
|
+
audioNode2.name = '__AudioUtil__2';
|
|
53
|
+
this.audioSourceShot = audioNode2.addComponent(AudioSource);
|
|
54
|
+
this.audioSourceShot.playOnAwake = false;
|
|
55
|
+
this.audioSourceShot.loop = false;
|
|
56
|
+
// 监听播放结束事件(仅对非循环 clip 有效)
|
|
57
|
+
audioNode2.on(AudioSource.EventType.ENDED, this.onAudioEndedShot, this);
|
|
39
58
|
}
|
|
40
59
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
this._audioSource2.playOnAwake = false
|
|
47
|
-
this._audioSource2.loop = false
|
|
60
|
+
private onAudioEndedShot() {
|
|
61
|
+
if (this._musicCompleteCallbackShot) {
|
|
62
|
+
this._musicCompleteCallbackShot();
|
|
63
|
+
this._musicCompleteCallbackShot = undefined; // 避免重复触发
|
|
64
|
+
}
|
|
48
65
|
}
|
|
49
66
|
|
|
50
67
|
public get audioSource() {
|
|
51
68
|
return this._audioSource;
|
|
52
69
|
}
|
|
53
70
|
|
|
54
|
-
|
|
55
|
-
* @en
|
|
56
|
-
* play short audio, such as strikes,explosions
|
|
57
|
-
* @zh
|
|
58
|
-
* 播放短音频,比如 打击音效,爆炸音效等
|
|
59
|
-
* @param sound clip or url for the audio
|
|
60
|
-
* @param volume
|
|
61
|
-
*/
|
|
62
|
-
async playOneShot(sound: AudioClip | string, volume: number = 0.5) {
|
|
63
|
-
const v = this.sound_volume
|
|
64
|
-
if (sound instanceof AudioClip) {
|
|
65
|
-
this._audioSource.playOneShot(sound, v);
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
let clip = await ResourceManager.loadAsset<AudioClip>(BundleConfigName.common, sound, AudioClip)
|
|
69
|
-
this._audioSource.playOneShot(clip, v);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
71
|
+
// ==================== 音量管理 ====================
|
|
73
72
|
get sound_volume(): number {
|
|
74
|
-
|
|
75
|
-
return v
|
|
73
|
+
return App.storage.getNumber('sound_volume', 1);
|
|
76
74
|
}
|
|
77
75
|
set sound_volume(value: number) {
|
|
78
|
-
App.storage.set('sound_volume', value)
|
|
76
|
+
App.storage.set('sound_volume', value);
|
|
79
77
|
}
|
|
80
78
|
|
|
81
79
|
get music_volume(): number {
|
|
82
|
-
|
|
83
|
-
return v
|
|
80
|
+
return App.storage.getNumber('music_volume', 1);
|
|
84
81
|
}
|
|
85
82
|
set music_volume(value: number) {
|
|
86
83
|
this._audioSource.volume = value;
|
|
87
|
-
App.storage.set('music_volume', value)
|
|
84
|
+
App.storage.set('music_volume', value);
|
|
88
85
|
}
|
|
86
|
+
|
|
87
|
+
// ==================== 背景音乐控制 ====================
|
|
89
88
|
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* @
|
|
93
|
-
*
|
|
94
|
-
* @param
|
|
95
|
-
* @param
|
|
89
|
+
* 播放背景音乐(支持完成回调)
|
|
90
|
+
* @param params.path 音频路径
|
|
91
|
+
* @param params.bundle 资源包名(可选)
|
|
92
|
+
* @param params.loop 是否循环(默认 false)
|
|
93
|
+
* @param params.volume 音量(默认使用 music_volume)
|
|
94
|
+
* @param params.callback 播放完成回调(仅在 loop=false 时有效)
|
|
96
95
|
*/
|
|
97
|
-
async play(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
96
|
+
async play(params: {
|
|
97
|
+
path: string;
|
|
98
|
+
bundle?: string;
|
|
99
|
+
loop?: boolean;
|
|
100
|
+
volume?: number;
|
|
101
|
+
complete?: () => void;
|
|
102
|
+
}) {
|
|
103
|
+
try {
|
|
104
|
+
const clip = await this.loadAudioClip(params.bundle, params.path);
|
|
105
|
+
this._audioSource.stop(); // 停止当前播放
|
|
106
|
+
|
|
107
|
+
this._audioSource.clip = clip;
|
|
108
|
+
this._audioSource.loop = params.loop ?? false;
|
|
109
|
+
this._audioSource.volume = params.volume ?? this.music_volume;
|
|
110
|
+
|
|
111
|
+
// 设置完成回调(仅非循环时有意义)
|
|
112
|
+
this._musicCompleteCallback = (!params.loop && params.complete) ? params.complete : undefined;
|
|
113
113
|
|
|
114
|
+
this._audioSource.play();
|
|
115
|
+
} catch (e) {
|
|
116
|
+
console.error(`[AudioUtil] Failed to load or play music: ${params.path}`, e);
|
|
114
117
|
}
|
|
115
118
|
}
|
|
116
119
|
|
|
117
|
-
/**
|
|
118
|
-
* stop the audio play
|
|
119
|
-
*/
|
|
120
120
|
stop() {
|
|
121
121
|
this._audioSource.stop();
|
|
122
|
+
this._musicCompleteCallback = undefined;
|
|
122
123
|
}
|
|
123
124
|
|
|
124
|
-
/**
|
|
125
|
-
* pause the audio play
|
|
126
|
-
*/
|
|
127
125
|
pause() {
|
|
128
126
|
this._audioSource.pause();
|
|
129
127
|
}
|
|
130
128
|
|
|
131
|
-
/**
|
|
132
|
-
* resume the audio play
|
|
133
|
-
*/
|
|
134
129
|
resume() {
|
|
135
130
|
this._audioSource.play();
|
|
136
131
|
}
|
|
137
132
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
this.
|
|
149
|
-
this.
|
|
150
|
-
|
|
133
|
+
// ==================== 音效播放 ====================
|
|
134
|
+
/** 播放一次性音效(不可控,使用 playOneShot) */
|
|
135
|
+
async playShot(params: {
|
|
136
|
+
path: string;
|
|
137
|
+
bundle?: string;
|
|
138
|
+
volume?: number;
|
|
139
|
+
isMusic?: boolean;
|
|
140
|
+
complete?: () => void;
|
|
141
|
+
}) {
|
|
142
|
+
try {
|
|
143
|
+
const clip = await this.loadAudioClip(params.bundle, params.path);
|
|
144
|
+
const volume = params.volume ?? this.sound_volume;
|
|
145
|
+
if (params.isMusic) {
|
|
146
|
+
this.audioSourceShot.stop(); // 停止当前播放
|
|
147
|
+
this.audioSourceShot.clip = clip;
|
|
148
|
+
this.audioSourceShot.loop = false;
|
|
149
|
+
this.audioSourceShot.volume = volume
|
|
150
|
+
// 设置完成回调(仅非循环时有意义)
|
|
151
|
+
this._musicCompleteCallbackShot = (params.complete) ? params.complete : undefined;
|
|
152
|
+
this.audioSourceShot.play();
|
|
153
|
+
} else {
|
|
154
|
+
this._audioSource.playOneShot(clip, volume);
|
|
155
|
+
}
|
|
156
|
+
} catch (e) {
|
|
157
|
+
console.error(`[AudioUtil] Failed to play shot sound: ${params.path}`, e);
|
|
151
158
|
}
|
|
152
159
|
}
|
|
153
160
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
161
|
+
|
|
162
|
+
// ==================== 音效控制(仅对 clip + play 模式有效,当前 playOneShot 无效)====================
|
|
163
|
+
stopShotMusic() {
|
|
164
|
+
this.audioSourceShot.stop();
|
|
165
|
+
}
|
|
166
|
+
pauseShotMusic() {
|
|
167
|
+
this.audioSourceShot.pause();
|
|
168
|
+
}
|
|
169
|
+
resumeShotMusic() {
|
|
170
|
+
this.audioSourceShot.play();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ==================== 工具方法 ====================
|
|
174
|
+
private async loadAudioClip(bundle: string | undefined, path: string): Promise<AudioClip> {
|
|
175
|
+
return await ResourceManager.loadAsset<AudioClip>(
|
|
176
|
+
bundle || BundleConfigName.common,
|
|
177
|
+
path,
|
|
178
|
+
AudioClip
|
|
179
|
+
);
|
|
159
180
|
}
|
|
160
181
|
}
|
|
@@ -92,7 +92,7 @@ export class EffectSingleCase {
|
|
|
92
92
|
|
|
93
93
|
for (let i = 0; i < count; i++) {
|
|
94
94
|
let node = instantiate(App.GetAsset(params.bundle, params.path))//ViewUtil.createPrefabNode(path, bundleName);
|
|
95
|
-
node.asset_path = App.
|
|
95
|
+
node.asset_path = App.asset.getAssetKey(params.path, params.bundle)
|
|
96
96
|
np.put(node);
|
|
97
97
|
}
|
|
98
98
|
resolve();
|
|
@@ -148,7 +148,7 @@ export class EffectSingleCase {
|
|
|
148
148
|
if (params && params.bundle) bundleName = params.bundle;
|
|
149
149
|
node = instantiate(App.GetAsset(bundleName, params.path))//ViewUtil.createPrefabNode(path, bundleName);
|
|
150
150
|
// //@ts-ignore
|
|
151
|
-
node.asset_path = App.
|
|
151
|
+
node.asset_path = App.asset.getAssetKey(params.path, params.bundle)
|
|
152
152
|
// if (params && params.isPlayFinishedRelease) {
|
|
153
153
|
// node.addComponent(EffectFinishedRelease);
|
|
154
154
|
// }
|
|
@@ -292,7 +292,7 @@ export class EffectSingleCase {
|
|
|
292
292
|
this.res.set(params.path, params.bundle);
|
|
293
293
|
const prefab = await App.LoadAsset(params.bundle, params.path, Prefab);
|
|
294
294
|
const node = instantiate(prefab)
|
|
295
|
-
node.asset_path = App.
|
|
295
|
+
node.asset_path = App.asset.getAssetKey(params.path, params.bundle)
|
|
296
296
|
this.updateNode(node, params)
|
|
297
297
|
resolve(node);
|
|
298
298
|
});
|
|
@@ -40,7 +40,7 @@ export class App {
|
|
|
40
40
|
/**消息 */
|
|
41
41
|
static get message(): EventManager { return this.instance._message };
|
|
42
42
|
/**声音 */
|
|
43
|
-
static get
|
|
43
|
+
static get audio(): AudioUtil { return this.instance._audio };
|
|
44
44
|
/**声音 */
|
|
45
45
|
static get tools(): Tools { return this.instance._tools };
|
|
46
46
|
/**对象池 */
|
|
@@ -55,7 +55,7 @@ export class App {
|
|
|
55
55
|
_timeManager: TimeManager;
|
|
56
56
|
_language: LanguageManager;
|
|
57
57
|
_message: EventManager;
|
|
58
|
-
|
|
58
|
+
_audio: AudioUtil;
|
|
59
59
|
_tools: Tools;
|
|
60
60
|
_pool: EffectSingleCase;
|
|
61
61
|
_asset: ResourceManager;
|
|
@@ -89,7 +89,7 @@ export class App {
|
|
|
89
89
|
self._gui = new LayerUI();
|
|
90
90
|
self._http = new HttpManager();
|
|
91
91
|
self._message = new EventManager();
|
|
92
|
-
self.
|
|
92
|
+
self._audio = new AudioUtil();
|
|
93
93
|
self._tools = new Tools();
|
|
94
94
|
self._pool = EffectSingleCase.instance;
|
|
95
95
|
self._asset = ResourceManager.instance;
|
|
@@ -125,17 +125,6 @@ export class App {
|
|
|
125
125
|
static async PreloadDir(bundleName: string, dirName: string, pre: Function) { return ResourceManager.preloadDir(bundleName, dirName, pre) }
|
|
126
126
|
static async LoadDir(bundleName: string, dirName: string, type: any, pre: Function) { return ResourceManager.loadDir(bundleName, dirName, type, pre) }
|
|
127
127
|
|
|
128
|
-
//音乐
|
|
129
|
-
static async PlayOneShot(sound: AudioClip | string, volume: number = 1) { this.sound.playOneShot(sound, volume) }
|
|
130
|
-
static async Play(sound: AudioClip | string, volume: number = 1.0) { this.sound.play(sound, volume) }
|
|
131
|
-
static async Stop() { this.sound.stop() }
|
|
132
|
-
static async Pause() { this.sound.pause() }
|
|
133
|
-
static async Resume() { this.sound.resume() }
|
|
134
|
-
static MusicVolume(volume: number) { this.sound.music_volume = volume }
|
|
135
|
-
static SoundVolume(volume: number) { this.sound.sound_volume = volume }
|
|
136
|
-
static GetMusicVolume() { return this.sound.music_volume }
|
|
137
|
-
static GetSoundVolume() { return this.sound.sound_volume }
|
|
138
|
-
|
|
139
128
|
/**
|
|
140
129
|
* ================事件===================
|
|
141
130
|
*/
|
|
@@ -36,7 +36,7 @@ declare global {
|
|
|
36
36
|
/**消息 */
|
|
37
37
|
const message: EventManager
|
|
38
38
|
/**声音 */
|
|
39
|
-
const
|
|
39
|
+
const audio: AudioUtil;
|
|
40
40
|
/**工具类 */
|
|
41
41
|
const tools: Tools;
|
|
42
42
|
/**对象池 */
|
|
@@ -123,16 +123,6 @@ declare global {
|
|
|
123
123
|
function GetOpenWindowsConfig(): IBundleConfig[];
|
|
124
124
|
/** 显示加载转圈*/
|
|
125
125
|
function OpenLoading(is_show: boolean);
|
|
126
|
-
/**=======================================✅✅音乐======================= */
|
|
127
|
-
function PlayOneShot(sound: string, volume?: number);
|
|
128
|
-
function Play(sound: string, volume?: number);
|
|
129
|
-
function Stop();
|
|
130
|
-
function Pause();
|
|
131
|
-
function Resume();
|
|
132
|
-
function MusicVolume(volume: number);
|
|
133
|
-
function SoundVolume(volume: number);
|
|
134
|
-
function GetMusicVolume(): number;
|
|
135
|
-
function GetSoundVolume(): number;
|
|
136
126
|
|
|
137
127
|
/**=======================================✅✅常用工具======================= */
|
|
138
128
|
// function TwoBezier(param1, param2, param3, param4);
|