资源加载,bgm和音效播放

This commit is contained in:
unanmed 2023-06-21 17:10:06 +08:00
parent 6f59ea51ac
commit 5aed6393a2
16 changed files with 289 additions and 52 deletions

View File

@ -16,11 +16,25 @@ export default defineConfig({
'resource.zip': [ 'resource.zip': [
'autotiles/*', 'autotiles/*',
'tilesets/*', 'tilesets/*',
'materials/*',
'images/*', 'images/*',
'animates/*', 'animates/*',
'sounds/*', 'sounds/*',
'fonts/*' 'fonts/*'
],
'weather.zip': [
'materials/fog.png',
'materials/cloud.png',
'materials/sun.png'
],
'materials.zip': [
'materials/animates.png',
'materials/enemy48.png',
'materials/enemys.png',
'materials/icons.png',
'materials/items.png',
'materials/npc48.png',
'materials/npcs.png',
'materials/terrains.png'
] ]
} }
}); });

View File

@ -636,6 +636,13 @@ return '{' + [
mainStyle_m mainStyle_m
: '主要样式设置:' '标题界面背景图:' EvalString BGNL? Newline
'竖屏标题界面背景图:' EvalString BGNL? Newline
'标题样式;可写 display: none 隐藏标题' EvalString BGNL? Newline
'标题按钮样式:' EvalString BGNL? Newline
'横屏状态栏背景url(...) 0 0/100% 100% no-repeat 可将图片拉伸自适配' BGNL? Newline EvalString BGNL? Newline
'竖屏状态栏背景:' EvalString BGNL? Newline
'竖屏工具栏背景:' EvalString BGNL? Newline
'楼层切换样式:' EvalString BGNL? Newline '楼层切换样式:' EvalString BGNL? Newline
'状态栏颜色' ColorString Colour '边框颜色' ColorString Colour BGNL? Newline '状态栏颜色' ColorString Colour '边框颜色' ColorString Colour BGNL? Newline
'选中框颜色' ColorString Colour '全局字体' EvalString BEND '选中框颜色' ColorString Colour '全局字体' EvalString BEND
@ -645,7 +652,14 @@ tooltip : 主要样式设置
default : ["project/images/bg.jpg", "project/images/bg.jpg", "color: white", "background-color: #32369F; opacity: 0.85; color: #FFFFFF; border: #FFFFFF 2px solid; caret-color: #FFD700;", "url(project/materials/ground.png) repeat", "url(project/materials/ground.png) repeat", "url(project/materials/ground.png) repeat", "background-color: black; color: white", "255,255,255,1", "rgba(255,255,255,1)", "204,204,204,1", "rgba(204,204,204,1)", "255,215,0,1", "rgba(255,215,0,1)", "Verdana"] default : ["project/images/bg.jpg", "project/images/bg.jpg", "color: white", "background-color: #32369F; opacity: 0.85; color: #FFFFFF; border: #FFFFFF 2px solid; caret-color: #FFD700;", "url(project/materials/ground.png) repeat", "url(project/materials/ground.png) repeat", "url(project/materials/ground.png) repeat", "background-color: black; color: white", "255,255,255,1", "rgba(255,255,255,1)", "204,204,204,1", "rgba(204,204,204,1)", "255,215,0,1", "rgba(255,215,0,1)", "Verdana"]
helpUrl : /_docs/#/instruction helpUrl : /_docs/#/instruction
var code = { var code = {
floorChangingStyle: EvalString_0, startBackground: EvalString_0,
startVerticalBackground: EvalString_1,
startLogoStyle: EvalString_2,
startButtonsStyle: EvalString_3,
statusLeftBackground: EvalString_4,
statusTopBackground: EvalString_5,
toolsBackground: EvalString_6,
floorChangingStyle: EvalString_7,
statusBarColor: JSON.parse('['+ColorString_0+']'), statusBarColor: JSON.parse('['+ColorString_0+']'),
borderColor: JSON.parse('['+ColorString_1+']'), borderColor: JSON.parse('['+ColorString_1+']'),
selectColor: JSON.parse('['+ColorString_2+']'), selectColor: JSON.parse('['+ColorString_2+']'),

View File

@ -277,7 +277,7 @@ span#hard {
box-sizing: border-box; box-sizing: border-box;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
background: url(project/materials/ground.png) repeat; background: black;
z-index: 185; z-index: 185;
display: none; display: none;
top: 0; top: 0;

View File

@ -56,6 +56,10 @@ const compress = type === 'dist';
await fs.remove('./dist/_server'); await fs.remove('./dist/_server');
await fs.remove('./dist/editor.html'); await fs.remove('./dist/editor.html');
await fs.remove('./dist/server.cjs'); await fs.remove('./dist/server.cjs');
await fs.remove('./dist/project/materials/airwall.png');
await fs.remove('./dist/project/materials/ground.png');
await fs.remove('./dist/project/materials/icons_old.png');
} catch {} } catch {}
// 2. 压缩字体 // 2. 压缩字体

View File

@ -254,7 +254,7 @@ async function writeFile(req: Request, res: Response) {
if (name.endsWith('project/events.js')) doDeclaration('events', value); if (name.endsWith('project/events.js')) doDeclaration('events', value);
if (name.endsWith('project/items.js')) doDeclaration('items', value); if (name.endsWith('project/items.js')) doDeclaration('items', value);
if (name.endsWith('project/maps.js')) doDeclaration('maps', value); if (name.endsWith('project/maps.js')) doDeclaration('maps', value);
if (name.endsWith('project/data.js')) doDeclaration('data', value); if (name.endsWith('project/data.js')) writeDevResource(value);
} catch (e) { } catch (e) {
console.log(e); console.log(e);
res.end( res.end(
@ -315,6 +315,44 @@ async function writeMultiFiles(req: Request, res: Response) {
res.end(); res.end();
} }
async function writeDevResource(data: string) {
try {
const buf = Buffer.from(data, 'base64');
data = buf.toString('utf-8');
const info = JSON.parse(data.split('\n').slice(1).join(''));
const res: string[] = [];
const icons = await fs.readFile('./public/project/icons.js', 'utf-8');
const iconData = JSON.parse(icons.split('\n').slice(1).join(''));
res.push(
...info.main.animates.map((v: any) => `animates.${v}.animate`),
...info.main.bgms.map((v: any) => `bgms.${v}`),
...info.main.fonts.map((v: any) => `fonts.${v}.ttf`),
...info.main.images.map((v: any) => `images.${v}`),
...info.main.sounds.map((v: any) => `sounds.${v}`),
...info.main.tilesets.map((v: any) => `tilesets.${v}`),
...Object.keys(iconData.autotile).map(v => `autotiles.${v}.png`),
...[
'animates',
'cloud',
'enemy48',
'enemys',
'fog',
'icons',
'items',
'keyboard',
'npc48',
'npcs',
'sun',
'terrains'
].map(v => `materials.${v}.png`)
);
const text = JSON.stringify(res, void 0, 4);
await fs.writeFile('./src/data/resource-dev.json', text, 'utf-8');
} catch (e) {
console.log(e);
}
}
/** /**
* *
* @param {string} type * @param {string} type

View File

@ -44,6 +44,7 @@ export class AudioPlayer extends EventEmitter<AudioPlayerEvent> {
async update(data: ArrayBuffer) { async update(data: ArrayBuffer) {
this.data = data; this.data = data;
this.buffer = await ac.decodeAudioData(data); this.buffer = await ac.decodeAudioData(data);
this.emit('update', this.buffer); this.emit('update', this.buffer);
} }
@ -61,9 +62,10 @@ export class AudioPlayer extends EventEmitter<AudioPlayerEvent> {
* *
*/ */
play(when?: number, offset?: number, duration?: number) { play(when?: number, offset?: number, duration?: number) {
if (!this.source) return;
this.ready(); this.ready();
this.source?.start(when, offset, duration); if (!this.source) return;
this.source.start(when, offset, duration);
const source = this.source; const source = this.source;
this.source?.addEventListener('ended', ev => { this.source?.addEventListener('ended', ev => {

View File

@ -1,7 +1,7 @@
import { has } from '../../plugin/utils'; import { has } from '../../plugin/utils';
import { ResourceController } from '../loader/controller'; import { ResourceController } from '../loader/controller';
class BgmController extends ResourceController<HTMLAudioElement> { export class BgmController extends ResourceController<HTMLAudioElement> {
playing?: BgmIds; playing?: BgmIds;
/** /**
@ -27,6 +27,7 @@ class BgmController extends ResourceController<HTMLAudioElement> {
const bgm = this.get(id); const bgm = this.get(id);
bgm.currentTime = when; bgm.currentTime = when;
bgm.play(); bgm.play();
this.playing = id;
} }
/** /**
@ -48,13 +49,6 @@ class BgmController extends ResourceController<HTMLAudioElement> {
} }
get(id: BgmIds) { get(id: BgmIds) {
return this.list[`bgm.${id}`]; return this.list[`bgms.${id}`];
} }
} }
declare global {
interface AncTe {
bgm: BgmController;
}
}
ancTe.bgm = new BgmController();

View File

@ -132,7 +132,10 @@ export class SoundEffect extends AudioPlayer {
} }
} }
class SoundController extends ResourceController<ArrayBuffer, SoundEffect> { export class SoundController extends ResourceController<
ArrayBuffer,
SoundEffect
> {
private seIndex: Record<number, SoundEffect> = {}; private seIndex: Record<number, SoundEffect> = {};
/** /**
@ -196,10 +199,3 @@ class SoundController extends ResourceController<ArrayBuffer, SoundEffect> {
return this.list[`sounds.${sound}`]; return this.list[`sounds.${sound}`];
} }
} }
declare global {
interface AncTe {
sound: SoundController;
}
}
ancTe.sound = new SoundController();

View File

@ -1,11 +1,32 @@
import { BgmController } from './audio/bgm';
import { SoundController } from './audio/sound';
import { readyAllResource } from './loader/load';
import { ResourceStore, ResourceType } from './loader/resource';
export {}; export {};
declare global { declare global {
interface AncTe {} interface AncTe {
sound: SoundController;
/** 游戏资源 */
resource: ResourceStore<Exclude<ResourceType, 'zip'>>;
zipResource: ResourceStore<'zip'>;
bgm: BgmController;
}
interface Window { interface Window {
readonly ancTe: AncTe; ancTe: AncTe;
} }
const ancTe: AncTe; const ancTe: AncTe;
} }
// @ts-ignore
window.ancTe = {}; function ready() {
window.ancTe = {
bgm: new BgmController(),
resource: new ResourceStore(),
zipResource: new ResourceStore(),
sound: new SoundController()
};
readyAllResource();
}
ready();

View File

@ -7,7 +7,7 @@ const info = resource;
* *
*/ */
export function readyAllResource() { export function readyAllResource() {
if (main.RESOURCE_TYPE === 'dev') return readyDevResource(); /* @__PURE__ */ if (main.RESOURCE_TYPE === 'dev') return readyDevResource();
info.resource.forEach(v => { info.resource.forEach(v => {
const type = getTypeByResource(v); const type = getTypeByResource(v);
if (type === 'zip') { if (type === 'zip') {
@ -21,4 +21,14 @@ export function readyAllResource() {
/** /**
* *
*/ */
function readyDevResource() {} /* @__PURE__ */ async function readyDevResource() {
const loadData = (await import('../../data/resource-dev.json')).default;
loadData.forEach(v => {
const type = getTypeByResource(v);
if (type !== 'zip') {
ancTe.resource.set(v, new Resource(v, type));
}
});
ancTe.resource.forEach(v => v.active());
}

View File

@ -37,12 +37,13 @@ export class Resource<
constructor(resource: string, format: T) { constructor(resource: string, format: T) {
super(resource); super(resource);
this.data = this.resolveUrl(resource); this.data = this.resolveUrl(resource);
this.format = format; this.format = format;
this.uri = resource; this.uri = resource;
this.once('active', this.load); this.once('active', () => this.load());
this.once('load', this.onLoad); this.once('load', v => this.onLoad(v));
this.once('loadstart', this.onLoadStart); this.once('loadstart', v => this.onLoadStart(v));
} }
protected onLoadStart(v?: ResourceData[T]) { protected onLoadStart(v?: ResourceData[T]) {
@ -242,7 +243,10 @@ export class ZippedResource extends EventEmitter<ZippedEvent> {
} }
} }
class ResourceStore<T extends ResourceType> extends Map<string, Resource<T>> { export class ResourceStore<T extends ResourceType> extends Map<
string,
Resource<T>
> {
active(key: string[] | string) { active(key: string[] | string) {
const keys = ensureArray(key); const keys = ensureArray(key);
keys.forEach(v => this.get(v)?.active()); keys.forEach(v => this.get(v)?.active());
@ -301,14 +305,3 @@ export function getZipFormatByType(type: ResourceType): 'arraybuffer' | 'text' {
if (type === 'text' || type === 'json') return 'text'; if (type === 'text' || type === 'json') return 'text';
else return 'arraybuffer'; else return 'arraybuffer';
} }
declare global {
interface AncTe {
/** 游戏资源 */
resource: ResourceStore<Exclude<ResourceType, 'zip'>>;
zipResource: ResourceStore<'zip'>;
}
}
ancTe.resource = new ResourceStore();
ancTe.zipResource = new ResourceStore();

145
src/data/resource-dev.json Normal file
View File

@ -0,0 +1,145 @@
[
"animates.amazed.animate",
"animates.angry.animate",
"animates.angry2.animate",
"animates.bulb.animate",
"animates.emm.animate",
"animates.explosion1.animate",
"animates.explosion2.animate",
"animates.explosion3.animate",
"animates.explosion4.animate",
"animates.fire.animate",
"animates.focus.animate",
"animates.fret.animate",
"animates.hand.animate",
"animates.ice.animate",
"animates.jianji.animate",
"animates.luv.animate",
"animates.magicAtk.animate",
"animates.stone.animate",
"animates.sweat.animate",
"animates.sweat2.animate",
"animates.sword.animate",
"animates.zone.animate",
"bgms.beforeBoss.mp3",
"bgms.cave.mp3",
"bgms.escape.mp3",
"bgms.grass.mp3",
"bgms.mount.mp3",
"bgms.plot1.mp3",
"bgms.road.mp3",
"bgms.title.mp3",
"bgms.tower.mp3",
"bgms.towerBoss.mp3",
"bgms.towerBoss2.mp3",
"bgms.towerBoss3.mp3",
"bgms.winter.mp3",
"bgms.winterTown.mp3",
"fonts.normal.ttf",
"images.IQ.png",
"images.arrow.png",
"images.atk.png",
"images.bg.jpg",
"images.boom.png",
"images.botton.png",
"images.cave2.jpg",
"images.def.png",
"images.exp.png",
"images.hero1.png",
"images.hero2.png",
"images.hp.png",
"images.money.png",
"images.skill.png",
"images.skill0.png",
"images.skill1.png",
"images.skill10.png",
"images.skill11.png",
"images.skill12.png",
"images.skill13.png",
"images.skill14.png",
"images.skill2.png",
"images.skill3.png",
"images.skill4.png",
"images.skill5.png",
"images.skill6.png",
"images.skill7.png",
"images.skill8.png",
"images.skill9.png",
"images.title.jpg",
"images.tower.jpg",
"images.tower7.jpeg",
"images.winskin.png",
"images.winskin2.png",
"images.winskin3.png",
"sounds.008-System08.ogg",
"sounds.015-Jump01.ogg",
"sounds.050-Explosion03.ogg",
"sounds.051-Explosion04.ogg",
"sounds.087-Action02.ogg",
"sounds.094-Attack06.ogg",
"sounds.118-Fire02.ogg",
"sounds.119-Fire03.ogg",
"sounds.120-Ice01.ogg",
"sounds.arrow.mp3",
"sounds.attack.mp3",
"sounds.bomb.mp3",
"sounds.cancel.mp3",
"sounds.centerFly.mp3",
"sounds.chapter.mp3",
"sounds.confirm.mp3",
"sounds.cursor.mp3",
"sounds.danger.mp3",
"sounds.door.mp3",
"sounds.drink.mp3",
"sounds.electron.mp3",
"sounds.equip.mp3",
"sounds.error.mp3",
"sounds.floor.mp3",
"sounds.item.mp3",
"sounds.jump.mp3",
"sounds.load.mp3",
"sounds.open_ui.mp3",
"sounds.paper.mp3",
"sounds.pickaxe.mp3",
"sounds.quake.mp3",
"sounds.recovery.mp3",
"sounds.save.mp3",
"sounds.shake.mp3",
"sounds.shop.mp3",
"sounds.thunder.mp3",
"sounds.tree.mp3",
"sounds.zone.mp3",
"tilesets.magictower.png",
"tilesets.043-Cave01.png",
"tilesets.004-Mountain01.png",
"tilesets.Map-Tower01.png",
"tilesets.Caverna1.png",
"tilesets.map-tower.png",
"tilesets.winter1.png",
"tilesets.snowTown.png",
"tilesets.room.png",
"autotiles.autotile.png",
"autotiles.autotile1.png",
"autotiles.autotile2.png",
"autotiles.autotile3.png",
"autotiles.autotile4.png",
"autotiles.autotile5.png",
"autotiles.autotile6.png",
"autotiles.autotile7.png",
"autotiles.autotile8.png",
"autotiles.autotile9.png",
"autotiles.autotile10.png",
"autotiles.autotile11.png",
"materials.animates.png",
"materials.cloud.png",
"materials.enemy48.png",
"materials.enemys.png",
"materials.fog.png",
"materials.icons.png",
"materials.items.png",
"materials.keyboard.png",
"materials.npc48.png",
"materials.npcs.png",
"materials.sun.png",
"materials.terrains.png"
]

View File

@ -1,6 +1,9 @@
{ {
"resource": [ "resource": [
"zip.resource.zip", "zip.resource.zip",
"zip.weather.zip",
"zip.materials.zip",
"materials.keyboard.png",
"bgms.tower.mp3", "bgms.tower.mp3",
"bgms.cave.mp3", "bgms.cave.mp3",
"bgms.mount.mp3", "bgms.mount.mp3",

View File

@ -4,6 +4,7 @@ import App2 from './App2.vue';
import './styles.less'; import './styles.less';
import 'ant-design-vue/dist/antd.dark.css'; import 'ant-design-vue/dist/antd.dark.css';
import './initPlugin'; import './initPlugin';
import './core/index';
createApp(App).mount('#root'); createApp(App).mount('#root');
createApp(App2).mount('#root2'); createApp(App2).mount('#root2');

View File

@ -2,7 +2,7 @@ import { message } from 'ant-design-vue';
import { MessageApi } from 'ant-design-vue/lib/message'; import { MessageApi } from 'ant-design-vue/lib/message';
import { isNil } from 'lodash-es'; import { isNil } from 'lodash-es';
import { Animation, sleep, TimingFn } from 'mutate-animate'; import { Animation, sleep, TimingFn } from 'mutate-animate';
import { ComputedRef, ref } from 'vue'; import { ref } from 'vue';
import { EVENT_KEY_CODE_MAP } from './keyCodes'; import { EVENT_KEY_CODE_MAP } from './keyCodes';
import axios from 'axios'; import axios from 'axios';
import { decompressFromBase64 } from 'lz-string'; import { decompressFromBase64 } from 'lz-string';
@ -211,14 +211,12 @@ export async function doByInterval(
interval: number, interval: number,
awaitFirst: boolean = false awaitFirst: boolean = false
) { ) {
if (awaitFirst) {
await sleep(interval);
}
for await (const fn of funcs) { for await (const fn of funcs) {
if (awaitFirst) {
await sleep(interval);
}
fn(); fn();
if (!awaitFirst) { await sleep(interval);
await sleep(interval);
}
} }
} }

View File

@ -22,7 +22,11 @@ interface Loader {
* @param imgName * @param imgName
* @param callback * @param callback
*/ */
loadImage(dir: string, imgName: string, callback?: () => void): void; loadImage(
dir: string,
imgName: string,
callback?: (name: string, img: HTMLImageElement) => void
): void;
/** /**
* zip中加载一系列图片 * zip中加载一系列图片