mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-01-31 23:29:27 +08:00
feat: 动画
This commit is contained in:
parent
63765ab626
commit
d0ff2f1dc5
@ -1,5 +1,6 @@
|
|||||||
type AdapterFunction<T> = (item: T, ...params: any[]) => Promise<any>;
|
type AdapterFunction<T> = (item: T, ...params: any[]) => Promise<any>;
|
||||||
type SyncAdapterFunction<T> = (item: T, ...params: any[]) => any;
|
type SyncAdapterFunction<T> = (item: T, ...params: any[]) => any;
|
||||||
|
type GlobalAdapterFunction = (...params: any[]) => Promise<any>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 渲染适配器,用作渲染层与数据层沟通的桥梁,用于在数据层等待渲染层执行,常用与动画等。
|
* 渲染适配器,用作渲染层与数据层沟通的桥梁,用于在数据层等待渲染层执行,常用与动画等。
|
||||||
@ -16,6 +17,7 @@ export class RenderAdapter<T> {
|
|||||||
|
|
||||||
private execute: Map<string, AdapterFunction<T>> = new Map();
|
private execute: Map<string, AdapterFunction<T>> = new Map();
|
||||||
private syncExecutes: Map<string, SyncAdapterFunction<T>> = new Map();
|
private syncExecutes: Map<string, SyncAdapterFunction<T>> = new Map();
|
||||||
|
private globalExecutes: Map<string, GlobalAdapterFunction> = new Map();
|
||||||
|
|
||||||
constructor(id: string) {
|
constructor(id: string) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
@ -36,11 +38,20 @@ export class RenderAdapter<T> {
|
|||||||
this.items.delete(item);
|
this.items.delete(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定义一个类似于静态函数的函数,只会调用一次,不会对每个元素执行
|
||||||
|
* @param id 函数名称
|
||||||
|
* @param fn 执行的函数
|
||||||
|
*/
|
||||||
|
receiveGlobal(id: string, fn: GlobalAdapterFunction) {
|
||||||
|
this.globalExecutes.set(id, fn);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置执行函数
|
* 设置执行函数
|
||||||
* @param fn 对于每个元素执行的函数
|
* @param fn 对于每个元素执行的函数
|
||||||
*/
|
*/
|
||||||
recieve(id: string, fn: AdapterFunction<T>): void {
|
receive(id: string, fn: AdapterFunction<T>): void {
|
||||||
this.execute.set(id, fn);
|
this.execute.set(id, fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +59,7 @@ export class RenderAdapter<T> {
|
|||||||
* 设置同步执行函数
|
* 设置同步执行函数
|
||||||
* @param fn 对于每个元素执行的函数
|
* @param fn 对于每个元素执行的函数
|
||||||
*/
|
*/
|
||||||
recieveSync(id: string, fn: SyncAdapterFunction<T>): void {
|
receiveSync(id: string, fn: SyncAdapterFunction<T>): void {
|
||||||
this.syncExecutes.set(id, fn);
|
this.syncExecutes.set(id, fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,6 +107,18 @@ export class RenderAdapter<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用一个全局函数
|
||||||
|
*/
|
||||||
|
global<R = any>(id: string, ...params: any[]): Promise<R> {
|
||||||
|
const execute = this.globalExecutes.get(id);
|
||||||
|
if (!execute) {
|
||||||
|
return Promise.reject();
|
||||||
|
} else {
|
||||||
|
return execute(...params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 销毁这个adapter
|
* 销毁这个adapter
|
||||||
*/
|
*/
|
||||||
|
@ -6,6 +6,7 @@ import { LayerGroup, FloorLayer } from './preset/layer';
|
|||||||
import { MotaRenderer } from './render';
|
import { MotaRenderer } from './render';
|
||||||
import { LayerShadowExtends } from '../fx/shadow';
|
import { LayerShadowExtends } from '../fx/shadow';
|
||||||
import { LayerGroupFilter } from '@/plugin/fx/gameCanvas';
|
import { LayerGroupFilter } from '@/plugin/fx/gameCanvas';
|
||||||
|
import { LayerGroupAnimate } from './preset/animate';
|
||||||
|
|
||||||
let main: MotaRenderer;
|
let main: MotaRenderer;
|
||||||
|
|
||||||
@ -31,12 +32,14 @@ Mota.require('var', 'loading').once('loaded', () => {
|
|||||||
const door = new LayerDoorAnimate();
|
const door = new LayerDoorAnimate();
|
||||||
const shadow = new LayerShadowExtends();
|
const shadow = new LayerShadowExtends();
|
||||||
const filter = new LayerGroupFilter();
|
const filter = new LayerGroupFilter();
|
||||||
|
const animate = new LayerGroupAnimate();
|
||||||
layer.extends(damage);
|
layer.extends(damage);
|
||||||
layer.extends(detail);
|
layer.extends(detail);
|
||||||
layer.extends(filter);
|
layer.extends(filter);
|
||||||
layer.getLayer('event')?.extends(hero);
|
layer.getLayer('event')?.extends(hero);
|
||||||
layer.getLayer('event')?.extends(door);
|
layer.getLayer('event')?.extends(door);
|
||||||
layer.getLayer('event')?.extends(shadow);
|
layer.getLayer('event')?.extends(shadow);
|
||||||
|
layer.extends(animate);
|
||||||
|
|
||||||
render.appendChild(layer);
|
render.appendChild(layer);
|
||||||
});
|
});
|
||||||
|
262
src/core/render/preset/animate.ts
Normal file
262
src/core/render/preset/animate.ts
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
import { logger } from '@/core/common/logger';
|
||||||
|
import { RenderAdapter } from '../adapter';
|
||||||
|
import { Sprite } from '../sprite';
|
||||||
|
import { HeroRenderer } from './hero';
|
||||||
|
import { ILayerGroupRenderExtends, LayerGroup } from './layer';
|
||||||
|
import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d';
|
||||||
|
import { transformCanvas } from '../item';
|
||||||
|
|
||||||
|
export class LayerGroupAnimate implements ILayerGroupRenderExtends {
|
||||||
|
static animateList: Set<LayerGroupAnimate> = new Set();
|
||||||
|
id: string = 'animate';
|
||||||
|
|
||||||
|
group!: LayerGroup;
|
||||||
|
hero!: HeroRenderer;
|
||||||
|
animate!: Animate;
|
||||||
|
|
||||||
|
private animation: Set<AnimateData> = new Set();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制一个跟随勇士的动画
|
||||||
|
* @param name 动画id
|
||||||
|
*/
|
||||||
|
async drawHeroAnimate(name: AnimationIds) {
|
||||||
|
const animate = this.animate.animate(name, 0, 0);
|
||||||
|
this.updatePosition(animate);
|
||||||
|
await this.animate.draw(animate);
|
||||||
|
this.animation.delete(animate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private updatePosition(animate: AnimateData) {
|
||||||
|
if (!this.hero.renderable) return;
|
||||||
|
const { x, y } = this.hero.renderable;
|
||||||
|
const cell = this.group.cellSize;
|
||||||
|
const half = cell / 2;
|
||||||
|
animate.centerX = x * cell + half;
|
||||||
|
animate.centerY = y * cell + half;
|
||||||
|
}
|
||||||
|
|
||||||
|
private onMoveTick = (x: number, y: number) => {
|
||||||
|
const cell = this.group.cellSize;
|
||||||
|
const half = cell / 2;
|
||||||
|
const ax = x * cell + half;
|
||||||
|
const ay = y * cell + half;
|
||||||
|
this.animation.forEach(v => {
|
||||||
|
v.centerX = ax;
|
||||||
|
v.centerY = ay;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private listen() {
|
||||||
|
this.hero.on('moveTick', this.onMoveTick);
|
||||||
|
}
|
||||||
|
|
||||||
|
awake(group: LayerGroup): void {
|
||||||
|
this.group = group;
|
||||||
|
const ex = group.getLayer('event')?.getExtends('floor-hero');
|
||||||
|
if (ex instanceof HeroRenderer) {
|
||||||
|
this.hero = ex;
|
||||||
|
this.animate = new Animate();
|
||||||
|
this.animate.size(group.width, group.height);
|
||||||
|
this.animate.setHD(true);
|
||||||
|
this.animate.setZIndex(100);
|
||||||
|
group.appendChild(this.animate);
|
||||||
|
LayerGroupAnimate.animateList.add(this);
|
||||||
|
this.listen();
|
||||||
|
} else {
|
||||||
|
logger.error(
|
||||||
|
14,
|
||||||
|
`Animate extends needs 'floor-hero' extends as dependency.`
|
||||||
|
);
|
||||||
|
group.removeExtends('animate');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDestroy(group: LayerGroup): void {
|
||||||
|
this.hero.off('moveTick', this.onMoveTick);
|
||||||
|
LayerGroupAnimate.animateList.delete(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AnimateData {
|
||||||
|
obj: globalThis.Animate;
|
||||||
|
/** 第一帧是全局第几帧 */
|
||||||
|
readonly start: number;
|
||||||
|
/** 当前是第几帧 */
|
||||||
|
index: number;
|
||||||
|
/** 是否需要播放音频 */
|
||||||
|
sound: boolean;
|
||||||
|
centerX: number;
|
||||||
|
centerY: number;
|
||||||
|
onEnd?: () => void;
|
||||||
|
readonly absolute: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Animate extends Sprite {
|
||||||
|
/** 绝对位置的动画 */
|
||||||
|
private absoluteAnimates: Set<AnimateData> = new Set();
|
||||||
|
/** 静态位置的动画 */
|
||||||
|
private staticAnimates: Set<AnimateData> = new Set();
|
||||||
|
|
||||||
|
private delegation: number;
|
||||||
|
private frame: number = 0;
|
||||||
|
private lastTime: number = 0;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super('absolute', false);
|
||||||
|
|
||||||
|
this.setRenderFn((canvas, transform) => {
|
||||||
|
const { ctx } = canvas;
|
||||||
|
ctx.save();
|
||||||
|
this.drawAnimates(this.absoluteAnimates, canvas);
|
||||||
|
transformCanvas(canvas, transform);
|
||||||
|
this.drawAnimates(this.staticAnimates, canvas);
|
||||||
|
ctx.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.delegation = this.delegateTicker(time => {
|
||||||
|
if (time - this.lastTime < 50) return;
|
||||||
|
this.lastTime = time;
|
||||||
|
this.frame++;
|
||||||
|
if (
|
||||||
|
this.absoluteAnimates.size > 0 ||
|
||||||
|
this.staticAnimates.size > 0
|
||||||
|
) {
|
||||||
|
this.update(this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
adapter.add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private drawAnimates(
|
||||||
|
data: Set<AnimateData>,
|
||||||
|
canvas: MotaOffscreenCanvas2D
|
||||||
|
) {
|
||||||
|
if (data.size === 0) return;
|
||||||
|
const { ctx } = canvas;
|
||||||
|
const toDelete = new Set<AnimateData>();
|
||||||
|
data.forEach(v => {
|
||||||
|
const obj = v.obj;
|
||||||
|
const index = v.index;
|
||||||
|
const frame = obj.frames[index];
|
||||||
|
const ratio = obj.ratio;
|
||||||
|
if (!v.sound) {
|
||||||
|
const se = (index % obj.frame) + 1;
|
||||||
|
core.playSound(v.obj.se[se], v.obj.pitch[se]);
|
||||||
|
v.sound = true;
|
||||||
|
}
|
||||||
|
const centerX = v.centerX;
|
||||||
|
const centerY = v.centerY;
|
||||||
|
|
||||||
|
frame.forEach(v => {
|
||||||
|
const img = obj.images[v.index];
|
||||||
|
if (!img) return;
|
||||||
|
|
||||||
|
const realWidth = (img.width * ratio * v.zoom) / 100;
|
||||||
|
const realHeight = (img.height * ratio * v.zoom) / 100;
|
||||||
|
ctx.globalAlpha = v.opacity / 255;
|
||||||
|
|
||||||
|
const cx = centerX + v.x;
|
||||||
|
const cy = centerY + v.y;
|
||||||
|
|
||||||
|
const ix = -realWidth / 2;
|
||||||
|
const iy = -realHeight / 2;
|
||||||
|
const angle = v.angle ? (-v.angle * Math.PI) / 180 : 0;
|
||||||
|
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(cx, cy);
|
||||||
|
if (v.mirror) {
|
||||||
|
ctx.scale(-1, 1);
|
||||||
|
}
|
||||||
|
ctx.rotate(angle);
|
||||||
|
ctx.drawImage(img, ix, iy, realWidth, realHeight);
|
||||||
|
ctx.restore();
|
||||||
|
});
|
||||||
|
const now = this.frame - v.start;
|
||||||
|
if (now !== v.index) v.sound = true;
|
||||||
|
v.index = now;
|
||||||
|
if (v.index === v.obj.frame) {
|
||||||
|
toDelete.add(v);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toDelete.forEach(v => {
|
||||||
|
data.delete(v);
|
||||||
|
v.onEnd?.();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个可以被执行的动画
|
||||||
|
* @param name 动画名称
|
||||||
|
* @param absolute 是否是绝对定位,绝对定位不会受到transform的影响
|
||||||
|
*/
|
||||||
|
animate(
|
||||||
|
name: AnimationIds,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
absolute: boolean = false
|
||||||
|
) {
|
||||||
|
const animate = core.material.animates[name];
|
||||||
|
const data: AnimateData = {
|
||||||
|
index: 0,
|
||||||
|
start: this.frame,
|
||||||
|
obj: animate,
|
||||||
|
centerX: x,
|
||||||
|
centerY: y,
|
||||||
|
absolute,
|
||||||
|
sound: false
|
||||||
|
};
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制动画,动画结束时兑现返回的Promise
|
||||||
|
* @param animate 动画信息
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
draw(animate: AnimateData): Promise<void> {
|
||||||
|
return new Promise(res => {
|
||||||
|
if (animate.absolute) {
|
||||||
|
this.absoluteAnimates.add(animate);
|
||||||
|
} else {
|
||||||
|
this.staticAnimates.add(animate);
|
||||||
|
}
|
||||||
|
animate.onEnd = () => {
|
||||||
|
res();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据动画名称、坐标、定位绘制动画
|
||||||
|
* @param name 动画名称
|
||||||
|
* @param absolute 是否是绝对定位
|
||||||
|
*/
|
||||||
|
drawAnimate(
|
||||||
|
name: AnimationIds,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
absolute: boolean = false
|
||||||
|
) {
|
||||||
|
return this.draw(this.animate(name, x, y, absolute));
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy(): void {
|
||||||
|
super.destroy();
|
||||||
|
this.removeTicker(this.delegation);
|
||||||
|
adapter.remove(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const adapter = new RenderAdapter<Animate>('animate');
|
||||||
|
adapter.receive('drawAnimate', (item, name, x, y, absolute) => {
|
||||||
|
return item.drawAnimate(name, x, y, absolute);
|
||||||
|
});
|
||||||
|
adapter.receiveGlobal('drawHeroAnimate', name => {
|
||||||
|
const execute: Promise<void>[] = [];
|
||||||
|
LayerGroupAnimate.animateList.forEach(v => {
|
||||||
|
execute.push(v.drawHeroAnimate(name));
|
||||||
|
});
|
||||||
|
return Promise.all(execute);
|
||||||
|
});
|
@ -381,9 +381,9 @@ export class LayerDoorAnimate implements ILayerRenderExtends {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const doorAdapter = new RenderAdapter<LayerDoorAnimate>('door-animate');
|
const doorAdapter = new RenderAdapter<LayerDoorAnimate>('door-animate');
|
||||||
doorAdapter.recieve('openDoor', (item, block: Block) => {
|
doorAdapter.receive('openDoor', (item, block: Block) => {
|
||||||
return item.openDoor(block);
|
return item.openDoor(block);
|
||||||
});
|
});
|
||||||
doorAdapter.recieve('closeDoor', (item, block: Block) => {
|
doorAdapter.receive('closeDoor', (item, block: Block) => {
|
||||||
return item.closeDoor(block);
|
return item.closeDoor(block);
|
||||||
});
|
});
|
||||||
|
@ -359,42 +359,42 @@ export class HeroRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
const adapter = new RenderAdapter<HeroRenderer>('hero-adapter');
|
const adapter = new RenderAdapter<HeroRenderer>('hero-adapter');
|
||||||
adapter.recieve('readyMove', item => {
|
adapter.receive('readyMove', item => {
|
||||||
item.readyMove();
|
item.readyMove();
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
});
|
});
|
||||||
adapter.recieve('move', (item, dir: Dir) => {
|
adapter.receive('move', (item, dir: Dir) => {
|
||||||
return item.move(dir);
|
return item.move(dir);
|
||||||
});
|
});
|
||||||
adapter.recieve('endMove', item => {
|
adapter.receive('endMove', item => {
|
||||||
return item.endMove();
|
return item.endMove();
|
||||||
});
|
});
|
||||||
adapter.recieve(
|
adapter.receive(
|
||||||
'moveAs',
|
'moveAs',
|
||||||
(item, x: number, y: number, time: number, fn: TimingFn<3>) => {
|
(item, x: number, y: number, time: number, fn: TimingFn<3>) => {
|
||||||
return item.moveAs(x, y, time, fn);
|
return item.moveAs(x, y, time, fn);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
adapter.recieve('setMoveSpeed', (item, speed: number) => {
|
adapter.receive('setMoveSpeed', (item, speed: number) => {
|
||||||
item.setMoveSpeed(speed);
|
item.setMoveSpeed(speed);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
});
|
});
|
||||||
adapter.recieve('setHeroLoc', (item, x?: number, y?: number) => {
|
adapter.receive('setHeroLoc', (item, x?: number, y?: number) => {
|
||||||
item.setHeroLoc(x, y);
|
item.setHeroLoc(x, y);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
});
|
});
|
||||||
adapter.recieve('turn', (item, dir: Dir2) => {
|
adapter.receive('turn', (item, dir: Dir2) => {
|
||||||
item.turn(dir);
|
item.turn(dir);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
});
|
});
|
||||||
adapter.recieve('setImage', (item, image: SizedCanvasImageSource) => {
|
adapter.receive('setImage', (item, image: SizedCanvasImageSource) => {
|
||||||
item.setImage(image);
|
item.setImage(image);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
});
|
});
|
||||||
// 同步fallback,用于适配现在的样板,之后会删除
|
// 同步fallback,用于适配现在的样板,之后会删除
|
||||||
adapter.recieveSync('setHeroLoc', (item, x?: number, y?: number) => {
|
adapter.receiveSync('setHeroLoc', (item, x?: number, y?: number) => {
|
||||||
item.setHeroLoc(x, y);
|
item.setHeroLoc(x, y);
|
||||||
});
|
});
|
||||||
adapter.recieveSync('turn', (item, dir: Dir2) => {
|
adapter.receiveSync('turn', (item, dir: Dir2) => {
|
||||||
item.turn(dir);
|
item.turn(dir);
|
||||||
});
|
});
|
||||||
|
@ -1,26 +1,30 @@
|
|||||||
import type { RenderAdapter } from '@/core/render/adapter';
|
import type { RenderAdapter } from '@/core/render/adapter';
|
||||||
|
import type { LayerGroupAnimate } from '@/core/render/preset/animate';
|
||||||
import type { LayerDoorAnimate } from '@/core/render/preset/floor';
|
import type { LayerDoorAnimate } from '@/core/render/preset/floor';
|
||||||
import type { HeroRenderer } from '@/core/render/preset/hero';
|
import type { HeroRenderer } from '@/core/render/preset/hero';
|
||||||
import { hook } from '@/game/game';
|
|
||||||
|
|
||||||
interface Adapters {
|
interface Adapters {
|
||||||
'hero-adapter'?: RenderAdapter<HeroRenderer>;
|
'hero-adapter'?: RenderAdapter<HeroRenderer>;
|
||||||
'door-animate'?: RenderAdapter<LayerDoorAnimate>;
|
'door-animate'?: RenderAdapter<LayerDoorAnimate>;
|
||||||
|
animate?: RenderAdapter<LayerGroupAnimate>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const adapters: Adapters = {};
|
const adapters: Adapters = {};
|
||||||
|
|
||||||
export function init() {
|
export function init() {
|
||||||
const hook = Mota.require('var', 'hook');
|
const hook = Mota.require('var', 'hook');
|
||||||
|
const loading = Mota.require('var', 'loading');
|
||||||
let fallbackIds: number = 1e8;
|
let fallbackIds: number = 1e8;
|
||||||
|
|
||||||
if (!main.replayChecking && main.mode === 'play') {
|
if (!main.replayChecking && main.mode === 'play') {
|
||||||
const Adapter = Mota.require('module', 'Render').RenderAdapter;
|
const Adapter = Mota.require('module', 'Render').RenderAdapter;
|
||||||
const hero = Adapter.get<HeroRenderer>('hero-adapter');
|
const hero = Adapter.get<HeroRenderer>('hero-adapter');
|
||||||
const doorAnimate = Adapter.get<LayerDoorAnimate>('door-animate');
|
const doorAnimate = Adapter.get<LayerDoorAnimate>('door-animate');
|
||||||
|
const animate = Adapter.get<LayerGroupAnimate>('animate');
|
||||||
|
|
||||||
adapters['hero-adapter'] = hero;
|
adapters['hero-adapter'] = hero;
|
||||||
adapters['door-animate'] = doorAnimate;
|
adapters['door-animate'] = doorAnimate;
|
||||||
|
adapters['animate'] = animate;
|
||||||
}
|
}
|
||||||
|
|
||||||
let moving: boolean = false;
|
let moving: boolean = false;
|
||||||
@ -391,6 +395,87 @@ export function init() {
|
|||||||
this._openDoor_animate(block, x, y, callback);
|
this._openDoor_animate(block, x, y, callback);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ----- animate & hero animate
|
||||||
|
////// 绘制动画 //////
|
||||||
|
maps.prototype.drawAnimate = function (
|
||||||
|
name: AnimationIds,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
alignWindow?: boolean,
|
||||||
|
callback?: () => void
|
||||||
|
) {
|
||||||
|
// @ts-ignore
|
||||||
|
name = core.getMappedName(name);
|
||||||
|
|
||||||
|
// 正在播放录像:不显示动画
|
||||||
|
if (
|
||||||
|
core.isReplaying() ||
|
||||||
|
!core.material.animates[name] ||
|
||||||
|
x == null ||
|
||||||
|
y == null
|
||||||
|
) {
|
||||||
|
if (callback) callback();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
adapters.animate
|
||||||
|
?.all(
|
||||||
|
'drawAnimate',
|
||||||
|
name,
|
||||||
|
x * 32 + 16,
|
||||||
|
y * 32 + 16,
|
||||||
|
alignWindow ?? false
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
callback?.();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
maps.prototype.drawHeroAnimate = function (
|
||||||
|
name: AnimationIds,
|
||||||
|
callback?: () => void
|
||||||
|
) {
|
||||||
|
// @ts-ignore
|
||||||
|
name = core.getMappedName(name);
|
||||||
|
|
||||||
|
// 正在播放录像或动画不存在:不显示动画
|
||||||
|
if (core.isReplaying() || !core.material.animates[name]) {
|
||||||
|
if (callback) callback();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
adapters.animate?.global('drawHeroAnimate', name).then(() => {
|
||||||
|
callback?.();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 开始绘制
|
||||||
|
// var animate = core.material.animates[name];
|
||||||
|
// animate.se = animate.se || {};
|
||||||
|
// if (typeof animate.se == 'string') animate.se = { 1: animate.se };
|
||||||
|
|
||||||
|
// var id = setTimeout(null);
|
||||||
|
// core.status.animateObjs.push({
|
||||||
|
// name: name,
|
||||||
|
// id: id,
|
||||||
|
// animate: animate,
|
||||||
|
// hero: true,
|
||||||
|
// index: 0,
|
||||||
|
// callback: callback
|
||||||
|
// });
|
||||||
|
|
||||||
|
// return id;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
loading.once('loaded', () => {
|
||||||
|
for (const animate of Object.values(core.material.animates)) {
|
||||||
|
animate.se ??= {};
|
||||||
|
if (typeof animate.se === 'string') {
|
||||||
|
animate.se = { 1: animate.se };
|
||||||
|
}
|
||||||
|
animate.pitch ??= {};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { readyMove, endMove, move };
|
return { readyMove, endMove, move };
|
||||||
|
5
src/types/util.d.ts
vendored
5
src/types/util.d.ts
vendored
@ -753,7 +753,7 @@ type EventValuePreffix =
|
|||||||
|
|
||||||
interface Animate {
|
interface Animate {
|
||||||
/**
|
/**
|
||||||
* 动画的帧数s
|
* 动画的帧数
|
||||||
*/
|
*/
|
||||||
frame: number;
|
frame: number;
|
||||||
|
|
||||||
@ -775,7 +775,8 @@ interface Animate {
|
|||||||
/**
|
/**
|
||||||
* 音效
|
* 音效
|
||||||
*/
|
*/
|
||||||
se: string;
|
se: any;
|
||||||
|
pitch: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Save = DeepReadonly<{
|
type Save = DeepReadonly<{
|
||||||
|
Loading…
Reference in New Issue
Block a user