mirror of
https://gitee.com/dgflash/oops-plugin-framework.git
synced 2026-05-17 03:35:49 +08:00
1. 重构音效管理模块,支持对象池管理多音效播放、关闭
2. GameComponent 支持释放时,自动关闭没播放完的音效 3. ButtonSimple、UIButton 支持释放时,自动关闭没播放完的音效
This commit is contained in:
@@ -24,7 +24,7 @@ import { GameManager } from "./game/GameManager";
|
||||
import { LayerManager } from "./gui/layer/LayerManager";
|
||||
|
||||
/** 框架版本号 */
|
||||
export var version: string = "1.2.2";
|
||||
export var version: string = "1.3.0";
|
||||
|
||||
/** 框架核心模块访问入口 */
|
||||
export class oops {
|
||||
|
||||
@@ -4,120 +4,21 @@
|
||||
* @LastEditors: dgflash
|
||||
* @LastEditTime: 2022-09-02 10:22:36
|
||||
*/
|
||||
import { AudioClip, AudioSource, _decorator, error } from 'cc';
|
||||
import { AudioClip, AudioSource, _decorator } from 'cc';
|
||||
import { oops } from '../../Oops';
|
||||
const { ccclass } = _decorator;
|
||||
|
||||
/**
|
||||
* 注:用playOneShot播放的音乐效果,在播放期间暂时没办法即时关闭音乐
|
||||
*/
|
||||
|
||||
/** 资源加载记录 */
|
||||
interface ResRecord {
|
||||
source: boolean;
|
||||
ac: AudioClip,
|
||||
bundle?: string,
|
||||
path?: string
|
||||
}
|
||||
|
||||
|
||||
/** 游戏音效 */
|
||||
@ccclass('AudioEffect')
|
||||
export class AudioEffect extends AudioSource {
|
||||
private effects: Map<string, ResRecord> = new Map<string, ResRecord>();
|
||||
/** 背景音乐播放完成回调 */
|
||||
onComplete: Function | null = null;
|
||||
|
||||
private _progress: number = 0;
|
||||
/** 获取音乐播放进度 */
|
||||
get progress(): number {
|
||||
if (this.duration > 0)
|
||||
this._progress = this.currentTime / this.duration;
|
||||
return this._progress;
|
||||
}
|
||||
/**
|
||||
* 设置音乐当前播放进度
|
||||
* @param value 进度百分比0到1之间
|
||||
*/
|
||||
set progress(value: number) {
|
||||
this._progress = value;
|
||||
this.currentTime = value * this.duration;
|
||||
start() {
|
||||
this.node.on(AudioSource.EventType.ENDED, this.onAudioEnded, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载音效并播放
|
||||
* @param url 音效资源地址
|
||||
* @param callback 资源加载完成并开始播放回调
|
||||
* @param bundleName 资源包名
|
||||
*/
|
||||
load(url: string | AudioClip, callback?: Function, bundleName?: string) {
|
||||
if (bundleName == null) bundleName = oops.res.defaultBundleName;
|
||||
|
||||
// 资源播放音乐对象
|
||||
if (url instanceof AudioClip) {
|
||||
this.effects.set(url.uuid, { source: true, ac: url });
|
||||
this.playOneShot(url, this.volume);
|
||||
callback && callback();
|
||||
}
|
||||
else {
|
||||
const key = `${bundleName}:${url}`;
|
||||
// 地址加载音乐资源后播放
|
||||
if (!this.effects.has(url)) {
|
||||
oops.res.load(bundleName, url, AudioClip, (err: Error | null, data: AudioClip) => {
|
||||
if (err) {
|
||||
error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
this.effects.set(key, { source: false, bundle: bundleName, path: url, ac: data });
|
||||
this.playOneShot(data, this.volume);
|
||||
callback && callback();
|
||||
});
|
||||
}
|
||||
// 播放缓存中音效
|
||||
else {
|
||||
const rr = this.effects.get(key)!;
|
||||
this.playOneShot(rr.ac, this.volume);
|
||||
callback && callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 释放所有已使用过的音效资源 */
|
||||
releaseAll() {
|
||||
for (let key in this.effects) {
|
||||
const rr = this.effects.get(key)!;
|
||||
if (rr.source) {
|
||||
this.release(rr.ac);
|
||||
}
|
||||
else {
|
||||
this.release(rr.path!, rr.bundle!);
|
||||
}
|
||||
}
|
||||
this.effects.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放指定地址音效资源
|
||||
* @param url 音效资源地址
|
||||
* @param bundleName 资源所在包名
|
||||
*/
|
||||
release(url: string | AudioClip, bundleName?: string) {
|
||||
if (bundleName == null) bundleName = oops.res.defaultBundleName;
|
||||
|
||||
let ac: AudioClip | undefined = undefined;
|
||||
if (url instanceof AudioClip) {
|
||||
ac = url;
|
||||
if (this.effects.has(ac.uuid)) {
|
||||
this.effects.delete(ac.uuid);
|
||||
ac.decRef();
|
||||
}
|
||||
}
|
||||
else {
|
||||
const key = `${bundleName}:${url}`;
|
||||
const rr = this.effects.get(key);
|
||||
if (rr) {
|
||||
this.effects.delete(key);
|
||||
rr.ac.decRef();
|
||||
}
|
||||
}
|
||||
private onAudioEnded() {
|
||||
this.onComplete && this.onComplete();
|
||||
}
|
||||
}
|
||||
148
assets/core/common/audio/AudioEffectPool.ts
Normal file
148
assets/core/common/audio/AudioEffectPool.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
import { AudioClip, Node, NodePool } from "cc";
|
||||
import { oops } from "../../Oops";
|
||||
import { resLoader } from "../loader/ResLoader";
|
||||
import { AudioEffect } from "./AudioEffect";
|
||||
|
||||
const AE_ID_MAX = 30000;
|
||||
|
||||
/** 音效池 */
|
||||
export class AudioEffectPool {
|
||||
/** 音效播放器对象池 */
|
||||
private pool: NodePool = new NodePool();
|
||||
/** 对象池集合 */
|
||||
private effects: Map<string, AudioEffect> = new Map();
|
||||
/** 用过的音效资源记录 */
|
||||
private res: Map<string, string> = new Map();
|
||||
/** 音效播放器唯一编号 */
|
||||
private _aeId: number = 0;
|
||||
|
||||
/** 获取请求唯一编号 */
|
||||
private getAeId() {
|
||||
if (this._aeId == AE_ID_MAX) this._aeId = 1;
|
||||
this._aeId++;
|
||||
return this._aeId;
|
||||
}
|
||||
|
||||
async loadAndPlay(url: string | AudioClip, bundleName: string = resLoader.defaultBundleName, onPlayComplete?: Function): Promise<number> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let aeid = this.getAeId();
|
||||
let key: string;
|
||||
if (url instanceof AudioClip) {
|
||||
key = url.uuid;
|
||||
}
|
||||
else {
|
||||
key = `${bundleName}_${url}`;
|
||||
}
|
||||
key += "_" + aeid;
|
||||
|
||||
// 创建音效资源
|
||||
let clip: AudioClip;
|
||||
if (url instanceof AudioClip) {
|
||||
clip = url;
|
||||
}
|
||||
else {
|
||||
clip = resLoader.get(url, AudioClip, bundleName)!;
|
||||
if (!clip) {
|
||||
this.res.set(bundleName, url);
|
||||
clip = await resLoader.loadAsync(bundleName, url, AudioClip);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取音效果播放器播放音乐
|
||||
let ae: AudioEffect;
|
||||
let node: Node = null!;
|
||||
if (this.pool.size() == 0) {
|
||||
node = new Node();
|
||||
node.name = "AudioEffect";
|
||||
node.parent = oops.audio.node;
|
||||
ae = node.addComponent(AudioEffect)!;
|
||||
}
|
||||
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.clip = clip;
|
||||
ae.play();
|
||||
|
||||
resolve(aeid);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 回收音效播放器
|
||||
* @param aeid 播放器编号
|
||||
* @param url 音效路径
|
||||
* @param bundleName 资源包名
|
||||
*/
|
||||
put(aeid: number, url: string | AudioClip, bundleName: string = resLoader.defaultBundleName) {
|
||||
let key: string;
|
||||
if (url instanceof AudioClip) {
|
||||
key = url.uuid;
|
||||
}
|
||||
else {
|
||||
key = `${bundleName}_${url}`;
|
||||
}
|
||||
key += "_" + aeid;
|
||||
|
||||
let ae = this.effects.get(key);
|
||||
if (ae && ae.clip) {
|
||||
this.effects.delete(key);
|
||||
ae.stop();
|
||||
this.pool.put(ae.node);
|
||||
}
|
||||
}
|
||||
|
||||
/** 释放所有音效资源与对象池中播放器 */
|
||||
release() {
|
||||
// 释放正在播放的音效
|
||||
this.effects.forEach(ae => {
|
||||
ae.node.destroy();
|
||||
});
|
||||
this.effects.clear();
|
||||
|
||||
// 释放音效资源
|
||||
this.res.forEach((url: string, bundleName: string) => {
|
||||
resLoader.release(bundleName, url);
|
||||
});
|
||||
|
||||
// 释放池中播放器
|
||||
this.pool.clear();
|
||||
}
|
||||
|
||||
/** 设置音量 */
|
||||
setVolume(volume: number) {
|
||||
this.effects.forEach(ae => {
|
||||
ae.volume = volume;
|
||||
});
|
||||
}
|
||||
|
||||
/** 停止播放所有音效 */
|
||||
stop() {
|
||||
this.effects.forEach(ae => {
|
||||
ae.stop();
|
||||
});
|
||||
}
|
||||
|
||||
/** 恢复所有音效 */
|
||||
play() {
|
||||
this.effects.forEach(ae => {
|
||||
ae.play();
|
||||
});
|
||||
}
|
||||
|
||||
/** 暂停所有音效 */
|
||||
pause() {
|
||||
this.effects.forEach(ae => {
|
||||
ae.pause();
|
||||
});
|
||||
}
|
||||
}
|
||||
9
assets/core/common/audio/AudioEffectPool.ts.meta
Normal file
9
assets/core/common/audio/AudioEffectPool.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "01278043-8ebb-42af-8081-a663b90d994d",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import {AudioClip, Component} from "cc";
|
||||
import {oops} from "../../Oops";
|
||||
import {AudioEffect} from "./AudioEffect";
|
||||
import {AudioMusic} from "./AudioMusic";
|
||||
import { AudioClip, Component } from "cc";
|
||||
import { oops } from "../../Oops";
|
||||
import { AudioEffectPool } from "./AudioEffectPool";
|
||||
import { AudioMusic } from "./AudioMusic";
|
||||
|
||||
const LOCAL_STORE_KEY = "game_audio";
|
||||
|
||||
@@ -15,7 +15,7 @@ export class AudioManager extends Component {
|
||||
/** 背景音乐管理对象 */
|
||||
music: AudioMusic = null!;
|
||||
/** 音效管理对象 */
|
||||
effect: AudioEffect = null!;
|
||||
effect: AudioEffectPool = new AudioEffectPool();
|
||||
|
||||
/** 音乐管理状态数据 */
|
||||
private local_data: any = {};
|
||||
@@ -109,8 +109,7 @@ export class AudioManager extends Component {
|
||||
set switchMusic(value: boolean) {
|
||||
this._switch_music = value;
|
||||
|
||||
if (!value)
|
||||
this.music.stop();
|
||||
if (!value) this.music.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,15 +118,16 @@ export class AudioManager extends Component {
|
||||
* @param callback 加载完成回调
|
||||
* @param bundleName 资源包名
|
||||
*/
|
||||
playEffect(url: string | AudioClip, callback?: Function, bundleName?: string) {
|
||||
playEffect(url: string | AudioClip, bundleName?: string, onPlayComplete?: Function): Promise<number> {
|
||||
if (this._switch_effect) {
|
||||
this.effect.load(url, callback, bundleName);
|
||||
return this.effect.loadAndPlay(url, bundleName, onPlayComplete);
|
||||
}
|
||||
return Promise.resolve(-1);
|
||||
}
|
||||
|
||||
/** 释放音效资源 */
|
||||
releaseEffect(url: string | AudioClip, bundleName?: string) {
|
||||
this.effect.release(url, bundleName);
|
||||
putEffect(aeid: number, url: string | AudioClip, bundleName?: string) {
|
||||
this.effect.put(aeid, url, bundleName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,7 +143,7 @@ export class AudioManager extends Component {
|
||||
*/
|
||||
set volumeEffect(value: number) {
|
||||
this._volume_effect = value;
|
||||
this.effect.volume = value;
|
||||
this.effect.setVolume(value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,26 +164,20 @@ export class AudioManager extends Component {
|
||||
|
||||
/** 恢复当前暂停的音乐与音效播放 */
|
||||
resumeAll() {
|
||||
if (this.music) {
|
||||
if (!this.music.playing && this.music.progress > 0) this.music.play();
|
||||
if (!this.effect.playing && this.effect.progress > 0) this.effect.play();
|
||||
}
|
||||
if (!this.music.playing && this.music.progress > 0) this.music.play();
|
||||
this.effect.play();
|
||||
}
|
||||
|
||||
/** 暂停当前音乐与音效的播放 */
|
||||
pauseAll() {
|
||||
if (this.music) {
|
||||
if (this.music.playing) this.music.pause();
|
||||
if (this.effect.playing) this.effect.pause();
|
||||
}
|
||||
if (this.music.playing) this.music.pause();
|
||||
this.effect.pause();
|
||||
}
|
||||
|
||||
/** 停止当前音乐与音效的播放 */
|
||||
stopAll() {
|
||||
if (this.music) {
|
||||
this.music.stop();
|
||||
this.effect.stop();
|
||||
}
|
||||
this.music.stop();
|
||||
this.effect.stop();
|
||||
}
|
||||
|
||||
/** 保存音乐音效的音量、开关配置数据到本地 */
|
||||
@@ -196,25 +190,25 @@ export class AudioManager extends Component {
|
||||
oops.storage.set(LOCAL_STORE_KEY, this.local_data);
|
||||
}
|
||||
|
||||
|
||||
/** 本地加载音乐音效的音量、开关配置数据并设置到游戏中 */
|
||||
load() {
|
||||
this.music = this.getComponent(AudioMusic) || this.addComponent(AudioMusic)!;
|
||||
this.effect = this.getComponent(AudioEffect) || this.addComponent(AudioEffect)!;
|
||||
|
||||
this.local_data = oops.storage.getJson(LOCAL_STORE_KEY);
|
||||
if (this.local_data) {
|
||||
try {
|
||||
this.setState();
|
||||
} catch (e) {
|
||||
}
|
||||
catch {
|
||||
this.setStateDefault();
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
this.setStateDefault();
|
||||
}
|
||||
|
||||
if (this.music) this.music.volume = this._volume_music;
|
||||
if (this.effect) this.effect.volume = this._volume_effect;
|
||||
this.effect.setVolume(this._volume_effect);
|
||||
}
|
||||
|
||||
private setState() {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @LastEditTime: 2023-05-16 09:11:30
|
||||
*/
|
||||
import { AudioClip, AudioSource, _decorator } from 'cc';
|
||||
import { oops } from '../../Oops';
|
||||
import { resLoader } from '../loader/ResLoader';
|
||||
|
||||
const { ccclass, menu } = _decorator;
|
||||
|
||||
@@ -20,10 +20,19 @@ export class AudioMusic extends AudioSource {
|
||||
|
||||
private _progress: number = 0;
|
||||
private _isLoading: boolean = false;
|
||||
private _bundleName: string = null!; // 当前音乐资源包
|
||||
private _url: string = null!; // 当前播放音乐
|
||||
private _bundleName_next: string = null!; // 下一个音乐资源包
|
||||
private _url_next: string = null!; // 下一个播放音乐
|
||||
private _nextBundleName: string = null!; // 下一个音乐资源包
|
||||
private _nextUrl: string = null!; // 下一个播放音乐
|
||||
|
||||
start() {
|
||||
// this.node.on(AudioSource.EventType.STARTED, this.onAudioStarted, this);
|
||||
this.node.on(AudioSource.EventType.ENDED, this.onAudioEnded, this);
|
||||
}
|
||||
|
||||
// private onAudioStarted() { }
|
||||
|
||||
private onAudioEnded() {
|
||||
this.onComplete && this.onComplete();
|
||||
}
|
||||
|
||||
/** 获取音乐播放进度 */
|
||||
get progress(): number {
|
||||
@@ -46,75 +55,49 @@ export class AudioMusic extends AudioSource {
|
||||
* @param callback 加载完成回调
|
||||
* @param bundleName 资源包名
|
||||
*/
|
||||
async load(url: string, callback?: Function, bundleName?: string) {
|
||||
if (bundleName == null) bundleName = oops.res.defaultBundleName;
|
||||
|
||||
async load(url: string, callback?: Function, bundleName: string = resLoader.defaultBundleName) {
|
||||
// 下一个加载的背景音乐资源
|
||||
if (this._isLoading) {
|
||||
this._bundleName_next = bundleName;
|
||||
this._url_next = url;
|
||||
this._nextBundleName = bundleName;
|
||||
this._nextUrl = url;
|
||||
return;
|
||||
}
|
||||
|
||||
this._isLoading = true;
|
||||
var data: AudioClip = await oops.res.loadAsync(bundleName, url, AudioClip);
|
||||
var data: AudioClip = await resLoader.loadAsync(bundleName, url, AudioClip);
|
||||
if (data) {
|
||||
this._isLoading = false;
|
||||
|
||||
// 处理等待加载的背景音乐
|
||||
if (this._url_next != null) {
|
||||
// 删除之前加载的音乐资源
|
||||
this.release();
|
||||
|
||||
if (this._nextUrl != null) {
|
||||
// 加载等待播放的背景音乐
|
||||
this.load(this._url_next, callback, this._bundleName_next);
|
||||
this._bundleName_next = this._url_next = null!;
|
||||
this.load(this._nextUrl, callback, this._nextBundleName);
|
||||
this._nextBundleName = this._nextUrl = null!;
|
||||
}
|
||||
else {
|
||||
callback && callback();
|
||||
this.playPrepare(bundleName, url, data);
|
||||
|
||||
// 正在播放的时候先关闭
|
||||
if (this.playing) {
|
||||
this.stop();
|
||||
}
|
||||
|
||||
// 删除当前正在播放的音乐
|
||||
this.release();
|
||||
|
||||
// 播放背景音乐
|
||||
this.clip = data;
|
||||
this.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private playPrepare(bundleName: string, url: string, data: AudioClip) {
|
||||
// 正在播放的时候先关闭
|
||||
if (this.playing) {
|
||||
this.stop();
|
||||
}
|
||||
|
||||
// 删除当前正在播放的音乐
|
||||
this.release();
|
||||
|
||||
// 播放背景音乐
|
||||
this.enabled = true;
|
||||
this.clip = data;
|
||||
this.play();
|
||||
|
||||
// 记录新的资源包与资源名数据
|
||||
this._bundleName = bundleName;
|
||||
this._url = url;
|
||||
}
|
||||
|
||||
/** cc.Component 生命周期方法,验证背景音乐播放完成逻辑,建议不要主动调用 */
|
||||
update(dt: number) {
|
||||
// 背景资源播放完成事件
|
||||
if (this.playing == false && this.progress == 0) {
|
||||
this.enabled = false;
|
||||
this.clip = null;
|
||||
this._bundleName = this._url = null!;
|
||||
this.onComplete && this.onComplete();
|
||||
}
|
||||
}
|
||||
|
||||
/** 释放当前背景音乐资源 */
|
||||
release() {
|
||||
if (this._url) {
|
||||
if (this.clip) {
|
||||
this.stop();
|
||||
this.clip.decRef();
|
||||
this.clip = null;
|
||||
oops.res.release(this._url, this._bundleName);
|
||||
}
|
||||
|
||||
this._bundleName = this._url = null!;
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
*/
|
||||
import { Animation, AnimationClip, EventTouch, instantiate, Node, Prefab, Size, UITransform, v3, Vec3 } from "cc";
|
||||
import { resLoader } from "../common/loader/ResLoader";
|
||||
import { oops } from "../Oops";
|
||||
|
||||
/** 显示对象工具 */
|
||||
export class ViewUtil {
|
||||
@@ -90,7 +89,7 @@ export class ViewUtil {
|
||||
* @param path 资源路径
|
||||
* @param bundleName 资源包名
|
||||
*/
|
||||
static createPrefabNode(path: string, bundleName: string = oops.res.defaultBundleName): Node {
|
||||
static createPrefabNode(path: string, bundleName: string = resLoader.defaultBundleName): Node {
|
||||
const p = resLoader.get(path, Prefab, bundleName);
|
||||
if (p) {
|
||||
return instantiate(p);
|
||||
@@ -103,7 +102,7 @@ export class ViewUtil {
|
||||
* @param path 资源路径
|
||||
* @param bundleName 资源包名
|
||||
*/
|
||||
static createPrefabNodeAsync(path: string, bundleName: string = oops.res.defaultBundleName): Promise<Node> {
|
||||
static createPrefabNodeAsync(path: string, bundleName: string = resLoader.defaultBundleName): Promise<Node> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const p = await resLoader.loadAsync(bundleName, path, Prefab);
|
||||
if (p) {
|
||||
|
||||
@@ -59,7 +59,6 @@ export default class ButtonEffect extends ButtonSimple {
|
||||
super.onTouchEnd(event);
|
||||
}
|
||||
|
||||
|
||||
onDestroy() {
|
||||
this.node.off(Node.EventType.TOUCH_START, this.onTouchtStart, this);
|
||||
super.onDestroy();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { AudioClip, Component, EventTouch, Node, _decorator, game } from "cc";
|
||||
import { oops } from "../../../core/Oops";
|
||||
import { resLoader } from "../../../core/common/loader/ResLoader";
|
||||
|
||||
const { ccclass, property, menu } = _decorator;
|
||||
|
||||
@@ -22,7 +23,7 @@ export default class ButtonSimple extends Component {
|
||||
type: AudioClip
|
||||
})
|
||||
private effect: AudioClip = null!;
|
||||
|
||||
private effectIds: number[] = [];
|
||||
private touchCount = 0;
|
||||
private touchtEndTime = 0;
|
||||
|
||||
@@ -54,14 +55,24 @@ export default class ButtonSimple extends Component {
|
||||
}
|
||||
|
||||
/** 短按触摸音效 */
|
||||
protected playEffect() {
|
||||
if (this.effect) oops.audio.playEffect(this.effect);
|
||||
protected async playEffect() {
|
||||
if (this.effect) {
|
||||
const effectId = await oops.audio.playEffect(this.effect, resLoader.defaultBundleName, () => {
|
||||
this.effectIds.remove(effectId);
|
||||
});
|
||||
if (effectId > 0) this.effectIds.push(effectId);
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
this.node.off(Node.EventType.TOUCH_END, this.onTouchEnd, this);
|
||||
this.node.off(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
|
||||
|
||||
if (this.effect) oops.audio.releaseEffect(this.effect);
|
||||
if (this.effect) {
|
||||
this.effectIds.forEach(effectId => {
|
||||
console.log(effectId);
|
||||
oops.audio.putEffect(effectId, this.effect);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { AudioClip, Button, EventTouch, _decorator, game } from "cc";
|
||||
import { oops } from "../../../core/Oops";
|
||||
import { resLoader } from "../../../core/common/loader/ResLoader";
|
||||
|
||||
const { ccclass, property, menu } = _decorator;
|
||||
|
||||
@@ -26,6 +27,7 @@ export default class UIButton extends Button {
|
||||
type: AudioClip
|
||||
})
|
||||
private effect: AudioClip = null!;
|
||||
private effectIds: number[] = [];
|
||||
|
||||
/** 触摸次数 */
|
||||
private _touchCount = 0;
|
||||
@@ -50,13 +52,28 @@ export default class UIButton extends Button {
|
||||
else {
|
||||
this._touchEndTime = game.totalTime;
|
||||
super._onTouchEnded(event);
|
||||
}
|
||||
|
||||
// 短按触摸音效
|
||||
if (this.effect) oops.audio.playEffect(this.effect);
|
||||
// 短按触摸音效
|
||||
this.playEffect();
|
||||
}
|
||||
}
|
||||
|
||||
/** 短按触摸音效 */
|
||||
protected async playEffect() {
|
||||
if (this.effect) {
|
||||
const effectId = await oops.audio.playEffect(this.effect, resLoader.defaultBundleName, () => {
|
||||
this.effectIds.remove(effectId);
|
||||
});
|
||||
if (effectId > 0) this.effectIds.push(effectId);
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
if (this.effect) oops.audio.releaseEffect(this.effect);
|
||||
if (this.effect) {
|
||||
this.effectIds.forEach(effectId => {
|
||||
console.log(effectId);
|
||||
oops.audio.putEffect(effectId, this.effect);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,12 @@ enum ResType {
|
||||
|
||||
/** 资源加载记录 */
|
||||
interface ResRecord {
|
||||
/** 资源包名 */
|
||||
bundle: string,
|
||||
path: string
|
||||
/** 资源路径 */
|
||||
path: string,
|
||||
/** 资源编号 */
|
||||
resId?: number
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,7 +130,7 @@ export class GameComponent extends Component {
|
||||
* @param bundleName 资源包名
|
||||
* @param paths 资源路径
|
||||
*/
|
||||
private addPathToRecord<T>(type: ResType, bundleName: string, paths?: string | string[] | AssetType<T> | ProgressCallback | CompleteCallback | null) {
|
||||
private addPathToRecord<T>(type: ResType, bundleName: string, paths?: string | string[] | AssetType<T> | ProgressCallback | CompleteCallback | null, resId?: number) {
|
||||
if (this.resPaths == null) this.resPaths = new Map();
|
||||
|
||||
var rps = this.resPaths.get(type);
|
||||
@@ -139,30 +143,36 @@ export class GameComponent extends Component {
|
||||
let realBundle = bundleName;
|
||||
for (let index = 0; index < paths.length; index++) {
|
||||
let realPath = paths[index];
|
||||
let key = `${realBundle}:${realPath}`;
|
||||
let key = this.getResKey(realBundle, realPath, resId);
|
||||
if (!rps.has(key)) {
|
||||
rps.set(key, { path: realPath, bundle: realBundle })
|
||||
rps.set(key, { path: realPath, bundle: realBundle, resId: resId });
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (typeof paths === "string") {
|
||||
let realBundle = bundleName;
|
||||
let realPath = paths;
|
||||
let key = `${realBundle}:${realPath}`;
|
||||
let key = this.getResKey(realBundle, realPath, resId);
|
||||
if (!rps.has(key)) {
|
||||
rps.set(key, { path: realPath, bundle: realBundle })
|
||||
rps.set(key, { path: realPath, bundle: realBundle, resId: resId });
|
||||
}
|
||||
}
|
||||
else {
|
||||
let realBundle = oops.res.defaultBundleName;
|
||||
let realPath = bundleName;
|
||||
let key = `${realBundle}:${realPath}`;
|
||||
let key = this.getResKey(realBundle, realPath, resId);
|
||||
if (!rps.has(key)) {
|
||||
rps.set(key, { path: realPath, bundle: realBundle })
|
||||
rps.set(key, { path: realPath, bundle: realBundle, resId: resId });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getResKey(realBundle: string, realPath: string, resId?: number) {
|
||||
let key = `${realBundle}:${realPath}`;
|
||||
if (resId != null) key += ":" + resId;
|
||||
return key;
|
||||
}
|
||||
|
||||
/** 异步加载资源 */
|
||||
loadAsync<T extends Asset>(bundleName: string, paths: string | string[], type: AssetType<T> | null): Promise<T>;
|
||||
loadAsync<T extends Asset>(bundleName: string, paths: string | string[]): Promise<T>;
|
||||
@@ -259,7 +269,7 @@ export class GameComponent extends Component {
|
||||
const rps = this.resPaths.get(ResType.Audio);
|
||||
if (rps) {
|
||||
rps.forEach((value: ResRecord) => {
|
||||
oops.audio.releaseEffect(value.path, value.bundle);
|
||||
oops.audio.putEffect(value.resId!, value.path, value.bundle);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -293,10 +303,16 @@ export class GameComponent extends Component {
|
||||
* @param callback 资源加载完成回调
|
||||
* @param bundleName 资源包名
|
||||
*/
|
||||
playEffect(url: string, callback?: Function, bundleName?: string) {
|
||||
async playEffect(url: string, bundleName?: string) {
|
||||
if (bundleName == null) bundleName = oops.res.defaultBundleName;
|
||||
this.addPathToRecord(ResType.Audio, bundleName, url);
|
||||
oops.audio.playEffect(url, callback, bundleName);
|
||||
const id = await oops.audio.playEffect(url, bundleName, () => {
|
||||
const rps = this.resPaths.get(ResType.Audio);
|
||||
if (rps) {
|
||||
const key = this.getResKey(bundleName, url, id);
|
||||
rps.delete(key);
|
||||
}
|
||||
});
|
||||
this.addPathToRecord(ResType.Audio, bundleName, url, id);
|
||||
}
|
||||
//#endregion
|
||||
|
||||
|
||||
Reference in New Issue
Block a user