Compare commits

..

1 Commits

Author SHA1 Message Date
AncTe
6ba46bbe94
Merge 7a019f02f4 into 820dc5bf4c 2025-11-23 05:01:56 +00:00
7 changed files with 102 additions and 257 deletions

View File

@ -46,7 +46,6 @@ export function createRender() {
Font.setDefaults(DEFAULT_FONT); Font.setDefaults(DEFAULT_FONT);
} }
export * from './commonIns';
export * from './components'; export * from './components';
export * from './elements'; export * from './elements';
export * from './fx'; export * from './fx';

View File

@ -6,7 +6,6 @@ import {
IHeroState, IHeroState,
IHeroStateHooks, IHeroStateHooks,
IMapLayer, IMapLayer,
nextFaceDirection,
state state
} from '@user/data-state'; } from '@user/data-state';
import { IMapRenderer, IMapRendererTicker, IMovingBlock } from '../types'; import { IMapRenderer, IMapRendererTicker, IMovingBlock } from '../types';
@ -60,14 +59,14 @@ export class MapHeroRenderer implements IMapHeroRenderer {
/** 勇士钩子 */ /** 勇士钩子 */
readonly controller: IHookController<IHeroStateHooks>; readonly controller: IHookController<IHeroStateHooks>;
/** 勇士每个朝向的贴图对象 */ /** 每个朝向的贴图对象 */
readonly textureMap: Map<FaceDirection, IMaterialFramedData> = new Map(); readonly textureMap: Map<FaceDirection, IMaterialFramedData> = new Map();
/** 勇士渲染实体,与 `entities[0]` 同引用 */ /** 勇士渲染实体,与 `entities[0]` 同引用 */
readonly heroEntity: HeroRenderEntity; readonly heroEntity: HeroRenderEntity;
/** /**
* 0 * 0
* *
*/ */
readonly entities: HeroRenderEntity[] = []; readonly entities: HeroRenderEntity[] = [];
@ -195,10 +194,7 @@ export class MapHeroRenderer implements IMapHeroRenderer {
} }
setPosition(x: number, y: number): void { setPosition(x: number, y: number): void {
this.entities.forEach(v => { this.heroEntity.block.setPos(x, y);
v.block.setPos(x, y);
v.nextDirection = FaceDirection.Unknown;
});
} }
/** /**
@ -224,12 +220,12 @@ export class MapHeroRenderer implements IMapHeroRenderer {
entity.promise = entity.promise.then(async () => { entity.promise = entity.promise.then(async () => {
entity.moving = true; entity.moving = true;
entity.animating = true; entity.animating = true;
entity.nextDirection = entity.direction;
entity.direction = direction; entity.direction = direction;
if (nextTex) block.setTexture(nextTex); if (nextTex) block.setTexture(nextTex);
await block.lineTo(tx, ty, time); await block.lineTo(tx, ty, time);
entity.moving = false; entity.moving = false;
entity.animating = false; entity.animating = false;
entity.nextDirection = entity.direction;
}); });
} }
@ -410,8 +406,8 @@ export class MapHeroRenderer implements IMapHeroRenderer {
); );
if (!tile) continue; if (!tile) continue;
moving.block.setTexture(tile); moving.block.setTexture(tile);
moving.direction = last.nextDirection;
moving.nextDirection = moving.direction; moving.nextDirection = moving.direction;
moving.direction = last.nextDirection;
} }
this.entities.splice(index, 1); this.entities.splice(index, 1);
} }
@ -430,17 +426,6 @@ export class MapHeroRenderer implements IMapHeroRenderer {
this.heroEntity.animateDirection = direction; this.heroEntity.animateDirection = direction;
} }
turn(direction?: FaceDirection): void {
const next = isNil(direction)
? nextFaceDirection(this.heroEntity.direction)
: direction;
const tex = this.textureMap.get(next);
if (tex) {
this.heroEntity.block.setTexture(tex);
this.heroEntity.direction = next;
}
}
destroy() { destroy() {
this.controller.unload(); this.controller.unload();
} }
@ -462,10 +447,6 @@ class MapHeroHook implements Partial<IHeroStateHooks> {
this.hero.setPosition(x, y); this.hero.setPosition(x, y);
} }
onTurnHero(direction: FaceDirection): void {
this.hero.turn(direction);
}
onStartMove(): void { onStartMove(): void {
this.hero.startMove(); this.hero.startMove();
} }

View File

@ -88,12 +88,6 @@ export interface IMapHeroRenderer {
*/ */
setHeroAnimateDirection(direction: HeroAnimateDirection): void; setHeroAnimateDirection(direction: HeroAnimateDirection): void;
/**
*
* @param direction
*/
turn(direction?: FaceDirection): void;
/** /**
* *
*/ */

