mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-01-19 12:49:25 +08:00
feat: 开关门动画
This commit is contained in:
parent
e5afdb73fd
commit
053de036ec
@ -1,6 +1,6 @@
|
|||||||
import { FloorItemDetail } from '@/plugin/fx/itemDetail';
|
import { FloorItemDetail } from '@/plugin/fx/itemDetail';
|
||||||
import { FloorDamageExtends } from './preset/damage';
|
import { FloorDamageExtends } from './preset/damage';
|
||||||
import { LayerGroupFloorBinder } from './preset/floor';
|
import { LayerDoorAnimate, LayerGroupFloorBinder } from './preset/floor';
|
||||||
import { HeroRenderer } from './preset/hero';
|
import { HeroRenderer } from './preset/hero';
|
||||||
import { LayerGroup, FloorLayer } from './preset/layer';
|
import { LayerGroup, FloorLayer } from './preset/layer';
|
||||||
import { MotaRenderer } from './render';
|
import { MotaRenderer } from './render';
|
||||||
@ -26,9 +26,11 @@ Mota.require('var', 'loading').once('loaded', () => {
|
|||||||
const damage = new FloorDamageExtends();
|
const damage = new FloorDamageExtends();
|
||||||
const hero = new HeroRenderer();
|
const hero = new HeroRenderer();
|
||||||
const detail = new FloorItemDetail();
|
const detail = new FloorItemDetail();
|
||||||
|
const door = new LayerDoorAnimate();
|
||||||
layer.extends(damage);
|
layer.extends(damage);
|
||||||
layer.extends(detail);
|
layer.extends(detail);
|
||||||
layer.getLayer('event')?.extends(hero);
|
layer.getLayer('event')?.extends(hero);
|
||||||
|
layer.getLayer('event')?.extends(door);
|
||||||
|
|
||||||
render.appendChild(layer);
|
render.appendChild(layer);
|
||||||
});
|
});
|
||||||
|
@ -4,9 +4,12 @@ import {
|
|||||||
ILayerGroupRenderExtends,
|
ILayerGroupRenderExtends,
|
||||||
ILayerRenderExtends,
|
ILayerRenderExtends,
|
||||||
Layer,
|
Layer,
|
||||||
LayerGroup
|
LayerGroup,
|
||||||
|
LayerMovingRenderable
|
||||||
} from './layer';
|
} from './layer';
|
||||||
import { texture } from '../cache';
|
import { texture } from '../cache';
|
||||||
|
import { sleep } from 'mutate-animate';
|
||||||
|
import { RenderAdapter } from '../adapter';
|
||||||
|
|
||||||
const hook = Mota.require('var', 'hook');
|
const hook = Mota.require('var', 'hook');
|
||||||
|
|
||||||
@ -281,16 +284,105 @@ export class LayerFloorBinder implements ILayerRenderExtends {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class LayerOpenDoorAnimate implements ILayerRenderExtends {
|
interface DoorAnimateRenderable {
|
||||||
id: string = 'open-door-animate';
|
renderable: LayerMovingRenderable;
|
||||||
|
count: number;
|
||||||
|
perTime: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LayerDoorAnimate implements ILayerRenderExtends {
|
||||||
|
id: string = 'door-animate';
|
||||||
|
|
||||||
layer!: Layer;
|
layer!: Layer;
|
||||||
|
|
||||||
|
private moving: Set<LayerMovingRenderable> = new Set();
|
||||||
|
|
||||||
|
private getRenderable(block: Block): DoorAnimateRenderable | null {
|
||||||
|
const { x, y, id } = block;
|
||||||
|
const renderable = texture.getRenderable(id);
|
||||||
|
if (!renderable) return null;
|
||||||
|
const image = renderable.autotile
|
||||||
|
? renderable.image[0]
|
||||||
|
: renderable.image;
|
||||||
|
const time = block.event.doorInfo?.time ?? 160;
|
||||||
|
const frame = renderable.render.length;
|
||||||
|
const perTime = time / frame;
|
||||||
|
|
||||||
|
const data: LayerMovingRenderable = {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
zIndex: y,
|
||||||
|
image,
|
||||||
|
autotile: false,
|
||||||
|
animate: 0,
|
||||||
|
frame,
|
||||||
|
bigImage: false,
|
||||||
|
render: renderable.render
|
||||||
|
};
|
||||||
|
return { renderable: data, count: frame, perTime };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开门
|
||||||
|
* @param block 图块信息
|
||||||
|
*/
|
||||||
|
async openDoor(block: Block) {
|
||||||
|
const renderable = this.getRenderable(block);
|
||||||
|
if (!renderable) return Promise.reject();
|
||||||
|
const { renderable: data, count: frame, perTime } = renderable;
|
||||||
|
data.animate = 0;
|
||||||
|
this.moving.add(data);
|
||||||
|
|
||||||
|
let now = 0;
|
||||||
|
while (now < frame) {
|
||||||
|
await sleep(perTime);
|
||||||
|
data.animate = ++now;
|
||||||
|
this.layer.update(this.layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.moving.delete(data);
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关门
|
||||||
|
* @param block 图块信息
|
||||||
|
*/
|
||||||
|
async closeDoor(block: Block) {
|
||||||
|
const renderable = this.getRenderable(block);
|
||||||
|
if (!renderable) return Promise.reject();
|
||||||
|
const { renderable: data, count: frame, perTime } = renderable;
|
||||||
|
data.animate = frame - 1;
|
||||||
|
this.moving.add(data);
|
||||||
|
|
||||||
|
let now = 0;
|
||||||
|
while (now >= 0) {
|
||||||
|
await sleep(perTime);
|
||||||
|
data.animate = --now;
|
||||||
|
this.layer.update(this.layer);
|
||||||
|
}
|
||||||
|
this.moving.delete(data);
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
awake(layer: Layer) {
|
awake(layer: Layer) {
|
||||||
this.layer = layer;
|
this.layer = layer;
|
||||||
|
doorAdapter.add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
openDoor(x: number, y: number) {}
|
onMovingUpdate(layer: Layer, renderable: LayerMovingRenderable[]): void {
|
||||||
|
renderable.push(...this.moving);
|
||||||
closeDoor(x: number, y: number) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onDestroy(layer: Layer): void {
|
||||||
|
doorAdapter.remove(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const doorAdapter = new RenderAdapter<LayerDoorAnimate>('door-animate');
|
||||||
|
doorAdapter.recieve('openDoor', (item, block: Block) => {
|
||||||
|
return item.openDoor(block);
|
||||||
|
});
|
||||||
|
doorAdapter.recieve('closeDoor', (item, block: Block) => {
|
||||||
|
return item.closeDoor(block);
|
||||||
|
});
|
||||||
|
@ -1,19 +1,26 @@
|
|||||||
import type { RenderAdapter } from '@/core/render/adapter';
|
import type { RenderAdapter } from '@/core/render/adapter';
|
||||||
|
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';
|
import { hook } from '@/game/game';
|
||||||
|
|
||||||
interface Adapters {
|
interface Adapters {
|
||||||
'hero-adapter'?: RenderAdapter<HeroRenderer>;
|
'hero-adapter'?: RenderAdapter<HeroRenderer>;
|
||||||
|
'door-animate'?: RenderAdapter<LayerDoorAnimate>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const adapters: Adapters = {};
|
const adapters: Adapters = {};
|
||||||
|
|
||||||
export function init() {
|
export function init() {
|
||||||
|
const hook = Mota.require('var', 'hook');
|
||||||
|
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');
|
||||||
|
|
||||||
adapters['hero-adapter'] = hero;
|
adapters['hero-adapter'] = hero;
|
||||||
|
adapters['door-animate'] = doorAnimate;
|
||||||
}
|
}
|
||||||
|
|
||||||
let moving: boolean = false;
|
let moving: boolean = false;
|
||||||
@ -280,6 +287,134 @@ export function init() {
|
|||||||
moveDir = core.status.hero.loc.direction;
|
moveDir = core.status.hero.loc.direction;
|
||||||
stepDir = moveDir;
|
stepDir = moveDir;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ----- 开关门
|
||||||
|
events.prototype.openDoor = function (
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
needKey: boolean,
|
||||||
|
callback?: () => void
|
||||||
|
) {
|
||||||
|
var block = core.getBlock(x, y);
|
||||||
|
core.saveAndStopAutomaticRoute();
|
||||||
|
if (!this._openDoor_check(block, x, y, needKey)) {
|
||||||
|
var locked = core.status.lockControl;
|
||||||
|
core.waitHeroToStop(function () {
|
||||||
|
if (!locked) core.unlockControl();
|
||||||
|
if (callback) callback();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (core.status.replay.speed === 24) {
|
||||||
|
core.status.replay.animate = true;
|
||||||
|
core.removeBlock(x, y);
|
||||||
|
setTimeout(function () {
|
||||||
|
core.status.replay.animate = false;
|
||||||
|
Mota.require('var', 'hook').emit(
|
||||||
|
'afterOpenDoor',
|
||||||
|
block.event.id,
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
);
|
||||||
|
if (callback) callback();
|
||||||
|
}, 1); // +1是为了录像检测系统
|
||||||
|
} else {
|
||||||
|
const locked = core.status.lockControl;
|
||||||
|
core.lockControl();
|
||||||
|
core.status.replay.animate = true;
|
||||||
|
core.removeBlock(x, y);
|
||||||
|
|
||||||
|
const cb = () => {
|
||||||
|
core.maps._removeBlockFromMap(core.status.floorId, block);
|
||||||
|
if (!locked) core.unlockControl();
|
||||||
|
core.status.replay.animate = false;
|
||||||
|
hook.emit('afterOpenDoor', block.event.id, x, y);
|
||||||
|
callback?.();
|
||||||
|
};
|
||||||
|
|
||||||
|
adapters['door-animate']?.all('openDoor', block).then(cb);
|
||||||
|
|
||||||
|
const animate = fallbackIds++;
|
||||||
|
core.animateFrame.lastAsyncId = animate;
|
||||||
|
core.animateFrame.asyncId[animate] = cb;
|
||||||
|
this._openDoor_animate(block, x, y, callback);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
events.prototype.closeDoor = function (
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
id: AllIds,
|
||||||
|
callback?: () => void
|
||||||
|
) {
|
||||||
|
id = id || '';
|
||||||
|
if (
|
||||||
|
// @ts-ignore
|
||||||
|
(core.material.icons.animates[id] == null &&
|
||||||
|
// @ts-ignore
|
||||||
|
core.material.icons.npc48[id] == null) ||
|
||||||
|
core.getBlock(x, y) != null
|
||||||
|
) {
|
||||||
|
if (callback) callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var block = core.getBlockById(id);
|
||||||
|
var doorInfo = (block.event || {}).doorInfo;
|
||||||
|
if (!doorInfo) {
|
||||||
|
if (callback) callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
core.playSound(doorInfo.closeSound);
|
||||||
|
|
||||||
|
const locked = core.status.lockControl;
|
||||||
|
core.lockControl();
|
||||||
|
core.status.replay.animate = true;
|
||||||
|
const cb = function () {
|
||||||
|
if (!locked) core.unlockControl();
|
||||||
|
core.status.replay.animate = false;
|
||||||
|
core.setBlock(id, x, y);
|
||||||
|
core.showBlock(x, y);
|
||||||
|
callback?.();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (core.status.replay.speed === 24) {
|
||||||
|
cb();
|
||||||
|
} else {
|
||||||
|
adapters['door-animate']?.all('closeDoor', block).then(() => {
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
|
||||||
|
const animate = fallbackIds++;
|
||||||
|
core.animateFrame.lastAsyncId = animate;
|
||||||
|
core.animateFrame.asyncId[animate] = cb;
|
||||||
|
this._openDoor_animate(block, x, y, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// var blockInfo = core.getBlockInfo(block);
|
||||||
|
// var speed = (doorInfo.time || 160) / 4;
|
||||||
|
// blockInfo.posX = 3;
|
||||||
|
// core.maps._drawBlockInfo(blockInfo, x, y);
|
||||||
|
|
||||||
|
// var animate = window.setInterval(
|
||||||
|
// function () {
|
||||||
|
// blockInfo.posX--;
|
||||||
|
// if (blockInfo.posX < 0) {
|
||||||
|
// clearInterval(animate);
|
||||||
|
// delete core.animateFrame.asyncId[animate];
|
||||||
|
// cb();
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// core.maps._drawBlockInfo(blockInfo, x, y);
|
||||||
|
// },
|
||||||
|
// core.status.replay.speed == 24
|
||||||
|
// ? 1
|
||||||
|
// : speed / Math.max(core.status.replay.speed, 1)
|
||||||
|
// );
|
||||||
|
|
||||||
|
// core.animateFrame.lastAsyncId = animate;
|
||||||
|
// core.animateFrame.asyncId[animate] = cb;
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return { readyMove, endMove, move };
|
return { readyMove, endMove, move };
|
||||||
|
2
src/types/core.d.ts
vendored
2
src/types/core.d.ts
vendored
@ -275,7 +275,7 @@ interface AnimateFrame {
|
|||||||
/**
|
/**
|
||||||
* 上一个异步事件的id
|
* 上一个异步事件的id
|
||||||
*/
|
*/
|
||||||
readonly lastAsyncId: number;
|
lastAsyncId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Weather {
|
interface Weather {
|
||||||
|
2
src/types/map.d.ts
vendored
2
src/types/map.d.ts
vendored
@ -1403,6 +1403,8 @@ interface Maps {
|
|||||||
floorId: FloorIds,
|
floorId: FloorIds,
|
||||||
noCache?: boolean
|
noCache?: boolean
|
||||||
): number[][];
|
): number[][];
|
||||||
|
|
||||||
|
_removeBlockFromMap(floorId: FloorIds, block: Block): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare const maps: new () => Maps;
|
declare const maps: new () => Maps;
|
||||||
|
2
src/types/status.d.ts
vendored
2
src/types/status.d.ts
vendored
@ -661,7 +661,7 @@ interface InitGameStatus {
|
|||||||
/**
|
/**
|
||||||
* 当前的回放状态
|
* 当前的回放状态
|
||||||
*/
|
*/
|
||||||
replay: DeepReadonly<ReplayStatus>;
|
replay: ReplayStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前的所有全局商店
|
* 当前的所有全局商店
|
||||||
|
Loading…
Reference in New Issue
Block a user