mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-03-01 01:57:05 +08:00
refactor: 传送门移动
This commit is contained in:
parent
0611b1864d
commit
f407b5cb74
@ -11,6 +11,7 @@ import type {
|
|||||||
LayerMovingRenderable
|
LayerMovingRenderable
|
||||||
} from '@/core/render/preset/layer';
|
} from '@/core/render/preset/layer';
|
||||||
import type { LayerFloorBinder } from '@/core/render/preset/floor';
|
import type { LayerFloorBinder } from '@/core/render/preset/floor';
|
||||||
|
import { BluePalace } from '../mechanism/misc';
|
||||||
|
|
||||||
interface MoveStepDir {
|
interface MoveStepDir {
|
||||||
type: 'dir';
|
type: 'dir';
|
||||||
@ -369,6 +370,13 @@ interface CanMoveStatus {
|
|||||||
noPass: boolean;
|
noPass: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface PortalStatus {
|
||||||
|
/** 下一步是否会步入传送门 */
|
||||||
|
portal: boolean;
|
||||||
|
/** 传送门会传到哪 */
|
||||||
|
data?: BluePalace.PortalTo;
|
||||||
|
}
|
||||||
|
|
||||||
const enum HeroMoveCode {
|
const enum HeroMoveCode {
|
||||||
Step,
|
Step,
|
||||||
Stop,
|
Stop,
|
||||||
@ -393,6 +401,9 @@ export class HeroMover extends ObjectMoverBase {
|
|||||||
/** 当前移动是否是在lockControl条件下开始的 */
|
/** 当前移动是否是在lockControl条件下开始的 */
|
||||||
private inLockControl: boolean = false;
|
private inLockControl: boolean = false;
|
||||||
|
|
||||||
|
/** 这一步的传送门信息 */
|
||||||
|
private portalData?: BluePalace.PortalTo;
|
||||||
|
|
||||||
override startMove(
|
override startMove(
|
||||||
ignoreTerrain: boolean = false,
|
ignoreTerrain: boolean = false,
|
||||||
noRoute: boolean = false,
|
noRoute: boolean = false,
|
||||||
@ -439,6 +450,16 @@ export class HeroMover extends ObjectMoverBase {
|
|||||||
this.moveDir = showDir;
|
this.moveDir = showDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查传送门
|
||||||
|
if (!this.ignoreTerrain) {
|
||||||
|
const { portal, data } = this.checkPortal(x, y, showDir);
|
||||||
|
if (portal && data) {
|
||||||
|
this.portalData = data;
|
||||||
|
await this.renderHeroSwap(data);
|
||||||
|
return HeroMoveCode.Portal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const dir = this.moveDir;
|
const dir = this.moveDir;
|
||||||
if (!this.ignoreTerrain) {
|
if (!this.ignoreTerrain) {
|
||||||
const { noPass, canMove } = this.checkCanMove(x, y, showDir);
|
const { noPass, canMove } = this.checkCanMove(x, y, showDir);
|
||||||
@ -482,9 +503,17 @@ export class HeroMover extends ObjectMoverBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 本次移动正常完成
|
// 本次移动正常完成
|
||||||
if (code === HeroMoveCode.Step) {
|
if (code === HeroMoveCode.Step || code === HeroMoveCode.Portal) {
|
||||||
core.setHeroLoc('x', nx, true);
|
if (code === HeroMoveCode.Portal) {
|
||||||
core.setHeroLoc('y', ny, true);
|
const data = this.portalData;
|
||||||
|
if (!data) return;
|
||||||
|
core.setHeroLoc('x', data.x);
|
||||||
|
core.setHeroLoc('y', data.y);
|
||||||
|
core.setHeroLoc('direction', data.dir);
|
||||||
|
} else {
|
||||||
|
core.setHeroLoc('x', nx, true);
|
||||||
|
core.setHeroLoc('y', ny, true);
|
||||||
|
}
|
||||||
|
|
||||||
const direction = core.getHeroLoc('direction');
|
const direction = core.getHeroLoc('direction');
|
||||||
core.control._moveAction_popAutomaticRoute();
|
core.control._moveAction_popAutomaticRoute();
|
||||||
@ -555,6 +584,121 @@ export class HeroMover extends ObjectMoverBase {
|
|||||||
const ny = y + dy;
|
const ny = y + dy;
|
||||||
return { x: nx, y: ny };
|
return { x: nx, y: ny };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查前方一格是否会步入传送门
|
||||||
|
* @param x 横坐标
|
||||||
|
* @param y 纵坐标
|
||||||
|
* @param dir 移动方向
|
||||||
|
*/
|
||||||
|
private checkPortal(x: number, y: number, dir: Dir): PortalStatus {
|
||||||
|
const map = BluePalace.portalMap.get(core.status.floorId);
|
||||||
|
if (!map) {
|
||||||
|
return { portal: false };
|
||||||
|
}
|
||||||
|
const width = core.status.thisMap.width;
|
||||||
|
const index = x + y * width;
|
||||||
|
const data = map?.get(index);
|
||||||
|
if (!data) {
|
||||||
|
return { portal: false };
|
||||||
|
}
|
||||||
|
const to = data[dir];
|
||||||
|
if (to) {
|
||||||
|
return { portal: true, data: to };
|
||||||
|
}
|
||||||
|
return { portal: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderHeroSwap(data: BluePalace.PortalTo) {
|
||||||
|
const adapter = HeroMover.adapter;
|
||||||
|
if (!adapter) return;
|
||||||
|
const list = adapter.items;
|
||||||
|
const { x: tx, y: ty, dir: toDir } = data;
|
||||||
|
const { x, y, direction } = core.status.hero.loc;
|
||||||
|
const { x: dx, y: dy } = core.utils.scan[direction];
|
||||||
|
const { x: tdx } = core.utils.scan[toDir];
|
||||||
|
|
||||||
|
const promises = [...list].map(v => {
|
||||||
|
if (!v.renderable) return;
|
||||||
|
const renderable = { ...v.renderable };
|
||||||
|
renderable.render = v.getRenderFromDir(toDir);
|
||||||
|
renderable.zIndex = ty;
|
||||||
|
const heroDir = v.moveDir;
|
||||||
|
|
||||||
|
const width = v.renderable.render[0][2];
|
||||||
|
const height = v.renderable.render[0][3];
|
||||||
|
const cell = v.layer.cellSize;
|
||||||
|
const restHeight = height - cell;
|
||||||
|
if (!width || !height) return;
|
||||||
|
|
||||||
|
const originFrom = structuredClone(v.renderable.render);
|
||||||
|
const originTo = structuredClone(renderable.render);
|
||||||
|
v.layer.moving.add(renderable);
|
||||||
|
v.layer.requestUpdateMoving();
|
||||||
|
|
||||||
|
const start = Date.now();
|
||||||
|
return new Promise<void>(res => {
|
||||||
|
const tick = () => {
|
||||||
|
const now = Date.now();
|
||||||
|
const progress = (now - start) / this.moveSpeed;
|
||||||
|
const clipWidth = cell * progress;
|
||||||
|
const clipHeight = cell * progress;
|
||||||
|
const beforeWidth = width - clipWidth;
|
||||||
|
const beforeHeight = height - clipHeight;
|
||||||
|
|
||||||
|
v.renderable!.x = x;
|
||||||
|
v.renderable!.y = y;
|
||||||
|
if (heroDir === 'left' || heroDir === 'right') {
|
||||||
|
v.renderable!.x = x + (clipWidth / 2 / cell) * dx;
|
||||||
|
v.renderable!.render.forEach((v, i) => {
|
||||||
|
v[2] = beforeWidth;
|
||||||
|
if (heroDir === 'left') {
|
||||||
|
v[0] = originFrom[i][0] + clipWidth;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
v.renderable!.render.forEach((v, i) => {
|
||||||
|
v[3] = beforeHeight;
|
||||||
|
if (heroDir === 'up') {
|
||||||
|
v[1] =
|
||||||
|
originFrom[i][1] + clipHeight + restHeight;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderable.x = tx;
|
||||||
|
renderable.y = ty;
|
||||||
|
if (toDir === 'left' || toDir === 'right') {
|
||||||
|
renderable.x = tx + (clipWidth / 2 / cell - 0.5) * tdx;
|
||||||
|
renderable.render.forEach((v, i) => {
|
||||||
|
v[2] = clipWidth;
|
||||||
|
if (toDir === 'right') {
|
||||||
|
v[0] = originTo[i][0] + beforeWidth;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (toDir === 'down') renderable.y = ty - 1 + progress;
|
||||||
|
renderable.render.forEach((v, i) => {
|
||||||
|
v[3] = clipHeight + restHeight;
|
||||||
|
if (toDir === 'down') {
|
||||||
|
v[1] = originTo[i][1] + clipHeight + restHeight;
|
||||||
|
v[3] = clipHeight;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
v.layer.delegateTicker(tick, this.moveSpeed, () => {
|
||||||
|
v.renderable!.render = originFrom;
|
||||||
|
v.setAnimateDir(data.dir);
|
||||||
|
v.layer.moving.delete(renderable);
|
||||||
|
v.layer.requestUpdateMoving();
|
||||||
|
res();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HeroMoveCollection {
|
interface HeroMoveCollection {
|
||||||
|
@ -5,9 +5,7 @@ import type {
|
|||||||
LayerFloorBinder
|
LayerFloorBinder
|
||||||
} from '@/core/render/preset/floor';
|
} from '@/core/render/preset/floor';
|
||||||
import type { HeroRenderer } from '@/core/render/preset/hero';
|
import type { HeroRenderer } from '@/core/render/preset/hero';
|
||||||
import type { Layer, LayerMovingRenderable } from '@/core/render/preset/layer';
|
import type { Layer } from '@/core/render/preset/layer';
|
||||||
import { BluePalace } from '@/game/mechanism/misc';
|
|
||||||
import { backDir } from './utils';
|
|
||||||
import type { TimingFn } from 'mutate-animate';
|
import type { TimingFn } from 'mutate-animate';
|
||||||
import { BlockMover, heroMoveCollection, MoveStep } from '@/game/state/move';
|
import { BlockMover, heroMoveCollection, MoveStep } from '@/game/state/move';
|
||||||
import type { FloorViewport } from '@/core/render/preset/viewport';
|
import type { FloorViewport } from '@/core/render/preset/viewport';
|
||||||
@ -44,159 +42,8 @@ export function init() {
|
|||||||
adapters['viewport'] = viewport;
|
adapters['viewport'] = viewport;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 传送门信息,下一步传送到哪 */
|
|
||||||
let portalData: BluePalace.PortalTo | undefined;
|
|
||||||
/** 下一步是否步入传送门 */
|
|
||||||
let portal: boolean = false;
|
|
||||||
|
|
||||||
const { mover: heroMover } = heroMoveCollection;
|
const { mover: heroMover } = heroMoveCollection;
|
||||||
|
|
||||||
function onMoveEnd(
|
|
||||||
noPass: boolean,
|
|
||||||
noRoute: boolean = false,
|
|
||||||
callback?: () => void
|
|
||||||
) {
|
|
||||||
// if (portal && portalData) {
|
|
||||||
// const before = moveDir;
|
|
||||||
// const { x, y, dir } = portalData;
|
|
||||||
// core.setHeroLoc('x', x);
|
|
||||||
// core.setHeroLoc('y', y);
|
|
||||||
// core.setHeroLoc('direction', dir);
|
|
||||||
// portal = false;
|
|
||||||
// moveDir = before;
|
|
||||||
// }
|
|
||||||
|
|
||||||
var direction = core.getHeroLoc('direction');
|
|
||||||
core.control._moveAction_popAutomaticRoute();
|
|
||||||
if (!noRoute) core.status.route.push(direction);
|
|
||||||
|
|
||||||
core.moveOneStep();
|
|
||||||
core.checkRouteFolding();
|
|
||||||
callback?.();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----- 移动 - 传送门
|
|
||||||
function checkPortal() {
|
|
||||||
const map = BluePalace.portalMap.get(core.status.floorId);
|
|
||||||
if (!map) {
|
|
||||||
portal = false;
|
|
||||||
portalData = void 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const width = core.status.thisMap.width;
|
|
||||||
const { x, y, direction } = core.status.hero.loc;
|
|
||||||
const index = x + y * width;
|
|
||||||
const data = map?.get(index);
|
|
||||||
if (!data) {
|
|
||||||
portal = false;
|
|
||||||
portalData = void 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const to = data[direction];
|
|
||||||
if (to) {
|
|
||||||
portal = true;
|
|
||||||
portalData = to;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const end: Record<Dir, [number, number]> = {
|
|
||||||
left: [-1, 0],
|
|
||||||
right: [1, 0],
|
|
||||||
down: [0, 1],
|
|
||||||
up: [0, -1]
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对勇士进行切割渲染,分成两个renderable进行渲染
|
|
||||||
*/
|
|
||||||
function renderHeroSwap() {
|
|
||||||
if (!portal || !portalData) return;
|
|
||||||
const list = adapters['hero-adapter']?.items;
|
|
||||||
if (!list) return;
|
|
||||||
const { x: tx, y: ty, dir: toDir } = portalData;
|
|
||||||
const { x, y, direction } = core.status.hero.loc;
|
|
||||||
const [dx, dy] = end[direction];
|
|
||||||
const [tdx] = end[toDir];
|
|
||||||
const checkX = x + dx;
|
|
||||||
const checkY = y + dy;
|
|
||||||
|
|
||||||
list.forEach(v => {
|
|
||||||
if (!v.renderable) return;
|
|
||||||
const renderable = { ...v.renderable };
|
|
||||||
renderable.render = v.getRenderFromDir(toDir);
|
|
||||||
renderable.zIndex = ty;
|
|
||||||
const heroDir = v.moveDir;
|
|
||||||
|
|
||||||
const width = v.renderable.render[0][2];
|
|
||||||
const height = v.renderable.render[0][3];
|
|
||||||
const cell = v.layer.cellSize;
|
|
||||||
const restHeight = height - cell;
|
|
||||||
if (!width || !height) return;
|
|
||||||
|
|
||||||
const originFrom = structuredClone(v.renderable.render);
|
|
||||||
const originTo = structuredClone(renderable.render);
|
|
||||||
v.layer.moving.add(renderable);
|
|
||||||
v.layer.requestUpdateMoving();
|
|
||||||
v.on('moveTick', function func() {
|
|
||||||
const progress =
|
|
||||||
heroDir === 'left' || heroDir === 'right'
|
|
||||||
? 1 - Math.abs(checkX - v.renderable!.x)
|
|
||||||
: 1 - Math.abs(checkY - v.renderable!.y);
|
|
||||||
if (progress >= 1 || !portal) {
|
|
||||||
v.renderable!.render = originFrom;
|
|
||||||
v.off('moveTick', func);
|
|
||||||
v.layer.moving.delete(renderable);
|
|
||||||
v.layer.requestUpdateMoving();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const clipWidth = cell * progress;
|
|
||||||
const clipHeight = cell * progress;
|
|
||||||
const beforeWidth = width - clipWidth;
|
|
||||||
const beforeHeight = height - clipHeight;
|
|
||||||
|
|
||||||
v.renderable!.x = x;
|
|
||||||
v.renderable!.y = y;
|
|
||||||
if (heroDir === 'left' || heroDir === 'right') {
|
|
||||||
v.renderable!.x = x + (clipWidth / 2 / cell) * dx;
|
|
||||||
v.renderable!.render.forEach((v, i) => {
|
|
||||||
v[2] = beforeWidth;
|
|
||||||
if (heroDir === 'left') {
|
|
||||||
v[0] = originFrom[i][0] + clipWidth;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
v.renderable!.render.forEach((v, i) => {
|
|
||||||
v[3] = beforeHeight;
|
|
||||||
if (heroDir === 'up') {
|
|
||||||
v[1] = originFrom[i][1] + clipHeight + restHeight;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
renderable.x = tx;
|
|
||||||
renderable.y = ty;
|
|
||||||
if (toDir === 'left' || toDir === 'right') {
|
|
||||||
renderable.x = tx + (clipWidth / 2 / cell - 0.5) * tdx;
|
|
||||||
renderable.render.forEach((v, i) => {
|
|
||||||
v[2] = clipWidth;
|
|
||||||
if (toDir === 'right') {
|
|
||||||
v[0] = originTo[i][0] + beforeWidth;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (toDir === 'down') renderable.y = ty - 1 + progress;
|
|
||||||
renderable.render.forEach((v, i) => {
|
|
||||||
v[3] = clipHeight + restHeight;
|
|
||||||
if (toDir === 'down') {
|
|
||||||
v[1] = originTo[i][1] + clipHeight + restHeight;
|
|
||||||
v[3] = clipHeight;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----- 工具函数
|
// ----- 工具函数
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -218,40 +65,6 @@ export function init() {
|
|||||||
return moveSteps;
|
return moveSteps;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 移动一个LayerMovingRenderable
|
|
||||||
*/
|
|
||||||
function moveRenderable(
|
|
||||||
item: Layer,
|
|
||||||
data: LayerMovingRenderable,
|
|
||||||
time: number,
|
|
||||||
x: number,
|
|
||||||
y: number
|
|
||||||
) {
|
|
||||||
const fx = data.x;
|
|
||||||
const fy = data.y;
|
|
||||||
const dx = x - fx;
|
|
||||||
const dy = y - fy;
|
|
||||||
const start = Date.now();
|
|
||||||
return new Promise<void>(res => {
|
|
||||||
item.delegateTicker(
|
|
||||||
() => {
|
|
||||||
const now = Date.now() - start;
|
|
||||||
const progress = now / time;
|
|
||||||
data.x = fx + dx * progress;
|
|
||||||
data.y = fy + dy * progress;
|
|
||||||
item.update(item);
|
|
||||||
},
|
|
||||||
time,
|
|
||||||
() => {
|
|
||||||
data.x = x;
|
|
||||||
data.y = y;
|
|
||||||
res();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成跳跃函数
|
* 生成跳跃函数
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user