播放音效

This commit is contained in:
unanmed 2023-06-14 19:20:24 +08:00
parent 069ee0613b
commit bdaf37cb0c
7 changed files with 1335 additions and 937 deletions

View File

@ -27,22 +27,22 @@
"vue": "^3.3.4"
},
"devDependencies": {
"@babel/cli": "^7.21.5",
"@babel/core": "^7.21.8",
"@babel/preset-env": "^7.21.5",
"@babel/cli": "^7.22.5",
"@babel/core": "^7.22.5",
"@babel/preset-env": "^7.22.5",
"@rollup/plugin-babel": "^6.0.3",
"@rollup/plugin-commonjs": "^25.0.0",
"@rollup/plugin-node-resolve": "^15.0.2",
"@rollup/plugin-commonjs": "^25.0.1",
"@rollup/plugin-node-resolve": "^15.1.0",
"@rollup/plugin-replace": "^5.0.2",
"@rollup/plugin-terser": "^0.4.3",
"@rollup/plugin-typescript": "^11.1.1",
"@types/babel__core": "^7.20.0",
"@types/babel__core": "^7.20.1",
"@types/fontmin": "^0.9.0",
"@types/fs-extra": "^9.0.13",
"@types/lodash-es": "^4.17.7",
"@types/node": "^18.16.14",
"@types/ws": "^8.5.4",
"@vitejs/plugin-legacy": "^4.0.3",
"@types/node": "^18.16.18",
"@types/ws": "^8.5.5",
"@vitejs/plugin-legacy": "^4.0.4",
"@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.1",
"chokidar": "^3.5.3",
@ -51,12 +51,12 @@
"form-data": "^4.0.0",
"fs-extra": "^10.1.0",
"less": "^4.1.3",
"rollup": "^3.23.0",
"terser": "^5.17.6",
"rollup": "^3.25.1",
"terser": "^5.18.0",
"ts-node": "^10.9.1",
"typescript": "^4.9.5",
"typescript": "^5.1.3",
"unplugin-vue-components": "^0.22.12",
"vite": "^4.3.8",
"vite": "^4.3.9",
"vue-tsc": "^1.6.5",
"ws": "^8.13.0"
}

File diff suppressed because it is too large Load Diff

View File

