mirror of
https://gitee.com/dgflash/oops-plugin-framework.git
synced 2026-05-07 19:07:30 +08:00
音乐模块支持可扩展的播放参数
This commit is contained in:
@@ -2,6 +2,7 @@ import { AudioClip, Node, NodePool } from "cc";
|
||||
import { oops } from "../../Oops";
|
||||
import { resLoader } from "../loader/ResLoader";
|
||||
import { AudioEffect } from "./AudioEffect";
|
||||
import { IAudioParams } from "./IAudio";
|
||||
|
||||
const AE_ID_MAX = 30000;
|
||||
|
||||
@@ -9,10 +10,10 @@ const AE_ID_MAX = 30000;
|
||||
export class AudioEffectPool {
|
||||
private _switch: boolean = true;
|
||||
/** 音效开关 */
|
||||
public get switch(): boolean {
|
||||
get switch(): boolean {
|
||||
return this._switch;
|
||||
}
|
||||
public set switch(value: boolean) {
|
||||
set switch(value: boolean) {
|
||||
this._switch = value;
|
||||
if (value) this.stop();
|
||||
}
|
||||
@@ -52,10 +53,21 @@ export class AudioEffectPool {
|
||||
* @param onPlayComplete 播放完成回调
|
||||
* @returns
|
||||
*/
|
||||
async load(url: string | AudioClip, bundleName: string = resLoader.defaultBundleName, onPlayComplete?: Function): Promise<number> {
|
||||
async loadAndPlay(url: string | AudioClip, params?: IAudioParams): Promise<number> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
if (!this.switch) return resolve(-1);
|
||||
|
||||
let bundleName = resLoader.defaultBundleName;
|
||||
let loop = false;
|
||||
let volume = this.volume;
|
||||
let onPlayComplete: Function = null!;
|
||||
if (params) {
|
||||
if (params.bundle != null) bundleName = params.bundle;
|
||||
if (params.loop != null) loop = params.loop;
|
||||
if (params.volume != null) volume = params.volume;
|
||||
if (params.onPlayComplete != null) onPlayComplete = params.onPlayComplete;
|
||||
}
|
||||
|
||||
// 创建音效资源
|
||||
let clip: AudioClip;
|
||||
if (url instanceof AudioClip) {
|
||||
@@ -63,6 +75,8 @@ export class AudioEffectPool {
|
||||
}
|
||||
else {
|
||||
clip = resLoader.get(url, AudioClip, bundleName)!;
|
||||
|
||||
// 加载音效资源
|
||||
if (clip == null) {
|
||||
let urls = this.res.get(bundleName);
|
||||
if (urls == null) {
|
||||
@@ -101,22 +115,24 @@ export class AudioEffectPool {
|
||||
node.name = "AudioEffect";
|
||||
node.parent = oops.audio.node;
|
||||
ae = node.addComponent(AudioEffect)!;
|
||||
ae.onComplete = () => {
|
||||
this.put(aeid, url, bundleName); // 播放完回收对象
|
||||
onPlayComplete && onPlayComplete(aeid, url, bundleName);
|
||||
// console.log(`【音效】回收,池中剩余音效播放器【${this.pool.size()}】`);
|
||||
};
|
||||
}
|
||||
else {
|
||||
node = this.pool.get()!;
|
||||
ae = node.getComponent(AudioEffect)!;
|
||||
}
|
||||
ae.onComplete = () => {
|
||||
this.put(aeid, url, bundleName); // 播放完回收对象
|
||||
onPlayComplete && onPlayComplete();
|
||||
// console.log(`【音效】回收,池中剩余音效播放器【${this.pool.size()}】`);
|
||||
};
|
||||
|
||||
// 记录正在播放的音效播放器
|
||||
this.effects.set(key, ae);
|
||||
|
||||
ae.volume = this.volume;
|
||||
ae.loop = loop;
|
||||
ae.clip = clip;
|
||||
ae.volume = volume;
|
||||
ae.currentTime = 0;
|
||||
ae.play();
|
||||
|
||||
resolve(aeid);
|
||||
@@ -147,23 +163,6 @@ export class AudioEffectPool {
|
||||
}
|
||||
}
|
||||
|
||||
/** 释放所有音效资源与对象池中播放器 */
|
||||
release() {
|
||||
// 释放正在播放的音效
|
||||
this.effects.forEach(ae => {
|
||||
ae.node.destroy();
|
||||
});
|
||||
this.effects.clear();
|
||||
|
||||
// 释放音效资源
|
||||
this.res.forEach((urls: string[], bundleName: string) => {
|
||||
urls.forEach(url => resLoader.release(url, bundleName));
|
||||
});
|
||||
|
||||
// 释放池中播放器
|
||||
this.pool.clear();
|
||||
}
|
||||
|
||||
/** 停止播放所有音效 */
|
||||
stop() {
|
||||
this.effects.forEach(ae => {
|
||||
@@ -188,4 +187,21 @@ export class AudioEffectPool {
|
||||
ae.pause();
|
||||
});
|
||||
}
|
||||
|
||||
/** 释放所有音效资源与对象池中播放器 */
|
||||
release() {
|
||||
// 释放正在播放的音效
|
||||
this.effects.forEach(ae => {
|
||||
ae.node.destroy();
|
||||
});
|
||||
this.effects.clear();
|
||||
|
||||
// 释放音效资源
|
||||
this.res.forEach((urls: string[], bundleName: string) => {
|
||||
urls.forEach(url => resLoader.release(url, bundleName));
|
||||
});
|
||||
|
||||
// 释放池中播放器
|
||||
this.pool.clear();
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { AudioClip, Component } from "cc";
|
||||
import { oops } from "../../Oops";
|
||||
import { AudioEffectPool } from "./AudioEffectPool";
|
||||
import { AudioMusic } from "./AudioMusic";
|
||||
import { IAudioParams } from "./IAudio";
|
||||
|
||||
const LOCAL_STORE_KEY = "game_audio";
|
||||
|
||||
@@ -19,100 +20,15 @@ export class AudioManager extends Component {
|
||||
effect: AudioEffectPool = new AudioEffectPool();
|
||||
|
||||
/** 音乐管理状态数据 */
|
||||
private local_data: any = {};
|
||||
|
||||
/**
|
||||
* 设置背景音乐播放完成回调
|
||||
* @param callback 背景音乐播放完成回调
|
||||
*/
|
||||
setMusicComplete(callback: Function | null = null) {
|
||||
this.music.onComplete = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放背景音乐
|
||||
* @param url 资源地址
|
||||
* @param callback 音乐播放完成事件
|
||||
* @param bundleName 资源包名
|
||||
*/
|
||||
playMusic(url: string, callback?: Function, bundleName?: string) {
|
||||
if (this.music.switch) {
|
||||
this.music.loop = false;
|
||||
this.music.load(url, callback, bundleName).then();
|
||||
}
|
||||
}
|
||||
|
||||
/** 循环播放背景音乐 */
|
||||
playMusicLoop(url: string, bundleName?: string) {
|
||||
if (this.music.switch) {
|
||||
this.music.loop = true;
|
||||
this.music.load(url, null!, bundleName).then();
|
||||
}
|
||||
}
|
||||
|
||||
/** 停止背景音乐播放 */
|
||||
stopMusic() {
|
||||
if (this.music.switch && this.music.playing) {
|
||||
this.music.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取背景音乐播放进度
|
||||
*/
|
||||
get progressMusic(): number {
|
||||
return this.music.progress;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置背景乐播放进度
|
||||
* @param value 播放进度值
|
||||
*/
|
||||
set progressMusic(value: number) {
|
||||
this.music.progress = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取背景音乐音量
|
||||
*/
|
||||
get volumeMusic(): number {
|
||||
return this.music.volume;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置背景音乐音量
|
||||
* @param value 音乐音量值
|
||||
*/
|
||||
set volumeMusic(value: number) {
|
||||
this.music.volume = value;
|
||||
this.save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取背景音乐开关值
|
||||
*/
|
||||
get switchMusic(): boolean {
|
||||
return this.music.switch;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置背景音乐开关值
|
||||
* @param value 开关值
|
||||
*/
|
||||
set switchMusic(value: boolean) {
|
||||
this.music.switch = value;
|
||||
if (!value) this.music.stop();
|
||||
this.save();
|
||||
}
|
||||
private localData: any = {};
|
||||
|
||||
/**
|
||||
* 播放音效
|
||||
* @param url 资源地址
|
||||
* @param callback 加载完成回调
|
||||
* @param bundleName 资源包名
|
||||
* @param params 音效参数
|
||||
*/
|
||||
playEffect(url: string | AudioClip, bundleName?: string, onPlayComplete?: Function): Promise<number> {
|
||||
return this.effect.load(url, bundleName, onPlayComplete);
|
||||
playEffect(url: string | AudioClip, params?: IAudioParams): Promise<number> {
|
||||
return this.effect.loadAndPlay(url, params);
|
||||
}
|
||||
|
||||
/** 回收音效播放器 */
|
||||
@@ -120,35 +36,6 @@ export class AudioManager extends Component {
|
||||
this.effect.put(aeid, url, bundleName);
|
||||
}
|
||||
|
||||
/** 获取音效音量 */
|
||||
get volumeEffect(): number {
|
||||
return this.effect.volume;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置获取音效音量
|
||||
* @param value 音效音量值
|
||||
*/
|
||||
set volumeEffect(value: number) {
|
||||
this.effect.volume = value;
|
||||
this.save();
|
||||
}
|
||||
|
||||
/** 获取音效开关值 */
|
||||
get switchEffect(): boolean {
|
||||
return this.effect.switch;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置音效开关值
|
||||
* @param value 音效开关值
|
||||
*/
|
||||
set switchEffect(value: boolean) {
|
||||
this.effect.switch = value;
|
||||
if (!value) this.effect.stop();
|
||||
this.save();
|
||||
}
|
||||
|
||||
/** 恢复当前暂停的音乐与音效播放 */
|
||||
resumeAll() {
|
||||
if (!this.music.playing && this.music.progress > 0) this.music.play();
|
||||
@@ -169,20 +56,20 @@ export class AudioManager extends Component {
|
||||
|
||||
/** 保存音乐音效的音量、开关配置数据到本地 */
|
||||
save() {
|
||||
this.local_data.volume_music = this.music.volume;
|
||||
this.local_data.volume_effect = this.effect.volume;
|
||||
this.local_data.switch_music = this.music.switch;
|
||||
this.local_data.switch_effect = this.effect.switch;
|
||||
this.localData.volume_music = this.music.volume;
|
||||
this.localData.volume_effect = this.effect.volume;
|
||||
this.localData.switch_music = this.music.switch;
|
||||
this.localData.switch_effect = this.effect.switch;
|
||||
|
||||
oops.storage.set(LOCAL_STORE_KEY, this.local_data);
|
||||
oops.storage.set(LOCAL_STORE_KEY, this.localData);
|
||||
}
|
||||
|
||||
/** 本地加载音乐音效的音量、开关配置数据并设置到游戏中 */
|
||||
load() {
|
||||
this.music = this.getComponent(AudioMusic) || this.addComponent(AudioMusic)!;
|
||||
|
||||
this.local_data = oops.storage.getJson(LOCAL_STORE_KEY);
|
||||
if (this.local_data) {
|
||||
this.localData = oops.storage.getJson(LOCAL_STORE_KEY);
|
||||
if (this.localData) {
|
||||
try {
|
||||
this.setState();
|
||||
}
|
||||
@@ -196,14 +83,14 @@ export class AudioManager extends Component {
|
||||
}
|
||||
|
||||
private setState() {
|
||||
this.music.volume = this.local_data.volume_music;
|
||||
this.effect.volume = this.local_data.volume_effect;
|
||||
this.music.switch = this.local_data.switch_music;
|
||||
this.effect.switch = this.local_data.switch_effect;
|
||||
this.music.volume = this.localData.volume_music;
|
||||
this.effect.volume = this.localData.volume_effect;
|
||||
this.music.switch = this.localData.switch_music;
|
||||
this.effect.switch = this.localData.switch_effect;
|
||||
}
|
||||
|
||||
private setStateDefault() {
|
||||
this.local_data = {};
|
||||
this.localData = {};
|
||||
this.music.volume = 1;
|
||||
this.effect.volume = 1;
|
||||
this.music.switch = true;
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
*/
|
||||
import { AudioClip, AudioSource, _decorator } from 'cc';
|
||||
import { resLoader } from '../loader/ResLoader';
|
||||
import { IAudioParams } from './IAudio';
|
||||
|
||||
const { ccclass, menu } = _decorator;
|
||||
const { ccclass } = _decorator;
|
||||
|
||||
/**
|
||||
* 背景音乐
|
||||
@@ -15,25 +16,20 @@ const { ccclass, menu } = _decorator;
|
||||
*/
|
||||
@ccclass('AudioMusic')
|
||||
export class AudioMusic extends AudioSource {
|
||||
/** 背景音乐开关 */
|
||||
switch: boolean = true;
|
||||
/** 背景音乐播放完成回调 */
|
||||
onComplete: Function | null = null;
|
||||
|
||||
private _progress: number = 0;
|
||||
private _isLoading: boolean = false;
|
||||
private _nextBundleName: string = null!; // 下一个音乐资源包
|
||||
private _nextUrl: string = null!; // 下一个播放音乐
|
||||
private _nextUrl: string = null!;
|
||||
private _nextParams: IAudioParams = null!;
|
||||
private _params: IAudioParams = null!;
|
||||
|
||||
start() {
|
||||
// this.node.on(AudioSource.EventType.STARTED, this.onAudioStarted, this);
|
||||
this.node.on(AudioSource.EventType.ENDED, this.onAudioEnded, this);
|
||||
/** 背景音乐开关 */
|
||||
private _switch: boolean = true;
|
||||
get switch(): boolean {
|
||||
return this._switch;
|
||||
}
|
||||
|
||||
// private onAudioStarted() { }
|
||||
|
||||
private onAudioEnded() {
|
||||
this.onComplete && this.onComplete();
|
||||
set switch(value: boolean) {
|
||||
this._switch = value;
|
||||
if (!value) this.stop();
|
||||
}
|
||||
|
||||
/** 获取音乐播放进度 */
|
||||
@@ -51,34 +47,59 @@ export class AudioMusic extends AudioSource {
|
||||
this.currentTime = value * this.duration;
|
||||
}
|
||||
|
||||
start() {
|
||||
// this.node.on(AudioSource.EventType.STARTED, this.onAudioStarted, this);
|
||||
this.node.on(AudioSource.EventType.ENDED, this.onAudioEnded, this);
|
||||
}
|
||||
|
||||
// private onAudioStarted() { }
|
||||
|
||||
private onAudioEnded() {
|
||||
if (this._params && this._params.onPlayComplete) {
|
||||
this._params.onPlayComplete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载音乐并播放
|
||||
* @param url 音乐资源地址
|
||||
* @param callback 加载完成回调
|
||||
* @param bundleName 资源包名
|
||||
* @param params 背景音乐资源播放参数
|
||||
*/
|
||||
async load(url: string, callback?: Function, bundleName: string = resLoader.defaultBundleName) {
|
||||
async loadAndPlay(url: string, params?: IAudioParams) {
|
||||
if (!this.switch) return; // 禁止播放音乐
|
||||
|
||||
// 下一个加载的背景音乐资源
|
||||
if (this._isLoading) {
|
||||
this._nextBundleName = bundleName;
|
||||
this._nextUrl = url;
|
||||
this._nextParams = params!;
|
||||
return;
|
||||
}
|
||||
|
||||
let bundleName = resLoader.defaultBundleName;
|
||||
let loop = false;
|
||||
let volume = this.volume;
|
||||
let onPlayComplete: Function = null!;
|
||||
if (params) {
|
||||
this._params = params!
|
||||
if (params.bundle != null) bundleName = params.bundle;
|
||||
if (params.loop != null) loop = params.loop;
|
||||
if (params.volume != null) volume = params.volume;
|
||||
if (params.onPlayComplete != null) onPlayComplete = params.onPlayComplete;
|
||||
};
|
||||
|
||||
this._isLoading = true;
|
||||
var data: AudioClip = await resLoader.loadAsync(bundleName, url, AudioClip);
|
||||
if (data) {
|
||||
var clip: AudioClip = await resLoader.loadAsync(bundleName, url, AudioClip);
|
||||
if (clip) {
|
||||
this._isLoading = false;
|
||||
|
||||
// 处理等待加载的背景音乐
|
||||
if (this._nextUrl != null) {
|
||||
// 加载等待播放的背景音乐
|
||||
this.load(this._nextUrl, callback, this._nextBundleName);
|
||||
this._nextBundleName = this._nextUrl = null!;
|
||||
this.loadAndPlay(this._nextUrl, this._nextParams);
|
||||
this._nextUrl = null!;
|
||||
this._nextParams = null!;
|
||||
}
|
||||
else {
|
||||
callback && callback();
|
||||
|
||||
// 正在播放的时候先关闭
|
||||
if (this.playing) {
|
||||
this.stop();
|
||||
@@ -88,12 +109,21 @@ export class AudioMusic extends AudioSource {
|
||||
this.release();
|
||||
|
||||
// 播放背景音乐
|
||||
this.clip = data;
|
||||
this.clip = clip;
|
||||
this.loop = loop;
|
||||
this.volume = volume;
|
||||
this.currentTime = 0;
|
||||
this.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
if (this.switch && this.playing) {
|
||||
super.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/** 释放当前背景音乐资源 */
|
||||
release() {
|
||||
if (this.clip) {
|
||||
|
||||
10
assets/core/common/audio/IAudio.ts
Normal file
10
assets/core/common/audio/IAudio.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export interface IAudioParams {
|
||||
/** 资源包名 */
|
||||
bundle?: string,
|
||||
/** 是否循环播放 */
|
||||
loop?: boolean;
|
||||
/** 音效音量 */
|
||||
volume?: number;
|
||||
/** 播放完成事件 */
|
||||
onPlayComplete?: Function;
|
||||
}
|
||||
9
assets/core/common/audio/IAudio.ts.meta
Normal file
9
assets/core/common/audio/IAudio.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "82ec630f-ea0b-4e37-a671-1b4555a756db",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
import { Asset, Button, Component, EventHandler, EventKeyboard, EventTouch, Input, Node, Prefab, Sprite, SpriteFrame, __private, _decorator, input, isValid } from "cc";
|
||||
import { oops } from "../../core/Oops";
|
||||
import { IAudioParams } from "../../core/common/audio/IAudio";
|
||||
import { EventDispatcher } from "../../core/common/event/EventDispatcher";
|
||||
import { EventMessage, ListenerFunc } from "../../core/common/event/EventMessage";
|
||||
import { AssetType, CompleteCallback, Paths, ProgressCallback, resLoader } from "../../core/common/loader/ResLoader";
|
||||
@@ -339,41 +340,44 @@ export class GameComponent extends Component {
|
||||
/**
|
||||
* 播放背景音乐(不受自动释放资源管理)
|
||||
* @param url 资源地址
|
||||
* @param callback 资源加载完成回调
|
||||
* @param bundleName 资源包名
|
||||
* @param params 背景音乐资源播放参数
|
||||
*/
|
||||
playMusic(url: string, callback?: Function, bundleName?: string) {
|
||||
oops.audio.playMusic(url, callback, bundleName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 循环播放背景音乐(不受自动释放资源管理)
|
||||
* @param url 资源地址
|
||||
* @param bundleName 资源包名
|
||||
*/
|
||||
playMusicLoop(url: string, bundleName?: string) {
|
||||
oops.audio.stopMusic();
|
||||
oops.audio.playMusicLoop(url, bundleName);
|
||||
playMusic(url: string, params?: IAudioParams) {
|
||||
oops.audio.music.loadAndPlay(url, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放音效
|
||||
* @param url 资源地址
|
||||
* @param callback 资源加载完成回调
|
||||
* @param bundleName 资源包名
|
||||
* @param params 音效播放参数
|
||||
*/
|
||||
async playEffect(url: string, bundleName?: string) {
|
||||
if (bundleName == null) bundleName = oops.res.defaultBundleName;
|
||||
let resId = await oops.audio.playEffect(url, bundleName, () => {
|
||||
if (!this.isValid) return;
|
||||
|
||||
const rps = this.resPaths.get(ResType.Audio);
|
||||
if (rps) {
|
||||
const key = this.getResKey(bundleName, url);
|
||||
rps.delete(key);
|
||||
async playEffect(url: string, params?: IAudioParams): Promise<number> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let bundleName = resLoader.defaultBundleName;
|
||||
if (params == null) {
|
||||
params = { bundle: bundleName }
|
||||
}
|
||||
else if (params.bundle != null) {
|
||||
bundleName = params.bundle;
|
||||
}
|
||||
|
||||
// 音效播放完,关闭正在播放状态的音乐效果
|
||||
params.onPlayComplete = (aeid: number, url: string, bundleName: string) => {
|
||||
// 音效播放完前,界面被释放
|
||||
if (!this.isValid) return;
|
||||
|
||||
// 删除界面音效的播放记录
|
||||
const rps = this.resPaths.get(ResType.Audio);
|
||||
if (rps) {
|
||||
const key = this.getResKey(bundleName, url, aeid);
|
||||
rps.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
let resId = await oops.audio.playEffect(url, params);
|
||||
this.addPathToRecord(ResType.Audio, bundleName, url, resId); // 支持界面释放时,立即停止所有音效的播放
|
||||
resolve(resId);
|
||||
});
|
||||
this.addPathToRecord(ResType.Audio, bundleName, url, resId);
|
||||
}
|
||||
//#endregion
|
||||
|
||||
|
||||
Reference in New Issue
Block a user