View File

@ -50,133 +50,3 @@ export function degradeFace(
} }
return dir; return dir;
} }
/**
*
* @param dir
* @param anticlockwise
* @param face8 使 `false` ->->->->->->
* `true` ->->->->->->->
*/
export function nextFaceDirection(
dir: FaceDirection,
anticlockwise: boolean = false,
face8: boolean = false
): FaceDirection {
if (face8) {
if (anticlockwise) {
switch (dir) {
case FaceDirection.Left:
return FaceDirection.LeftDown;
case FaceDirection.LeftDown:
return FaceDirection.Down;
case FaceDirection.Down:
return FaceDirection.RightDown;
case FaceDirection.RightDown:
return FaceDirection.Right;
case FaceDirection.Right:
return FaceDirection.RightUp;
case FaceDirection.RightUp:
return FaceDirection.Up;
case FaceDirection.Up:
return FaceDirection.LeftUp;
case FaceDirection.LeftUp:
return FaceDirection.Left;
case FaceDirection.Unknown:
return FaceDirection.Unknown;
}
} else {
switch (dir) {
case FaceDirection.Left:
return FaceDirection.LeftUp;
case FaceDirection.LeftUp:
return FaceDirection.Up;
case FaceDirection.Up:
return FaceDirection.RightUp;
case FaceDirection.RightUp:
return FaceDirection.Right;
case FaceDirection.Right:
return FaceDirection.RightDown;
case FaceDirection.RightDown:
return FaceDirection.Down;
case FaceDirection.Down:
return FaceDirection.LeftDown;
case FaceDirection.LeftDown:
return FaceDirection.Left;
case FaceDirection.Unknown:
return FaceDirection.Unknown;
}
}
} else {
if (anticlockwise) {
switch (dir) {
case FaceDirection.Left:
return FaceDirection.Down;
case FaceDirection.Down:
return FaceDirection.Right;
case FaceDirection.Right:
return FaceDirection.Up;
case FaceDirection.Up:
return FaceDirection.Left;
case FaceDirection.LeftUp:
return FaceDirection.LeftDown;
case FaceDirection.LeftDown:
return FaceDirection.RightDown;
case FaceDirection.RightDown:
return FaceDirection.RightUp;
case FaceDirection.RightUp:
return FaceDirection.LeftUp;
case FaceDirection.Unknown:
return FaceDirection.Unknown;
}
} else {
switch (dir) {
case FaceDirection.Left:
return FaceDirection.Up;
case FaceDirection.Up:
return FaceDirection.Right;
case FaceDirection.Right:
return FaceDirection.Down;
case FaceDirection.Down:
return FaceDirection.Left;
case FaceDirection.LeftUp:
return FaceDirection.RightUp;
case FaceDirection.RightUp:
return FaceDirection.RightDown;
case FaceDirection.RightDown:
return FaceDirection.LeftDown;
case FaceDirection.LeftDown:
return FaceDirection.LeftUp;
case FaceDirection.Unknown:
return FaceDirection.Unknown;
}
}
}
}
/**
*
* @param dir
*/
export function fromDirectionString(dir: Dir2): FaceDirection {
switch (dir) {
case 'left':
return FaceDirection.Left;
case 'right':
return FaceDirection.Right;
case 'up':
return FaceDirection.Up;
case 'down':
return FaceDirection.Down;
case 'leftup':
return FaceDirection.LeftUp;
case 'rightup':
return FaceDirection.RightUp;
case 'leftdown':
return FaceDirection.LeftDown;
case 'rightdown':
return FaceDirection.RightDown;
default:
return FaceDirection.Unknown;
}
}