@ -245,7 +245,7 @@ main.prototype.init = async function (mode, callback) {
const b = {};
new Proxy(a, b);
new Promise(res => res());
eval('`${123}`');
eval('`${0}`');
} catch {
alert('浏览器版本过低,无法游玩本塔!');
alert('建议使用Edge浏览器或Chrome浏览器游玩');

89
src/core/audio/audio.ts Normal file
View File

@ -0,0 +1,89 @@
import { EmitableEvent, EventEmitter } from '../common/eventEmitter';
const ac = new AudioContext();
interface BaseNode {
node: AudioNode;
channel?: number;
}
interface AudioPlayerEvent extends EmitableEvent {
play: (node: AudioBufferSourceNode) => void;
update: (audio: AudioBuffer) => void;
end: (node: AudioBufferSourceNode) => void;
}
export class AudioPlayer extends EventEmitter<AudioPlayerEvent> {
static ac: AudioContext = ac;
static index: number = 0;
/** 音频的索引,这样的话可以复用来提高性能表现 */
index: number = AudioPlayer.index++;
data: ArrayBuffer;
buffer: AudioBuffer | null = null;
source?: AudioBufferSourceNode;
baseNode: BaseNode[] = [];
constructor(data: ArrayBuffer) {
super();
this.data = data;
this.update(data);
}
/**
*
* @param data ArrayBuffer数据
*/
async update(data: ArrayBuffer) {
this.data = data;
this.buffer = await ac.decodeAudioData(data);
this.emit('update', this.buffer);
}
/**
*
*/
getSource() {
this.source ??= ac.createBufferSource();
this.source.buffer = this.buffer;
return this.source;
}
/**
*
*/
play(when?: number, offset?: number, duration?: number) {
if (!this.source) return;
this.ready();
this.source?.start(when, offset, duration);
const source = this.source;
this.source?.addEventListener('ended', ev => {
this.emit('end', source);
});
this.emit('play', source);
delete this.source;
return source;
}
/**
*
*/
ready() {
const source = this.getSource();
this.baseNode.forEach(v => {
source.connect(v.node, 0, v.channel);
});
}
/**
* destination
*/
getDestination() {
return ac.destination;
}
}

View File

@ -1,7 +1,137 @@
export class SoundEffect {}
import { has } from '../../plugin/utils';
import { AudioPlayer } from './audio';
export class SoundEffect extends AudioPlayer {
static playIndex = 0;
private playing: Record<string, AudioBufferSourceNode> = {};
private _stopingAll: boolean = false;
constructor(data: ArrayBuffer, stereo: boolean = false) {
super(data);
this.on('end', node => {
if (this._stopingAll) return;
const entry = Object.entries(this.playing);
const index = entry.find(v => node === v[1])?.[0];
if (!index) return;
delete this.playing[index];
});
this.initAudio(stereo);
}
/**
* 线
* @param stereo
*/
protected initAudio(stereo: boolean = false) {}
/**
*
* @returns id
*/
playSE() {
const node = this.play();
if (!node) return;
const index = SoundEffect.playIndex++;
this.playing[index] = node;
return index;
}
/**
*
*/
stopAll() {
this._stopingAll = true;
Object.values(this.playing).forEach(v => {
v.stop();
});
this.playing = {};
this._stopingAll = false;
}
/**
* id停止音频
* @param index id
*/
stopByIndex(index: number) {
this.playing[index]?.stop();
delete this.playing[index];
}
}
class SoundController {
add(uri: string, data: ArrayBuffer) {}
list: Record<string, SoundEffect> = {};
private seIndex: Record<number, SoundEffect> = {};
/**
*
* @param uri uri
* @param data ArrayBuffer信息AudioBuffer
*/
add(uri: string, data: ArrayBuffer) {
const se = new SoundEffect(data);
if (this.list[uri]) {
console.warn(`Repeated sound effect: ${uri}.`);
}
return (this.list[uri] = se);
}
/**
*
* @param uri uri
*/
remove(uri: string) {
delete this.list[uri];
}
/**
*
* @param sound
* @returns -1
*/
play(sound: SoundIds): number {
const se = this.get(sound);
const index = se.playSE();
if (!has(index)) return -1;
this.seIndex[index] = se;
return index;
}
/**
*
* @param id
*/
stop(id: number) {
const se = this.seIndex[id];
se.stopByIndex(id);
}
/**
*
* @param id
*/
stopById(id: SoundIds) {
const se = this.get(id);
se.stopAll();
}
/**
*
*/
stopAll() {
Object.values(this.list).forEach(v => v.stopAll());
}
/**
*
* @param sound
*/
get(sound: SoundIds) {
return this.list[`sounds.${sound}`];
}
}
declare global {

View File

@ -1,27 +1,15 @@
import resource from '../../data/resource.json';
import { NonZipResource, Resource, getTypeByResource } from './resource';
import { Resource, getTypeByResource } from './resource';
const info = resource as ResourceInfo[];
export interface ResourceInfo {
includes: string[];
zip: boolean;
zippedName?: string;
}
const info = resource;
export function readyAllResource() {
info.forEach(v => {
if (v.zip) {
const id = `zip.${v.zippedName}`;
ancTe.zipResource.push([[id, new Resource(id, 'zip')]]);
} else {
const res: [string, Resource<NonZipResource>][] = v.includes.map(
v => {
const type = getTypeByResource(v);
return [v, new Resource(v, type as NonZipResource)];
}
);
ancTe.resource.push(res);
if (type === 'zip') {
ancTe.zipResource.set(v, new Resource(v, 'zip'));
} else {
ancTe.resource.set(v, new Resource(v, type));
}
});
}

View File

@ -1,6 +1,3 @@
[
{
"includes": [],
"zip": false
}
""
]