fix: 跳跃勇士、图块

This commit is contained in:
unanmed 2024-08-28 21:43:49 +08:00
parent 288c76c194
commit 12c009dab6
5 changed files with 351 additions and 31 deletions

View File

@ -70,6 +70,7 @@ import { RenderItem } from './render/item';
import { texture } from './render/cache';
import { RenderAdapter } from './render/adapter';
import { getMainRenderer } from './render';
import { Layer } from './render/preset/layer';
// ----- 类注册
Mota.register('class', 'AudioPlayer', AudioPlayer);
@ -156,7 +157,8 @@ Mota.register('module', 'Render', {
Text,
Image,
RenderItem,
RenderAdapter
RenderAdapter,
Layer
});
main.renderLoaded = true;

View File

@ -9,6 +9,7 @@ import { glMatrix } from 'gl-matrix';
import { BlockCacher } from './block';
import { Transform } from '../transform';
import { LayerFloorBinder, LayerGroupFloorBinder } from './floor';
import { RenderAdapter } from '../adapter';
export interface ILayerGroupRenderExtends {
/** 拓展的唯一标识符 */
@ -657,7 +658,7 @@ export class Layer extends Container {
private extend: Map<string, ILayerRenderExtends> = new Map();
/** 正在移动的图块的渲染信息 */
private moving: Set<LayerMovingRenderable> = new Set();
moving: Set<LayerMovingRenderable> = new Set();
constructor() {
super('absolute', false);
@ -694,6 +695,7 @@ export class Layer extends Container {
});
this.extends(new LayerFloorBinder());
layerAdapter.add(this);
}
/**
@ -1333,7 +1335,8 @@ export class Layer extends Container {
/**
*
* @param index
* @param type
* @param x
* @param y
* @param fn 0-1
*
*
@ -1352,24 +1355,9 @@ export class Layer extends Container {
const block = this.renderData[index];
const fx = index % this.width;
const fy = Math.floor(index / this.width);
const renderable = texture.getRenderable(block);
if (!renderable) return Promise.reject();
const moving = Layer.getMovingRenderable(block, fx, fy);
if (!moving) return Promise.reject();
const image = renderable.autotile
? renderable.image[0]
: renderable.image;
const moving: LayerMovingRenderable = {
x: fx,
y: fy,
zIndex: fy,
image: image,
autotile: false,
frame: renderable.frame,
bigImage: renderable.bigImage,
animate: -1,
render: renderable.render
};
this.moving.add(moving);
// 删除原始位置的图块
@ -1405,10 +1393,84 @@ export class Layer extends Container {
});
}
/**
* renderable
* @param data renderable
* @param x `moveAs``x`
* @param y `moveAs``y`
* @param fn
* @param time
* @param relative
*/
moveRenderable(
data: LayerMovingRenderable,
x: number,
y: number,
fn: TimingFn<3>,
time: number,
relative: boolean = true
) {
let nowZ = y;
const startTime = Date.now();
return new Promise<void>(resolve => {
this.delegateTicker(
() => {
const now = Date.now();
const progress = (now - startTime) / time;
const [nx, ny, nz] = fn(progress);
const tx = relative ? nx + x : nx;
const ty = relative ? ny + y : ny;
data.x = tx;
data.y = ty;
data.zIndex = nz;
if (nz !== nowZ) {
this.movingRenderable.sort(
(a, b) => a.zIndex - b.zIndex
);
}
this.update(this);
},
time,
() => {
resolve();
}
);
});
}
destroy(): void {
for (const ex of this.extend.values()) {
ex.onDestroy?.(this);
}
super.destroy();
layerAdapter.remove(this);
}
/**
*
* @param num
* @param x
* @param y
*/
static getMovingRenderable(num: number, x: number, y: number) {
const renderable = texture.getRenderable(num);
if (!renderable) return null;
const image = renderable.autotile
? renderable.image[0]
: renderable.image;
const moving: LayerMovingRenderable = {
x: x,
y: y,
zIndex: y,
image: image,
autotile: false,
frame: renderable.frame,
bigImage: renderable.bigImage,
animate: -1,
render: renderable.render
};
return moving;
}
}
const layerAdapter = new RenderAdapter<Layer>('layer');

View File

