feat: proper sound pooling
This commit is contained in:
parent
0ee3da9e63
commit
54c1009d24
104
packages/sound/index.js
Normal file
104
packages/sound/index.js
Normal file
|
@ -0,0 +1,104 @@
|
|||
import {Howl, Howler} from 'howler';
|
||||
|
||||
import {Resource} from '@avocado/resource';
|
||||
|
||||
export class Sound extends Resource {
|
||||
|
||||
static load(uri) {
|
||||
if (!this.loadCache) {
|
||||
this.loadCache = {};
|
||||
}
|
||||
if (!this.refCache) {
|
||||
this.refCache = {};
|
||||
}
|
||||
if (!(uri in this.refCache)) {
|
||||
this.refCache[uri] = 0;
|
||||
}
|
||||
this.refCache[uri] += 1;
|
||||
if (this.loadCache[uri]) {
|
||||
return this.loadCache[uri];
|
||||
}
|
||||
return this.loadCache[uri] = this.read(uri).then((json) => {
|
||||
const instance = new this();
|
||||
instance.fromJSON(json);
|
||||
let lastTime = performance.now();
|
||||
instance.tickHandle = setInterval(() => {
|
||||
const now = performance.now();
|
||||
const elapsed = (now - lastTime) / 1000;
|
||||
lastTime = now;
|
||||
instance.tick(elapsed);
|
||||
}, 20);
|
||||
return new Promise((resolve) => {
|
||||
instance.sound.once('load', () => {
|
||||
resolve(instance);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.interval = 0;
|
||||
this.lastPlayHandle = undefined;
|
||||
this.locked = false;
|
||||
this.originalVolume = 1;
|
||||
this.remaining = 0;
|
||||
this.sound = undefined;
|
||||
this.tickHandle = undefined;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
clearInterval(instance.tickHandle);
|
||||
if (this.sound) {
|
||||
this.sound.unload();
|
||||
}
|
||||
}
|
||||
|
||||
fromJSON(json) {
|
||||
super.fromJSON(json);
|
||||
if (json.interval) {
|
||||
this.interval = json.interval;
|
||||
}
|
||||
if (json.volume) {
|
||||
this.originalVolume = json.volume;
|
||||
}
|
||||
this.sound = new Howl(json);
|
||||
return this;
|
||||
}
|
||||
|
||||
play() {
|
||||
if (this.locked) {
|
||||
const volume = this.sound.volume(this.lastPlayHandle);
|
||||
this.sound.volume(
|
||||
Math.min(1, Math.min(volume, this.originalVolume * 20)),
|
||||
this.lastPlayHandle
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.lastPlayHandle = this.sound.play();
|
||||
if (this.interval > 0) {
|
||||
this.locked = true;
|
||||
this.remaining = this.interval;
|
||||
}
|
||||
}
|
||||
|
||||
release() {
|
||||
const ctor = this.constructor;
|
||||
const uri = this.uri;
|
||||
ctor.refCache[uri] -= 1;
|
||||
if (0 === ctor.refCache[uri]) {
|
||||
delete ctor.loadCache[uri];
|
||||
this.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
tick(elapsed) {
|
||||
if (this.locked && this.interval > 0) {
|
||||
this.remaining -= elapsed;
|
||||
if (this.remaining <= 0) {
|
||||
this.locked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import {Howl, Howler} from 'howler';
|
||||
|
||||
import {Trait} from '@avocado/entity';
|
||||
|
||||
import {Sound} from '..';
|
||||
|
||||
export class Audible extends Trait {
|
||||
|
||||
static defaultParams() {
|
||||
|
@ -22,15 +22,26 @@ export class Audible extends Trait {
|
|||
destroy() {
|
||||
for (const key in this.sounds) {
|
||||
const sound = this.sounds[key];
|
||||
sound.unload();
|
||||
sound.release();
|
||||
}
|
||||
}
|
||||
|
||||
loadSounds() {
|
||||
for (const key in this._sounds) {
|
||||
const keys = Object.keys(this._sounds);
|
||||
const soundPromises = [];
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
const soundJSON = this._sounds[key];
|
||||
this.sounds[key] = new Howl(soundJSON);
|
||||
soundPromises.push(Sound.load(soundJSON.uri));
|
||||
}
|
||||
const soundsPromise = Promise.all(soundPromises);
|
||||
soundsPromise.then((sounds) => {
|
||||
for (let i = 0; i < sounds.length; i++) {
|
||||
const key = keys[i];
|
||||
const sound = sounds[i];
|
||||
this.sounds[key] = sound;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
methods() {
|
||||
|
|
Loading…
Reference in New Issue
Block a user