mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-03-01 01:57:05 +08:00
feat: 勇士进入传送门效果
This commit is contained in:
parent
292e17ed53
commit
0568542cec
@ -13,6 +13,7 @@ type HeroMovingStatus = 'stop' | 'moving' | 'moving-as';
|
|||||||
interface HeroRenderEvent {
|
interface HeroRenderEvent {
|
||||||
stepEnd: [];
|
stepEnd: [];
|
||||||
moveTick: [x: number, y: number];
|
moveTick: [x: number, y: number];
|
||||||
|
append: [renderable: LayerMovingRenderable[]];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HeroRenderer
|
export class HeroRenderer
|
||||||
@ -40,6 +41,7 @@ export class HeroRenderer
|
|||||||
/** 勇士移动速度 */
|
/** 勇士移动速度 */
|
||||||
speed: number = 100;
|
speed: number = 100;
|
||||||
/** 当前勇士朝向 */
|
/** 当前勇士朝向 */
|
||||||
|
// todo: 删了这个属性
|
||||||
dir: Dir = 'down';
|
dir: Dir = 'down';
|
||||||
|
|
||||||
/** 勇士移动定时器id */
|
/** 勇士移动定时器id */
|
||||||
@ -47,7 +49,7 @@ export class HeroRenderer
|
|||||||
/** 上一次帧数切换的时间 */
|
/** 上一次帧数切换的时间 */
|
||||||
private lastFrameTime: number = 0;
|
private lastFrameTime: number = 0;
|
||||||
/** 当前的移动方向 */
|
/** 当前的移动方向 */
|
||||||
private moveDir: Move2 = 'down';
|
moveDir: Move2 = 'down';
|
||||||
/** 上一步走到格子上的时间 */
|
/** 上一步走到格子上的时间 */
|
||||||
private lastStepTime: number = 0;
|
private lastStepTime: number = 0;
|
||||||
/** 执行当前步移动的Promise */
|
/** 执行当前步移动的Promise */
|
||||||
@ -58,7 +60,7 @@ export class HeroRenderer
|
|||||||
* 这一步的移动方向,与{@link moveDir}不同的是,在这一步走完之前,它都不会变,
|
* 这一步的移动方向,与{@link moveDir}不同的是,在这一步走完之前,它都不会变,
|
||||||
* 当这一步走完之后,才会将其设置为{@link moveDir}的值
|
* 当这一步走完之后,才会将其设置为{@link moveDir}的值
|
||||||
*/
|
*/
|
||||||
private stepDir: Dir2 = 'down';
|
stepDir: Dir2 = 'down';
|
||||||
/** 每步的格子增量 */
|
/** 每步的格子增量 */
|
||||||
private stepDelta: Loc = { x: 0, y: 1 };
|
private stepDelta: Loc = { x: 0, y: 1 };
|
||||||
/** 动画显示的方向,用于适配后退 */
|
/** 动画显示的方向,用于适配后退 */
|
||||||
@ -354,7 +356,10 @@ export class HeroRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMovingUpdate(layer: Layer, renderable: LayerMovingRenderable[]): void {
|
onMovingUpdate(layer: Layer, renderable: LayerMovingRenderable[]): void {
|
||||||
if (this.renderable) renderable.push(this.renderable);
|
if (this.renderable) {
|
||||||
|
renderable.push(this.renderable);
|
||||||
|
this.emit('append', renderable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { has } from '@/plugin/game/utils';
|
import { backDir, has } from '@/plugin/game/utils';
|
||||||
import { loading } from '../game';
|
import { loading } from '../game';
|
||||||
|
|
||||||
export namespace BluePalace {
|
export namespace BluePalace {
|
||||||
@ -90,6 +90,16 @@ export namespace BluePalace {
|
|||||||
toDir: Dir;
|
toDir: Dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PortalTo {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
dir: Dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
type PortalMap = Map<FloorIds, Map<number, Partial<Record<Dir, PortalTo>>>>;
|
||||||
|
|
||||||
|
export const portalMap: PortalMap = new Map();
|
||||||
|
|
||||||
export const portals: Partial<Record<FloorIds, Portal[]>> = {
|
export const portals: Partial<Record<FloorIds, Portal[]>> = {
|
||||||
MT75: [
|
MT75: [
|
||||||
{ fx: 7, fy: 7, dir: 'left', tx: 9, ty: 9, toDir: 'down' },
|
{ fx: 7, fy: 7, dir: 'left', tx: 9, ty: 9, toDir: 'down' },
|
||||||
@ -101,7 +111,103 @@ export namespace BluePalace {
|
|||||||
};
|
};
|
||||||
loading.once('coreInit', initPortals);
|
loading.once('coreInit', initPortals);
|
||||||
|
|
||||||
|
function generatePortalMap() {
|
||||||
|
const delta: Record<Dir, [[number, number], [number, number]]> = {
|
||||||
|
// 方向:[正向, 逆向]<进出>
|
||||||
|
left: [
|
||||||
|
[0, 0],
|
||||||
|
[-1, 0]
|
||||||
|
],
|
||||||
|
down: [
|
||||||
|
[0, 0],
|
||||||
|
[0, -1]
|
||||||
|
],
|
||||||
|
right: [
|
||||||
|
[0, 0],
|
||||||
|
[1, 0]
|
||||||
|
],
|
||||||
|
up: [
|
||||||
|
[0, 0],
|
||||||
|
[0, 1]
|
||||||
|
]
|
||||||
|
};
|
||||||
|
for (const [floor, p] of Object.entries(portals)) {
|
||||||
|
const width = core.floors[floor as FloorIds].width;
|
||||||
|
const map = new Map<number, Partial<Record<Dir, PortalTo>>>();
|
||||||
|
portalMap.set(floor as FloorIds, map);
|
||||||
|
|
||||||
|
// 正向映射
|
||||||
|
p.forEach(v => {
|
||||||
|
const [[fdx, fdy], [tdx, tdy]] = delta[v.dir];
|
||||||
|
const [[toFdx, toFdy], [toTdx, toTdy]] =
|
||||||
|
delta[backDir(v.toDir)];
|
||||||
|
const fx = v.fx + fdx;
|
||||||
|
const fy = v.fy + fdy;
|
||||||
|
const tx = v.fx + tdx;
|
||||||
|
const ty = v.fy + tdy;
|
||||||
|
const index = fx + fy * width;
|
||||||
|
const backIndex = tx + ty * width;
|
||||||
|
let data = map.get(index);
|
||||||
|
let backData = map.get(backIndex);
|
||||||
|
if (!data) {
|
||||||
|
data = {};
|
||||||
|
map.set(index, data);
|
||||||
|
}
|
||||||
|
if (!backData) {
|
||||||
|
backData = {};
|
||||||
|
map.set(backIndex, backData);
|
||||||
|
}
|
||||||
|
|
||||||
|
data[v.dir] = {
|
||||||
|
x: v.tx + toFdx,
|
||||||
|
y: v.ty + toFdy,
|
||||||
|
dir: backDir(v.toDir)
|
||||||
|
};
|
||||||
|
backData[backDir(v.dir)] = {
|
||||||
|
x: v.tx + toTdx,
|
||||||
|
y: v.ty + toTdy,
|
||||||
|
dir: v.toDir
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// 逆向映射
|
||||||
|
p.forEach(v => {
|
||||||
|
const [[fdx, fdy], [tdx, tdy]] = delta[backDir(v.toDir)];
|
||||||
|
const [[toFdx, toFdy], [toTdx, toTdy]] = delta[v.dir];
|
||||||
|
const fx = v.tx + fdx;
|
||||||
|
const fy = v.ty + fdy;
|
||||||
|
const tx = v.tx + tdx;
|
||||||
|
const ty = v.ty + tdy;
|
||||||
|
const index = fx + fy * width;
|
||||||
|
const backIndex = tx + ty * width;
|
||||||
|
|
||||||
|
let data = map.get(index);
|
||||||
|
let backData = map.get(backIndex);
|
||||||
|
if (!data) {
|
||||||
|
data = {};
|
||||||
|
map.set(index, data);
|
||||||
|
}
|
||||||
|
if (!backData) {
|
||||||
|
backData = {};
|
||||||
|
map.set(backIndex, backData);
|
||||||
|
}
|
||||||
|
|
||||||
|
data[v.toDir] = {
|
||||||
|
x: v.fx + toFdx,
|
||||||
|
y: v.fy + toFdy,
|
||||||
|
dir: backDir(v.dir)
|
||||||
|
};
|
||||||
|
backData[backDir(v.toDir)] = {
|
||||||
|
x: v.fx + toTdx,
|
||||||
|
y: v.fy + toTdy,
|
||||||
|
dir: v.dir
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function initPortals() {
|
function initPortals() {
|
||||||
// 主要是复写勇士绘制以及传送判定,还有自动寻路
|
// 主要是复写勇士绘制以及传送判定,还有自动寻路
|
||||||
|
generatePortalMap();
|
||||||
|
console.log(portalMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ import type { RenderAdapter } from '@/core/render/adapter';
|
|||||||
import type { LayerGroupAnimate } from '@/core/render/preset/animate';
|
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 type { LayerMovingRenderable } from '@/core/render/preset/layer';
|
||||||
|
import { BluePalace } from '@/game/mechanism/misc';
|
||||||
|
|
||||||
interface Adapters {
|
interface Adapters {
|
||||||
'hero-adapter'?: RenderAdapter<HeroRenderer>;
|
'hero-adapter'?: RenderAdapter<HeroRenderer>;
|
||||||
@ -33,6 +35,11 @@ export function init() {
|
|||||||
let stepDir: Dir;
|
let stepDir: Dir;
|
||||||
let moveEnding: Promise<any[]>;
|
let moveEnding: Promise<any[]>;
|
||||||
|
|
||||||
|
/** 传送门信息,下一步传送到哪 */
|
||||||
|
let portalData: BluePalace.PortalTo | undefined;
|
||||||
|
/** 下一步是否步入传送门 */
|
||||||
|
let portal: boolean = false;
|
||||||
|
|
||||||
const pressedArrow: Set<Dir> = new Set();
|
const pressedArrow: Set<Dir> = new Set();
|
||||||
Mota.r(() => {
|
Mota.r(() => {
|
||||||
const gameKey = Mota.require('var', 'gameKey');
|
const gameKey = Mota.require('var', 'gameKey');
|
||||||
@ -141,7 +148,7 @@ export function init() {
|
|||||||
if (stopChian || core.status.lockControl) break;
|
if (stopChian || core.status.lockControl) break;
|
||||||
stepDir = moveDir;
|
stepDir = moveDir;
|
||||||
if (!checkCanMoveStatus(callback)) break;
|
if (!checkCanMoveStatus(callback)) break;
|
||||||
|
if (portal) renderHeroSwap();
|
||||||
await adapter.all('move', moveDir);
|
await adapter.all('move', moveDir);
|
||||||
onMoveEnd(false, callback);
|
onMoveEnd(false, callback);
|
||||||
}
|
}
|
||||||
@ -153,8 +160,9 @@ export function init() {
|
|||||||
function checkCanMoveStatus(callback?: () => void) {
|
function checkCanMoveStatus(callback?: () => void) {
|
||||||
core.setHeroLoc('direction', stepDir);
|
core.setHeroLoc('direction', stepDir);
|
||||||
const { noPass, canMove } = checkCanMove();
|
const { noPass, canMove } = checkCanMove();
|
||||||
|
checkPortal();
|
||||||
|
|
||||||
if (noPass || !canMove) {
|
if (!portal && (noPass || !canMove)) {
|
||||||
onCannotMove(canMove, callback);
|
onCannotMove(canMove, callback);
|
||||||
if (moving) endMove();
|
if (moving) endMove();
|
||||||
return false;
|
return false;
|
||||||
@ -199,7 +207,13 @@ export function init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onMoveEnd(noPass: boolean, callback?: () => void) {
|
function onMoveEnd(noPass: boolean, callback?: () => void) {
|
||||||
if (!noPass) {
|
if (portal && portalData) {
|
||||||
|
const { x, y, dir } = portalData;
|
||||||
|
core.setHeroLoc('x', x);
|
||||||
|
core.setHeroLoc('y', y);
|
||||||
|
core.setHeroLoc('direction', dir);
|
||||||
|
portal = false;
|
||||||
|
} else if (!noPass) {
|
||||||
const { nx, ny } = getNextLoc();
|
const { nx, ny } = getNextLoc();
|
||||||
core.setHeroLoc('x', nx, true);
|
core.setHeroLoc('x', nx, true);
|
||||||
core.setHeroLoc('y', ny, true);
|
core.setHeroLoc('y', ny, true);
|
||||||
@ -214,6 +228,130 @@ export function init() {
|
|||||||
callback?.();
|
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.updateMovingRenderable();
|
||||||
|
const append = (r: LayerMovingRenderable[]) => {
|
||||||
|
r.push(renderable);
|
||||||
|
};
|
||||||
|
v.on('append', append);
|
||||||
|
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.off('append', append);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// ----- 勇士移动相关
|
// ----- 勇士移动相关
|
||||||
|
|
||||||
Mota.r(() => {
|
Mota.r(() => {
|
||||||
|
@ -28,6 +28,8 @@ const backDirMap: Record<Dir2, Dir2> = {
|
|||||||
rightdown: 'leftup'
|
rightdown: 'leftup'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function backDir(dir: Dir): Dir;
|
||||||
|
export function backDir(dir: Dir2): Dir2;
|
||||||
export function backDir(dir: Dir2): Dir2 {
|
export function backDir(dir: Dir2): Dir2 {
|
||||||
return backDirMap[dir];
|
return backDirMap[dir];
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user