@ -197,8 +197,6 @@ export namespace BluePalace {
}
function initPortals() {
// 主要是复写勇士绘制以及传送判定,还有自动寻路
generatePortalMap();
console.log(portalMap);
}
}

View File

@ -35,6 +35,7 @@ import type { Image, Text } from '@/core/render/preset/misc';
import type { RenderItem } from '@/core/render/item';
import type { RenderAdapter } from '@/core/render/adapter';
import type { ItemState } from './state/item';
import type { Layer } from '@/core/render/preset/layer';
interface ClassInterface {
// 渲染进程与游戏进程通用
@ -114,6 +115,7 @@ interface ModuleInterface {
Image: typeof Image;
RenderItem: typeof RenderItem;
RenderAdapter: typeof RenderAdapter;
Layer: typeof Layer;
};
State: {
ItemState: typeof ItemState;

View File

@ -1,14 +1,20 @@
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,
LayerFloorBinder
} from '@/core/render/preset/floor';
import type { HeroRenderer } from '@/core/render/preset/hero';
import type { LayerMovingRenderable } from '@/core/render/preset/layer';
import type { Layer, LayerMovingRenderable } from '@/core/render/preset/layer';
import { BluePalace } from '@/game/mechanism/misc';
import { backDir } from './utils';
import type { TimingFn } from 'mutate-animate';
interface Adapters {
'hero-adapter'?: RenderAdapter<HeroRenderer>;
'door-animate'?: RenderAdapter<LayerDoorAnimate>;
animate?: RenderAdapter<LayerGroupAnimate>;
layer?: RenderAdapter<Layer>;
}
const adapters: Adapters = {};
@ -23,17 +29,19 @@ export function init() {
const hero = Adapter.get<HeroRenderer>('hero-adapter');
const doorAnimate = Adapter.get<LayerDoorAnimate>('door-animate');
const animate = Adapter.get<LayerGroupAnimate>('animate');
const layer = Adapter.get<Layer>('layer');
adapters['hero-adapter'] = hero;
adapters['door-animate'] = doorAnimate;
adapters['animate'] = animate;
adapters['layer'] = layer;
}
let moving: boolean = false;
let stopChian: boolean = false;
let moveDir: Dir;
let stepDir: Dir;
let moveEnding: Promise<any[]>;
let moveEnding: Promise<any[]> = Promise.resolve([]);
/** 传送门信息,下一步传送到哪 */
let portalData: BluePalace.PortalTo | undefined;
@ -288,11 +296,8 @@ export function init() {
const originFrom = structuredClone(v.renderable.render);
const originTo = structuredClone(renderable.render);
v.layer.moving.add(renderable);
v.layer.requestUpdateMoving();
const append = (r: LayerMovingRenderable[]) => {
r.push(renderable);
};
v.on('append', append);
v.on('moveTick', function func() {
const progress =
heroDir === 'left' || heroDir === 'right'
@ -301,7 +306,7 @@ export function init() {
if (progress >= 1 || !portal) {
v.renderable!.render = originFrom;
v.off('moveTick', func);
v.off('append', append);
v.layer.moving.delete(renderable);
v.layer.requestUpdateMoving();
return;
}
@ -353,9 +358,79 @@ export function init() {
});
}
// ----- 勇士移动相关
// ----- 工具函数
/**
*
*/
function getMoveSteps(steps: string[]) {
const moveSteps: string[] = [];
steps.forEach(v => {
const [type, number] = v.split(':');
if (!number) moveSteps.push(type);
else {
if (type === 'speed') moveSteps.push(v);
else {
moveSteps.push(...Array(number).fill(type));
}
}
});
const step0 = steps.find(v => !v.startsWith('speed')) as Dir2;
return { steps, start: step0 };
}
/**
* 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();
}
);
});
}
/**
*
*/
function generateJumpFn(dx: number, dy: number): TimingFn<3> {
const distance = Math.hypot(dx, dy);
const peak = 3 + distance;
const k = dy / dx;
return (progress: number) => {
const x = dx * progress;
const y = k * x + (progress ** 2 - progress) * peak;
return [x, y, Math.ceil(y)];
};
}
Mota.r(() => {
// ----- 勇士移动相关
control.prototype._moveAction_moving = function (
callback?: () => void
) {};
@ -588,6 +663,157 @@ export function init() {
callback?.();
});
};
// 移动跳跃图块 & 跳跃勇士
maps.prototype.moveBlock = async function (
x: number,
y: number,
steps: string[],
time: number = 500,
keep: boolean = false,
callback?: () => void
) {
if (!steps || steps.length === 0) {
callback?.();
return;
}
const speed = core.status.replay.speed;
if (speed === 24) time = 1;
const block = core.getBlock(x, y);
if (!block) {
callback?.();
return;
}
core.removeBlock(x, y);
const list = adapters.layer?.items ?? [];
const items = [...list].filter(v => {
if (v.layer !== 'event') return false;
const ex = v.getExtends('floor-binder') as LayerFloorBinder;
if (!ex) return false;
return ex.getFloor() === core.status.floorId;
});
const { steps: moveSteps, start } = getMoveSteps(steps);
if (!start || items.length === 0) {
callback?.();
return;
}
let stepDir: Dir2 = start;
let nx = x;
let ny = y;
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);
if (step.startsWith('speed')) {
time = parseInt(step.slice(6));
continue;
}
const { x, y } = core.utils.scan2[stepDir];
const tx = nx + x;
const ty = ny + y;
await moveRenderable(items[0], moving, time / speed, tx, ty);
nx = tx;
ny = ty;
moving.zIndex = ty;
}
items.forEach(v => v.moving.delete(moving));
if (keep) {
core.setBlock(block.id, nx, ny);
}
callback?.();
};
////// 显示跳跃某块的动画,达到{"type":"jump"}的效果 //////
maps.prototype.jumpBlock = async function (
sx: number,
sy: number,
ex: number,
ey: number,
time: number = 500,
keep: boolean = false,
callback?: () => void
) {
const block = core.getBlock(sx, sy);
if (!block) {
callback?.();
return;
}
time /= core.status.replay.speed;
if (core.status.replay.speed === 24) time = 1;
const dx = ex - sx;
const dy = ey - sy;
const fn = generateJumpFn(dx, dy);
const list = adapters.layer?.items ?? [];
const items = [...list].filter(v => {
if (v.layer !== 'event') return false;
const ex = v.getExtends('floor-binder') as LayerFloorBinder;
if (!ex) return false;
return ex.getFloor() === core.status.floorId;
});
const width = core.status.thisMap.width;
const index = sx + sy * width;
const promise = Promise.all(
items.map(v => {
return v.moveAs(index, ex, ey, fn, time);
})
);
core.removeBlock(sx, sy);
await promise;
if (keep) {
core.setBlock(block.id, ex, ey);
}
callback?.();
};
events.prototype.jumpHero = async function (
ex: number,
ey: number,
time: number = 500,
callback?: () => void
) {
const sx = core.getHeroLoc('x');
const sy = core.getHeroLoc('y');
const locked = core.status.lockControl;
core.lockControl();
const list = adapters['hero-adapter']?.items ?? [];
const items = [...list];
time /= core.status.replay.speed;
if (core.status.replay.speed === 24) time = 1;
const fn = generateJumpFn(ex - sx, ey - sy);
await Promise.all(
items.map(v => {
if (!v.renderable) return Promise.reject();
return v.layer.moveRenderable(
v.renderable,
sx,
sy,
fn,
time
);
})
);
if (!locked) core.unlockControl();
core.setHeroLoc('x', ex);
core.setHeroLoc('y', ey);
callback?.();
};
});
loading.once('loaded', () => {
@ -600,5 +826,35 @@ export function init() {
}
});
// 复写录像的移动
core.registerReplayAction('move', action => {
if (
action === 'up' ||
action === 'down' ||
action === 'left' ||
action === 'right'
) {
stepDir = action;
const { noPass, canMove } = checkCanMove();
const { nx, ny } = getNextLoc();
if (noPass || !canMove) {
if (canMove) core.trigger(nx, ny);
} else {
core.setHeroLoc('x', nx);
core.setHeroLoc('y', ny);
core.setHeroLoc('direction', action);
}
if (!main.replayChecking) {
setTimeout(core.replay, 100);
} else {
core.replay();
}
return true;
} else {
return false;
}
});
return { readyMove, endMove, move };
}