mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-02-28 17:37:07 +08:00
feat: 图块移动
This commit is contained in:
parent
7c10af09c2
commit
bd432af00a
@ -11,7 +11,12 @@ import * as miscMechanism from './mechanism/misc';
|
|||||||
import * as study from './mechanism/study';
|
import * as study from './mechanism/study';
|
||||||
import { registerPresetState } from './state/preset';
|
import { registerPresetState } from './state/preset';
|
||||||
import { ItemState } from './state/item';
|
import { ItemState } from './state/item';
|
||||||
import { heroMoveCollection, HeroMover, ObjectMoverBase } from './state/move';
|
import {
|
||||||
|
BlockMover,
|
||||||
|
heroMoveCollection,
|
||||||
|
HeroMover,
|
||||||
|
ObjectMoverBase
|
||||||
|
} from './state/move';
|
||||||
|
|
||||||
// ----- 类注册
|
// ----- 类注册
|
||||||
Mota.register('class', 'DamageEnemy', damage.DamageEnemy);
|
Mota.register('class', 'DamageEnemy', damage.DamageEnemy);
|
||||||
@ -37,6 +42,7 @@ Mota.register('module', 'Mechanism', {
|
|||||||
Mota.register('module', 'State', {
|
Mota.register('module', 'State', {
|
||||||
ItemState,
|
ItemState,
|
||||||
HeroMover,
|
HeroMover,
|
||||||
|
BlockMover,
|
||||||
ObjectMoverBase,
|
ObjectMoverBase,
|
||||||
heroMoveCollection
|
heroMoveCollection
|
||||||
});
|
});
|
||||||
|
@ -5,6 +5,12 @@ import type { RenderAdapter } from '@/core/render/adapter';
|
|||||||
import type { HeroRenderer } from '@/core/render/preset/hero';
|
import type { HeroRenderer } from '@/core/render/preset/hero';
|
||||||
import type { FloorViewport } from '@/core/render/preset/viewport';
|
import type { FloorViewport } from '@/core/render/preset/viewport';
|
||||||
import type { HeroKeyMover } from '@/core/main/action/move';
|
import type { HeroKeyMover } from '@/core/main/action/move';
|
||||||
|
import type {
|
||||||
|
FloorLayer,
|
||||||
|
Layer,
|
||||||
|
LayerMovingRenderable
|
||||||
|
} from '@/core/render/preset/layer';
|
||||||
|
import type { LayerFloorBinder } from '@/core/render/preset/floor';
|
||||||
|
|
||||||
interface MoveStepDir {
|
interface MoveStepDir {
|
||||||
type: 'dir';
|
type: 'dir';
|
||||||
@ -115,8 +121,8 @@ export abstract class ObjectMoverBase extends EventEmitter<EObjectMovingEvent> {
|
|||||||
const start = async () => {
|
const start = async () => {
|
||||||
// 等待宏任务执行完成,不然controller会在首次调用中未定义
|
// 等待宏任务执行完成,不然controller会在首次调用中未定义
|
||||||
await new Promise<void>(res => res());
|
await new Promise<void>(res => res());
|
||||||
this.emit('moveStart', queue);
|
|
||||||
await this.onMoveStart(controller);
|
await this.onMoveStart(controller);
|
||||||
|
this.emit('moveStart', queue);
|
||||||
while (queue.length > 0) {
|
while (queue.length > 0) {
|
||||||
if (stopMove || !this.moving) break;
|
if (stopMove || !this.moving) break;
|
||||||
const step = queue.shift();
|
const step = queue.shift();
|
||||||
@ -126,7 +132,9 @@ export abstract class ObjectMoverBase extends EventEmitter<EObjectMovingEvent> {
|
|||||||
const code = await this.onStepStart(step, controller);
|
const code = await this.onStepStart(step, controller);
|
||||||
await this.onStepEnd(step, code, controller);
|
await this.onStepEnd(step, code, controller);
|
||||||
} else {
|
} else {
|
||||||
this.moveSpeed = step.value;
|
const replay = core.status.replay.speed;
|
||||||
|
const speed = replay === 24 ? 1 : step.value / replay;
|
||||||
|
this.moveSpeed = speed;
|
||||||
}
|
}
|
||||||
this.emit('stepEnd', step);
|
this.emit('stepEnd', step);
|
||||||
}
|
}
|
||||||
@ -189,6 +197,171 @@ export abstract class ObjectMoverBase extends EventEmitter<EObjectMovingEvent> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const enum BlockMoveCode {
|
||||||
|
Step
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BlockMover extends ObjectMoverBase {
|
||||||
|
/** 楼层渲染适配器,用于显示动画 */
|
||||||
|
static adapter?: RenderAdapter<Layer>;
|
||||||
|
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
floorId: FloorIds;
|
||||||
|
layer: FloorLayer;
|
||||||
|
|
||||||
|
/** 本次移动中需要进行动画移动的楼层渲染组件 */
|
||||||
|
private layerItems: Layer[] = [];
|
||||||
|
/** 本次移动过程中的移动renderable实例 */
|
||||||
|
private renderable?: LayerMovingRenderable;
|
||||||
|
/** 本次移动的图块id */
|
||||||
|
private blockNum: number = 0;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
floorId: FloorIds,
|
||||||
|
layer: FloorLayer,
|
||||||
|
dir: Dir = 'down'
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.floorId = floorId;
|
||||||
|
this.moveDir = dir;
|
||||||
|
this.layer = layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定移动点
|
||||||
|
* @param x 绑定点横坐标
|
||||||
|
* @param y 绑定点纵坐标
|
||||||
|
* @param floorId 绑定点楼层
|
||||||
|
* @returns 是否绑定成功,例如如果当前绑定点正在移动,那么就会绑定失败
|
||||||
|
*/
|
||||||
|
bind(
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
floorId: FloorIds,
|
||||||
|
layer: FloorLayer,
|
||||||
|
dir: Dir = 'down'
|
||||||
|
) {
|
||||||
|
if (this.moving) return false;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.floorId = floorId;
|
||||||
|
this.moveDir = dir;
|
||||||
|
this.layer = layer;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async onMoveStart(controller: IMoveController): Promise<void> {
|
||||||
|
const adapter = BlockMover.adapter;
|
||||||
|
if (adapter) {
|
||||||
|
const list = adapter.items;
|
||||||
|
const items = [...list].filter(v => {
|
||||||
|
if (v.layer !== this.layer) return false;
|
||||||
|
const ex = v.getExtends('floor-binder') as LayerFloorBinder;
|
||||||
|
if (!ex) return false;
|
||||||
|
return ex.getFloor() === core.status.floorId;
|
||||||
|
});
|
||||||
|
this.layerItems = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
let blockNum: number = 0;
|
||||||
|
if (this.layer === 'event') {
|
||||||
|
blockNum = core.status.maps[this.floorId].map[this.y][this.x];
|
||||||
|
} else {
|
||||||
|
const array = core.maps._getBgFgMapArray(this.layer, this.floorId);
|
||||||
|
blockNum = array[this.y][this.x];
|
||||||
|
}
|
||||||
|
this.blockNum = blockNum;
|
||||||
|
|
||||||
|
Mota.r(() => {
|
||||||
|
const { Layer } = Mota.require('module', 'Render');
|
||||||
|
const r = Layer.getMovingRenderable(blockNum, this.x, this.y);
|
||||||
|
|
||||||
|
if (r) {
|
||||||
|
this.renderable = r;
|
||||||
|
this.layerItems.forEach(v => {
|
||||||
|
v.moving.add(r);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.layer === 'event') {
|
||||||
|
core.removeBlock(this.x, this.y, this.floorId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async onMoveEnd(controller: IMoveController): Promise<void> {
|
||||||
|
if (this.renderable) {
|
||||||
|
this.layerItems.forEach(v => {
|
||||||
|
v.moving.delete(this.renderable!);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.layerItems = [];
|
||||||
|
this.renderable = void 0;
|
||||||
|
|
||||||
|
if (this.layer === 'event') {
|
||||||
|
core.setBlock(this.blockNum as AllNumbers, this.x, this.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async onStepStart(
|
||||||
|
step: MoveStepDir,
|
||||||
|
controller: IMoveController
|
||||||
|
): Promise<BlockMoveCode> {
|
||||||
|
await this.moveAnimate(step);
|
||||||
|
const { x: dx, y: dy } = core.utils.scan2[this.moveDir];
|
||||||
|
this.x += dx;
|
||||||
|
this.y += dy;
|
||||||
|
|
||||||
|
return BlockMoveCode.Step;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async onStepEnd(
|
||||||
|
step: MoveStepDir,
|
||||||
|
code: BlockMoveCode,
|
||||||
|
controller: IMoveController
|
||||||
|
): Promise<void> {}
|
||||||
|
|
||||||
|
private moveAnimate(step: MoveStepDir) {
|
||||||
|
const layer = this.layerItems[0];
|
||||||
|
if (!layer) return;
|
||||||
|
if (!this.renderable) return;
|
||||||
|
const data = this.renderable;
|
||||||
|
const fx = this.x;
|
||||||
|
const fy = this.y;
|
||||||
|
const { x: dx, y: dy } = core.utils.scan2[this.moveDir];
|
||||||
|
const start = Date.now();
|
||||||
|
const time = this.moveSpeed;
|
||||||
|
|
||||||
|
return new Promise<void>(res => {
|
||||||
|
layer.delegateTicker(
|
||||||
|
() => {
|
||||||
|
const now = Date.now() - start;
|
||||||
|
const progress = now / time;
|
||||||
|
data.x = fx + dx * progress;
|
||||||
|
data.y = fy + dy * progress;
|
||||||
|
this.layerItems.forEach(v => {
|
||||||
|
v.update(v);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
this.moveSpeed,
|
||||||
|
() => {
|
||||||
|
data.x = fx + dx;
|
||||||
|
data.y = fy + dy;
|
||||||
|
data.zIndex = fy + dy;
|
||||||
|
res();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface CanMoveStatus {
|
interface CanMoveStatus {
|
||||||
/** 由CannotIn和CannotOut计算出的信息,不可移动时不会触发触发器 */
|
/** 由CannotIn和CannotOut计算出的信息,不可移动时不会触发触发器 */
|
||||||
canMove: boolean;
|
canMove: boolean;
|
||||||
@ -408,6 +581,8 @@ loading.once('coreInit', () => {
|
|||||||
const Adapter = Mota.require('module', 'Render').RenderAdapter;
|
const Adapter = Mota.require('module', 'Render').RenderAdapter;
|
||||||
const adapter = Adapter.get<HeroRenderer>('hero-adapter');
|
const adapter = Adapter.get<HeroRenderer>('hero-adapter');
|
||||||
const viewport = Adapter.get<FloorViewport>('viewport');
|
const viewport = Adapter.get<FloorViewport>('viewport');
|
||||||
|
const layerAdapter = Adapter.get<Layer>('layer');
|
||||||
HeroMover.adapter = adapter;
|
HeroMover.adapter = adapter;
|
||||||
HeroMover.viewport = viewport;
|
HeroMover.viewport = viewport;
|
||||||
|
BlockMover.adapter = layerAdapter;
|
||||||
});
|
});
|
||||||
|
@ -38,7 +38,7 @@ import type { ItemState } from './state/item';
|
|||||||
import type { Layer } from '@/core/render/preset/layer';
|
import type { Layer } from '@/core/render/preset/layer';
|
||||||
import type { LayerGroupFloorBinder } from '@/core/render/preset/floor';
|
import type { LayerGroupFloorBinder } from '@/core/render/preset/floor';
|
||||||
import type { HeroKeyMover } from '@/core/main/action/move';
|
import type { HeroKeyMover } from '@/core/main/action/move';
|
||||||
import type { HeroMover, ObjectMoverBase } from './state/move';
|
import type { BlockMover, HeroMover, ObjectMoverBase } from './state/move';
|
||||||
|
|
||||||
interface ClassInterface {
|
interface ClassInterface {
|
||||||
// 渲染进程与游戏进程通用
|
// 渲染进程与游戏进程通用
|
||||||
@ -124,6 +124,7 @@ interface ModuleInterface {
|
|||||||
State: {
|
State: {
|
||||||
ItemState: typeof ItemState;
|
ItemState: typeof ItemState;
|
||||||
HeroMover: typeof HeroMover;
|
HeroMover: typeof HeroMover;
|
||||||
|
BlockMover: typeof BlockMover;
|
||||||
ObjectMoverBase: typeof ObjectMoverBase;
|
ObjectMoverBase: typeof ObjectMoverBase;
|
||||||
heroMoveCollection: {
|
heroMoveCollection: {
|
||||||
mover: HeroMover;
|
mover: HeroMover;
|
||||||
|
@ -9,8 +9,7 @@ import type { Layer, LayerMovingRenderable } from '@/core/render/preset/layer';
|
|||||||
import { BluePalace } from '@/game/mechanism/misc';
|
import { BluePalace } from '@/game/mechanism/misc';
|
||||||
import { backDir } from './utils';
|
import { backDir } from './utils';
|
||||||
import type { TimingFn } from 'mutate-animate';
|
import type { TimingFn } from 'mutate-animate';
|
||||||
import EventEmitter from 'eventemitter3';
|
import { BlockMover, heroMoveCollection, MoveStep } from '@/game/state/move';
|
||||||
import { heroMoveCollection, MoveStep } from '@/game/state/move';
|
|
||||||
import type { FloorViewport } from '@/core/render/preset/viewport';
|
import type { FloorViewport } from '@/core/render/preset/viewport';
|
||||||
|
|
||||||
// 向后兼容用,会充当两个版本间过渡的作用
|
// 向后兼容用,会充当两个版本间过渡的作用
|
||||||
@ -23,11 +22,6 @@ interface Adapters {
|
|||||||
viewport?: RenderAdapter<FloorViewport>;
|
viewport?: RenderAdapter<FloorViewport>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MoveEvent {
|
|
||||||
stepEnd: [];
|
|
||||||
moveEnd: [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const adapters: Adapters = {};
|
const adapters: Adapters = {};
|
||||||
|
|
||||||
export function init() {
|
export function init() {
|
||||||
@ -62,15 +56,15 @@ export function init() {
|
|||||||
noRoute: boolean = false,
|
noRoute: boolean = false,
|
||||||
callback?: () => void
|
callback?: () => void
|
||||||
) {
|
) {
|
||||||
if (portal && portalData) {
|
// if (portal && portalData) {
|
||||||
const before = moveDir;
|
// const before = moveDir;
|
||||||
const { x, y, dir } = portalData;
|
// const { x, y, dir } = portalData;
|
||||||
core.setHeroLoc('x', x);
|
// core.setHeroLoc('x', x);
|
||||||
core.setHeroLoc('y', y);
|
// core.setHeroLoc('y', y);
|
||||||
core.setHeroLoc('direction', dir);
|
// core.setHeroLoc('direction', dir);
|
||||||
portal = false;
|
// portal = false;
|
||||||
moveDir = before;
|
// moveDir = before;
|
||||||
}
|
// }
|
||||||
|
|
||||||
var direction = core.getHeroLoc('direction');
|
var direction = core.getHeroLoc('direction');
|
||||||
core.control._moveAction_popAutomaticRoute();
|
core.control._moveAction_popAutomaticRoute();
|
||||||
@ -619,61 +613,30 @@ export function init() {
|
|||||||
callback?.();
|
callback?.();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const speed = core.status.replay.speed;
|
|
||||||
time /= speed;
|
|
||||||
if (speed === 24) time = 1;
|
|
||||||
const block = core.getBlock(x, y);
|
const block = core.getBlock(x, y);
|
||||||
if (!block) {
|
if (!block) {
|
||||||
callback?.();
|
callback?.();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
core.removeBlock(x, y);
|
const mover = new BlockMover(x, y, core.status.floorId, 'event');
|
||||||
const list = adapters.layer?.items ?? [];
|
const moveSteps = getMoveSteps(steps);
|
||||||
const items = [...list].filter(v => {
|
const resolved = moveSteps.map<MoveStep>(v => {
|
||||||
if (v.layer !== 'event') return false;
|
if (v.startsWith('speed')) {
|
||||||
const ex = v.getExtends('floor-binder') as LayerFloorBinder;
|
return { type: 'speed', value: Number(v.slice(6)) };
|
||||||
if (!ex) return false;
|
} else {
|
||||||
return ex.getFloor() === core.status.floorId;
|
return { type: 'dir', value: v as Move2 };
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
const start: MoveStep = { type: 'speed', value: time };
|
||||||
|
mover.insertMove(...[start, ...resolved]);
|
||||||
|
const controller = mover.startMove();
|
||||||
|
|
||||||
const { steps: moveSteps, start } = getMoveSteps(steps);
|
if (controller) {
|
||||||
if (!start || items.length === 0) {
|
await controller.onEnd;
|
||||||
callback?.();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let stepDir: Dir2;
|
|
||||||
let nx = x;
|
|
||||||
let ny = y;
|
|
||||||
if (start === 'backward' || start === 'forward') stepDir = 'down';
|
|
||||||
else stepDir = start;
|
|
||||||
|
|
||||||
const { Layer } = Mota.require('module', 'Render');
|
|
||||||
const moving = Layer.getMovingRenderable(block.id, x, y);
|
|
||||||
if (!moving) {
|
|
||||||
callback?.();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
items.forEach(v => v.moving.add(moving));
|
|
||||||
|
|
||||||
for (const step of moveSteps) {
|
|
||||||
if (step === 'backward') stepDir = backDir(stepDir);
|
|
||||||
else if (step.startsWith('speed')) {
|
|
||||||
time = parseInt(step.slice(6));
|
|
||||||
continue;
|
|
||||||
} else stepDir = step as Dir2;
|
|
||||||
|
|
||||||
const { x, y } = core.utils.scan2[stepDir];
|
|
||||||
const tx = nx + x;
|
|
||||||
const ty = ny + y;
|
|
||||||
await moveRenderable(items[0], moving, time, tx, ty);
|
|
||||||
nx = tx;
|
|
||||||
ny = ty;
|
|
||||||
moving.zIndex = ty;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
items.forEach(v => v.moving.delete(moving));
|
if (!keep) {
|
||||||
if (keep) {
|
core.removeBlock(mover.x, mover.y);
|
||||||
core.setBlock(block.id, nx, ny);
|
|
||||||
}
|
}
|
||||||
callback?.();
|
callback?.();
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user