View File

@ -1,7 +1,6 @@
import { Hookable, HookController, IHookController } from '@motajs/common'; import { Hookable, HookController, IHookController } from '@motajs/common';
import { IHeroFollower, IHeroState, IHeroStateHooks } from './types'; import { IHeroFollower, IHeroState, IHeroStateHooks } from './types';
import { FaceDirection, getFaceMovement, nextFaceDirection } from '../common'; import { FaceDirection, getFaceMovement } from '../common';
import { isNil } from 'lodash-es';
export class HeroState extends Hookable<IHeroStateHooks> implements IHeroState { export class HeroState extends Hookable<IHeroStateHooks> implements IHeroState {
x: number = 0; x: number = 0;
@ -29,16 +28,6 @@ export class HeroState extends Hookable<IHeroStateHooks> implements IHeroState {
}); });
} }
turn(direction?: FaceDirection): void {
const next = isNil(direction)
? nextFaceDirection(this.direction)
: direction;
this.direction = next;
this.forEachHook(hook => {
hook.onTurnHero?.(next);
});
}
startMove(): void { startMove(): void {
this.moving = true; this.moving = true;
this.forEachHook(hook => { this.forEachHook(hook => {

View File

@ -26,12 +26,6 @@ export interface IHeroStateHooks extends IHookBase {
*/ */
onSetPosition(x: number, y: number): void; onSetPosition(x: number, y: number): void;
/**
*
* @param direction
*/
onTurnHero(direction: FaceDirection): void;
/** /**
* *
*/ */
@ -125,12 +119,6 @@ export interface IHeroState extends IHookable<IHeroStateHooks> {
*/ */
setPosition(x: number, y: number): void; setPosition(x: number, y: number): void;
/**
*
* @param direction
*/
turn(direction?: FaceDirection): void;
/** /**
* *
*/ */

View File

@ -1,27 +1,25 @@
import type { RenderAdapter } from '@motajs/render'; import type { RenderAdapter } from '@motajs/render';
import type { TimingFn } from 'mutate-animate'; import type { TimingFn } from 'mutate-animate';
import { import { BlockMover, heroMoveCollection, MoveStep } from '@user/data-state';
BlockMover,
fromDirectionString,
heroMoveCollection,
MoveStep,
state
} from '@user/data-state';
import { hook, loading } from '@user/data-base'; import { hook, loading } from '@user/data-base';
import { Patch, PatchClass } from '@motajs/legacy-common'; import { Patch, PatchClass } from '@motajs/legacy-common';
import type { import type {
HeroRenderer,
LayerDoorAnimate, LayerDoorAnimate,
LayerGroupAnimate, LayerGroupAnimate,
Layer,
FloorViewport, FloorViewport,
LayerFloorBinder,
LayerGroup LayerGroup
} from '@user/client-modules'; } from '@user/client-modules';
import { isNil } from 'lodash-es';
// 向后兼容用,会充当两个版本间过渡的作用 // 向后兼容用,会充当两个版本间过渡的作用
interface Adapters { interface Adapters {
'hero-adapter'?: RenderAdapter<HeroRenderer>;
'door-animate'?: RenderAdapter<LayerDoorAnimate>; 'door-animate'?: RenderAdapter<LayerDoorAnimate>;
animate?: RenderAdapter<LayerGroupAnimate>; animate?: RenderAdapter<LayerGroupAnimate>;
layer?: RenderAdapter<Layer>;
viewport?: RenderAdapter<FloorViewport>; viewport?: RenderAdapter<FloorViewport>;
} }
@ -32,12 +30,16 @@ export function initFallback() {
if (!main.replayChecking && main.mode === 'play') { if (!main.replayChecking && main.mode === 'play') {
const Adapter = Mota.require('@motajs/render').RenderAdapter; const Adapter = Mota.require('@motajs/render').RenderAdapter;
const hero = Adapter.get<HeroRenderer>('hero-adapter');
const doorAnimate = Adapter.get<LayerDoorAnimate>('door-animate'); const doorAnimate = Adapter.get<LayerDoorAnimate>('door-animate');
const animate = Adapter.get<LayerGroupAnimate>('animate'); const animate = Adapter.get<LayerGroupAnimate>('animate');
const layer = Adapter.get<Layer>('layer');
const viewport = Adapter.get<FloorViewport>('viewport'); const viewport = Adapter.get<FloorViewport>('viewport');
adapters['hero-adapter'] = hero;
adapters['door-animate'] = doorAnimate; adapters['door-animate'] = doorAnimate;
adapters['animate'] = animate; adapters['animate'] = animate;
adapters['layer'] = layer;
adapters['viewport'] = viewport; adapters['viewport'] = viewport;
} }
@ -72,7 +74,7 @@ export function initFallback() {
/** /**
* *
*/ */
function generateJumpFn(dx: number, dy: number): TimingFn<2> { function generateJumpFn(dx: number, dy: number): TimingFn<3> {
const distance = Math.hypot(dx, dy); const distance = Math.hypot(dx, dy);
const peak = 3 + distance; const peak = 3 + distance;
@ -80,7 +82,7 @@ export function initFallback() {
const x = dx * progress; const x = dx * progress;
const y = progress * dy + (progress ** 2 - progress) * peak; const y = progress * dy + (progress ** 2 - progress) * peak;
return [x, y]; return [x, y, Math.ceil(y)];
}; };
} }
@ -110,28 +112,31 @@ export function initFallback() {
patch.add('_moveAction_moving', () => {}); patch.add('_moveAction_moving', () => {});
patch2.add('_action_moveAction', function () { patch2.add(
if (core.canMoveHero()) { '_action_moveAction',
const nx = core.nextX(), function (data: any, x: number, y: number, prefix: any) {
ny = core.nextY(); if (core.canMoveHero()) {
// 检查noPass决定是撞击还是移动 const nx = core.nextX(),
if (core.noPass(nx, ny)) { ny = core.nextY();
core.insertAction([{ type: 'trigger', loc: [nx, ny] }]); // 检查noPass决定是撞击还是移动
} else { if (core.noPass(nx, ny)) {
// 先移动一格,然后尝试触发事件 core.insertAction([{ type: 'trigger', loc: [nx, ny] }]);
core.insertAction([ } else {
{ // 先移动一格,然后尝试触发事件
type: 'function', core.insertAction([
function: {
'function() { core.moveAction(core.doAction); }', type: 'function',
async: true function:
}, 'function() { core.moveAction(core.doAction); }',
{ type: '_label' } async: true
]); },
{ type: '_label' }
]);
}
} }
core.doAction();
} }
core.doAction(); );
});
patch2.add( patch2.add(
'eventMoveHero', 'eventMoveHero',
@ -171,28 +176,29 @@ export function initFallback() {
patch.add( patch.add(
'setHeroLoc', 'setHeroLoc',
function (name: 'x' | 'y' | 'direction', value: number | Dir) { function (
name: 'x' | 'y' | 'direction',
value: number | Dir,
noGather?: boolean
) {
if (!core.status.hero) return; if (!core.status.hero) return;
// @ts-ignore // @ts-ignore
core.status.hero.loc[name] = value; core.status.hero.loc[name] = value;
if ((name === 'x' || name === 'y') && !noGather) {
core.control.gatherFollowers();
}
if (name === 'direction') { if (name === 'direction') {
const dir = fromDirectionString(value as Dir); adapters['hero-adapter']?.sync('turn', value);
state.hero.turn(dir); adapters['hero-adapter']?.sync('setAnimateDir', value);
setHeroDirection(value as Dir); setHeroDirection(value as Dir);
} else if (name === 'x') { } else if (name === 'x') {
// 为了防止逆天样板出问题 // 为了防止逆天样板出问题
core.bigmap.posX = value as number; core.bigmap.posX = value as number;
state.hero.setPosition( adapters['hero-adapter']?.sync('setHeroLoc', value);
value as number,
core.status.hero.loc.y
);
} else { } else {
// 为了防止逆天样板出问题 // 为了防止逆天样板出问题
core.bigmap.posY = value as number; core.bigmap.posY = value as number;
state.hero.setPosition( adapters['hero-adapter']?.sync('setHeroLoc', void 0, value);
core.status.hero.loc.x,
value as number
);
} }
} }
); );
@ -237,8 +243,10 @@ export function initFallback() {
); );
patch2.add('setHeroIcon', function (name: ImageIds) { patch2.add('setHeroIcon', function (name: ImageIds) {
const img = core.material.images.images[name];
if (!img) return;
core.status.hero.image = name; core.status.hero.image = name;
state.hero.setImage(name); adapters['hero-adapter']?.sync('setImage', img);
}); });
patch.add('isMoving', function () { patch.add('isMoving', function () {
@ -271,10 +279,10 @@ export function initFallback() {
// 找寻自动寻路路线 // 找寻自动寻路路线
const moveStep = core.automaticRoute(destX, destY); const moveStep = core.automaticRoute(destX, destY);
if ( if (
moveStep.length === 0 && moveStep.length == 0 &&
(destX !== core.status.hero.loc.x || (destX != core.status.hero.loc.x ||
destY !== core.status.hero.loc.y || destY != core.status.hero.loc.y ||
stepPostfix.length === 0) stepPostfix.length == 0)
) )
return; return;
moveStep.push(...stepPostfix); moveStep.push(...stepPostfix);
@ -367,10 +375,10 @@ export function initFallback() {
id = id || ''; id = id || '';
if ( if (
// @ts-ignore // @ts-ignore
(isNil(core.material.icons.animates[id]) && (core.material.icons.animates[id] == null &&
// @ts-ignore // @ts-ignore
isNil(core.material.icons.npc48[id])) || core.material.icons.npc48[id] == null) ||
!isNil(core.getBlock(x, y)) core.getBlock(x, y) != null
) { ) {
if (callback) callback(); if (callback) callback();
return; return;
@ -430,10 +438,10 @@ export function initFallback() {
if ( if (
core.isReplaying() || core.isReplaying() ||
!core.material.animates[name] || !core.material.animates[name] ||
isNil(x) || x == null ||
isNil(y) y == null
) { ) {
callback?.(); if (callback) callback();
return -1; return -1;
} }
@ -539,25 +547,26 @@ export function initFallback() {
const dy = ey - sy; const dy = ey - sy;
const fn = generateJumpFn(dx, dy); const fn = generateJumpFn(dx, dy);
// 先使用 mainMapRenderer 妥协
const { mainMapRenderer: renderer } = Mota.require(
'@user/client-modules'
);
if (renderer.layerState !== state.layer) {
callback?.();
return;
}
const layer = state.layer.getLayerByAlias('event');
if (!layer) {
callback?.();
return;
}
core.removeBlock(sx, sy);
const moving = renderer.addMovingBlock(layer, block.id, sx, sy);
core.updateStatusBar();
await moving.moveRelative(fn, time);
moving.destroy();
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, keep);
})
);
core.updateStatusBar();
core.removeBlock(sx, sy);
await promise;
if (keep) { if (keep) {
core.setBlock(block.id, ex, ey); core.setBlock(block.id, ex, ey);
} }
@ -577,15 +586,30 @@ export function initFallback() {
) { ) {
if (heroMover.moving) return; if (heroMover.moving) return;
const sx = core.getHeroLoc('x');
const sy = core.getHeroLoc('y');
adapters.viewport?.all('mutateTo', ex, ey, time); adapters.viewport?.all('mutateTo', ex, ey, time);
const locked = core.status.lockControl; const locked = core.status.lockControl;
core.lockControl(); core.lockControl();
const list = adapters['hero-adapter']?.items ?? [];
const items = [...list];
time /= core.status.replay.speed; time /= core.status.replay.speed;
if (core.status.replay.speed === 24) time = 1; if (core.status.replay.speed === 24) time = 1;
const fn = generateJumpFn(ex - sx, ey - sy);
await state.hero.jumpHero(ex, ey, time); 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(); if (!locked) core.unlockControl();
core.setHeroLoc('x', ex); core.setHeroLoc('x', ex);