refactor: 将 Layer 0 单独放到一个包

This commit is contained in:
AncTe committed 2026-05-17 21:32:23 +08:00
1 parent bf781c5ee8
commit 8f4c4b7df2
48 files changed
+159 -97

No files matched your search

+1
View File
@@ -1,6 +1,7 @@
{
"name": "@user/data-base",
"dependencies": {
"@user/data-common": "workspace:*",
"@motajs/common": "workspace:*",
"@motajs/types": "workspace:*",
"@motajs/loader": "workspace:*"
@@ -1,63 +0,0 @@
import { logger } from '@motajs/common';
import { IFaceData, IRoleFaceBinder } from './types';
import { isNil } from 'lodash-es';
import { FaceDirection } from '.';
interface FaceInfo {
/** 此图块的朝向 */
readonly face: FaceDirection;
/** 此图块对应的映射 */
readonly map: Map<FaceDirection, number>;
}
export class RoleFaceBinder implements IRoleFaceBinder {
/** 每个图块对应的朝向信息 */
private faceMap: Map<number, FaceInfo> = new Map();
/** 主要朝向映射 */
private mainMap: Map<number, FaceDirection> = new Map();
malloc(identifier: number, main: FaceDirection): void {
this.mainMap.set(identifier, main);
const map = new Map<FaceDirection, number>();
map.set(main, identifier);
const info: FaceInfo = { face: main, map };
this.faceMap.set(identifier, info);
}
bind(identifier: number, main: number, face: FaceDirection): void {
const mainFace = this.mainMap.get(main);
if (isNil(mainFace)) {
logger.error(43, main.toString());
return;
}
if (mainFace === face) {
logger.error(44, main.toString());
return;
}
const { map } = this.faceMap.get(main)!;
map.set(face, identifier);
const info: FaceInfo = { face, map };
this.faceMap.set(identifier, info);
this.mainMap.set(identifier, mainFace);
}
getFaceOf(identifier: number, face: FaceDirection): IFaceData | null {
const info = this.faceMap.get(identifier);
if (!info) return null;
const target = info.map.get(face);
if (isNil(target)) return null;
const data: IFaceData = { identifier: target, face };
return data;
}
getFaceDirection(identifier: number): FaceDirection | undefined {
return this.faceMap.get(identifier)?.face;
}
getMainFace(identifier: number): IFaceData | null {
const face = this.mainMap.get(identifier);
if (isNil(face)) return null;
const data: IFaceData = { identifier, face };
return data;
}
}
@@ -1,282 +0,0 @@
import { FaceDirection } from './types';
//#region 接口与枚举
export const enum InternalFaceGroup {
/** 四方向(上下左右) */
Dir4,
/** 八方向(上下左右+斜向) */
Dir8
}
export interface IFaceDescriptor {
/** 横坐标增量 */
readonly x: number;
/** 纵坐标增量 */
readonly y: number;
}
export interface IFaceHandler<T extends number> {
/**
* 将任意朝向值降级为本组支持的方向。
* 对于无法合理降级的方向(包括 `Unknown`),返回 `FaceDirection.Unknown`
* @param dir 任意朝向值
*/
degrade(dir: number): T;
/**
* 获取指定方向的单步坐标偏移量,输入先经过 `degrade`
* @param dir 朝向
*/
movement(dir: number): IFaceDescriptor;
/**
* 获取指定方向走 `count` 步的坐标偏移量,等价于 `movement * count`。
* `count` 允许为负数,表示反向位移,输入先经过 `degrade`
* @param dir 朝向
* @param count 步数,允许为负
*/
move(dir: number, count: number): IFaceDescriptor;
/**
* 获取本组内的反方向,输入先经过 `degrade`,`Unknown` 返回 `Unknown`
* @param dir 朝向
*/
opposite(dir: number): T;
/**
* 在本组方向集合内顺时针(默认)或逆时针旋转一步,输入先经过 `degrade`,
* `Unknown` 返回 `Unknown`
* @param dir 朝向
* @param anticlockwise 是否逆时针,默认顺时针
*/
next(dir: number, anticlockwise?: boolean): T;
/**
* 迭代本组支持的所有朝向,包含 `Unknown`
*/
mapDirection(): Iterable<T>;
/**
* 迭代本组所有朝向及其对应的坐标描述器,包含 `Unknown`(对应 `{ x: 0, y: 0 }`)
*/
mapMovement(): Iterable<[T, IFaceDescriptor]>;
}
export interface IFaceManager {
/**
* 以数字 key 注册一个 handler
* @param group 数字 key
* @param handler 朝向处理器
*/
register(group: number, handler: IFaceHandler<number>): void;
/**
* 以字符串 id 注册一个 handler
* @param id 字符串 id
* @param handler 朝向处理器
*/
registerById(id: string, handler: IFaceHandler<number>): void;
/**
* 按数字 key 查找 handler,未找到返回 `null`
* @param group 数字 key
*/
get<T extends number>(group: number): IFaceHandler<T> | null;
/**
* 按字符串 id 查找 handler,未找到返回 `null`
* @param id 字符串 id
*/
getById<T extends number>(id: string): IFaceHandler<T> | null;
}
//#endregion
//#region 内置 Handler
const ZERO_DESCRIPTOR: IFaceDescriptor = { x: 0, y: 0 };
const DIR8_MOVEMENTS: ReadonlyMap<FaceDirection, IFaceDescriptor> = new Map([
[FaceDirection.Unknown, ZERO_DESCRIPTOR],
[FaceDirection.Left, { x: -1, y: 0 }],
[FaceDirection.Up, { x: 0, y: -1 }],
[FaceDirection.Right, { x: 1, y: 0 }],
[FaceDirection.Down, { x: 0, y: 1 }],
[FaceDirection.LeftUp, { x: -1, y: -1 }],
[FaceDirection.RightUp, { x: 1, y: -1 }],
[FaceDirection.LeftDown, { x: -1, y: 1 }],
[FaceDirection.RightDown, { x: 1, y: 1 }]
]);
/** 顺时针旋转顺序(不含 Unknown) */
const DIR8_CW: ReadonlyMap<FaceDirection, FaceDirection> = new Map([
[FaceDirection.Up, FaceDirection.RightUp],
[FaceDirection.RightUp, FaceDirection.Right],
[FaceDirection.Right, FaceDirection.RightDown],
[FaceDirection.RightDown, FaceDirection.Down],
[FaceDirection.Down, FaceDirection.LeftDown],
[FaceDirection.LeftDown, FaceDirection.Left],
[FaceDirection.Left, FaceDirection.LeftUp],
[FaceDirection.LeftUp, FaceDirection.Up]
]);
/** 逆时针旋转顺序(不含 Unknown) */
const DIR8_CCW: ReadonlyMap<FaceDirection, FaceDirection> = new Map([
[FaceDirection.Up, FaceDirection.LeftUp],
[FaceDirection.LeftUp, FaceDirection.Left],
[FaceDirection.Left, FaceDirection.LeftDown],
[FaceDirection.LeftDown, FaceDirection.Down],
[FaceDirection.Down, FaceDirection.RightDown],
[FaceDirection.RightDown, FaceDirection.Right],
[FaceDirection.Right, FaceDirection.RightUp],
[FaceDirection.RightUp, FaceDirection.Up]
]);
const DIR8_OPPOSITE: ReadonlyMap<FaceDirection, FaceDirection> = new Map([
[FaceDirection.Up, FaceDirection.Down],
[FaceDirection.Down, FaceDirection.Up],
[FaceDirection.Left, FaceDirection.Right],
[FaceDirection.Right, FaceDirection.Left],
[FaceDirection.LeftUp, FaceDirection.RightDown],
[FaceDirection.RightDown, FaceDirection.LeftUp],
[FaceDirection.RightUp, FaceDirection.LeftDown],
[FaceDirection.LeftDown, FaceDirection.RightUp]
]);
export class Dir8FaceHandler implements IFaceHandler<FaceDirection> {
degrade(dir: number): FaceDirection {
return dir as FaceDirection;
}
movement(dir: number): IFaceDescriptor {
return DIR8_MOVEMENTS.get(this.degrade(dir)) ?? ZERO_DESCRIPTOR;
}
move(dir: number, count: number): IFaceDescriptor {
const { x, y } = this.movement(dir);
return { x: x * count, y: y * count };
}
opposite(dir: number): FaceDirection {
const degraded = this.degrade(dir);
return DIR8_OPPOSITE.get(degraded) ?? FaceDirection.Unknown;
}
next(dir: number, anticlockwise: boolean = false): FaceDirection {
const degraded = this.degrade(dir);
if (degraded === FaceDirection.Unknown) return FaceDirection.Unknown;
const map = anticlockwise ? DIR8_CCW : DIR8_CW;
return map.get(degraded) ?? FaceDirection.Unknown;
}
mapDirection(): Iterable<FaceDirection> {
return DIR8_MOVEMENTS.keys();
}
mapMovement(): Iterable<[FaceDirection, IFaceDescriptor]> {
return DIR8_MOVEMENTS.entries();
}
}
const DIR4_DEGRADE: ReadonlyMap<FaceDirection, FaceDirection> = new Map([
[FaceDirection.Left, FaceDirection.Left],
[FaceDirection.Up, FaceDirection.Up],
[FaceDirection.Right, FaceDirection.Right],
[FaceDirection.Down, FaceDirection.Down],
[FaceDirection.LeftUp, FaceDirection.Left],
[FaceDirection.LeftDown, FaceDirection.Left],
[FaceDirection.RightUp, FaceDirection.Right],
[FaceDirection.RightDown, FaceDirection.Right]
]);
const DIR4_MOVEMENTS: ReadonlyMap<FaceDirection, IFaceDescriptor> = new Map([
[FaceDirection.Unknown, ZERO_DESCRIPTOR],
[FaceDirection.Left, { x: -1, y: 0 }],
[FaceDirection.Up, { x: 0, y: -1 }],
[FaceDirection.Right, { x: 1, y: 0 }],
[FaceDirection.Down, { x: 0, y: 1 }]
]);
const DIR4_CW: ReadonlyMap<FaceDirection, FaceDirection> = new Map([
[FaceDirection.Up, FaceDirection.Right],
[FaceDirection.Right, FaceDirection.Down],
[FaceDirection.Down, FaceDirection.Left],
[FaceDirection.Left, FaceDirection.Up]
]);
const DIR4_CCW: ReadonlyMap<FaceDirection, FaceDirection> = new Map([
[FaceDirection.Up, FaceDirection.Left],
[FaceDirection.Left, FaceDirection.Down],
[FaceDirection.Down, FaceDirection.Right],
[FaceDirection.Right, FaceDirection.Up]
]);
const DIR4_OPPOSITE: ReadonlyMap<FaceDirection, FaceDirection> = new Map([
[FaceDirection.Up, FaceDirection.Down],
[FaceDirection.Down, FaceDirection.Up],
[FaceDirection.Left, FaceDirection.Right],
[FaceDirection.Right, FaceDirection.Left]
]);
export class Dir4FaceHandler implements IFaceHandler<FaceDirection> {
degrade(dir: number): FaceDirection {
return DIR4_DEGRADE.get(dir as FaceDirection) ?? FaceDirection.Unknown;
}
movement(dir: number): IFaceDescriptor {
return DIR4_MOVEMENTS.get(this.degrade(dir)) ?? ZERO_DESCRIPTOR;
}
move(dir: number, count: number): IFaceDescriptor {
const { x, y } = this.movement(dir);
return { x: x * count, y: y * count };
}
opposite(dir: number): FaceDirection {
const degraded = this.degrade(dir);
return DIR4_OPPOSITE.get(degraded) ?? FaceDirection.Unknown;
}
next(dir: number, anticlockwise: boolean = false): FaceDirection {
const degraded = this.degrade(dir);
if (degraded === FaceDirection.Unknown) return FaceDirection.Unknown;
const map = anticlockwise ? DIR4_CCW : DIR4_CW;
return map.get(degraded) ?? FaceDirection.Unknown;
}
mapDirection(): Iterable<FaceDirection> {
return DIR4_MOVEMENTS.keys();
}
mapMovement(): Iterable<[FaceDirection, IFaceDescriptor]> {
return DIR4_MOVEMENTS.entries();
}
}
//#endregion
//#region FaceManager
export class FaceManager implements IFaceManager {
private readonly byGroup: Map<number, IFaceHandler<number>> = new Map();
private readonly byId: Map<string, IFaceHandler<number>> = new Map();
register(group: number, handler: IFaceHandler<number>): void {
this.byGroup.set(group, handler);
}
registerById(id: string, handler: IFaceHandler<number>): void {
this.byId.set(id, handler);
}
get<T extends number>(group: number): IFaceHandler<T> | null {
return (this.byGroup.get(group) as IFaceHandler<T>) ?? null;
}
getById<T extends number>(id: string): IFaceHandler<T> | null {
return (this.byId.get(id) as IFaceHandler<T>) ?? null;
}
}
//#endregion
@@ -1,6 +0,0 @@
export * from './face';
export * from './faceManager';
export * from './indexer';
export * from './mover';
export * from './types';
export * from './utils';
@@ -1,61 +0,0 @@
import { ITileLocator } from '@motajs/common';
//#region 接口定义
export interface ILocationHelper {
/**
* 坐标 -> 索引
* @param x 横坐标
* @param y 纵坐标
*/
locToIndex(x: number, y: number): number;
/**
* 定位符 -> 索引
* @param locator 定位符
*/
locaterToIndex(locator: ITileLocator): number;
/**
* 索引 -> 定位符
* @param index 索引
*/
indexToLocator(index: number): ITileLocator;
}
export interface ILocationIndexer extends ILocationHelper {
/**
* 设置地图宽度
* @param width 地图宽度
*/
setWidth(width: number): void;
}
//#endregion
//#region 默认实现
export class MapLocIndexer implements ILocationIndexer {
private width: number = 0;
setWidth(width: number): void {
this.width = width;
}
locToIndex(x: number, y: number): number {
return y * this.width + x;
}
locaterToIndex(locator: ITileLocator): number {
return locator.y * this.width + locator.x;
}
indexToLocator(index: number): ITileLocator {
return {
x: index % this.width,
y: Math.floor(index / this.width)
};
}
}
//#endregion
-560
View File
@@ -1,560 +0,0 @@
import {
Hookable,
HookController,
IHookable,
IHookBase,
IHookController,
ITileLocator
} from '@motajs/common';
import { FaceDirection } from './types';
import { IFaceHandler } from './faceManager';
//#region 对象移动
export const enum ObjectMoveStepType {
/** 绝对方向步,同步更新移动方向与朝向 */
Dir,
/** 绝对方向步,显式指定朝向 */
DirFace,
/** 速度步 */
Speed,
/** 纯转向步 */
Face,
/** 特殊步,如前进或后退 */
Special,
/** 动画方向步 */
AnimDir
}
export const enum ObjectSpecialStep {
/** 前进 */
Forward,
/** 后退 */
Backward
}
export const enum ObjectAnimDirection {
/** 正向播放动画 */
Forward,
/** 反向播放动画 */
Backward
}
export interface IObjectMovable {
/** 当前横坐标 */
readonly x: number;
/** 当前纵坐标 */
readonly y: number;
/**
* 设置对象位置
* @param x 横坐标
* @param y 纵坐标
*/
setPos(x: number, y: number): void;
/**
* 获取当前朝向
*/
getCurrentFaceDirection(): FaceDirection;
}
export interface IObjectMoveStepDir {
/** 步骤类型 */
type: ObjectMoveStepType.Dir;
/** 本步移动方向 */
move: FaceDirection;
}
export interface IObjectMoveStepDirFace {
/** 步骤类型 */
type: ObjectMoveStepType.DirFace;
/** 本步移动方向 */
move: FaceDirection;
/** 本步显式朝向 */
face: FaceDirection;
}
export interface IObjectMoveStepSpeed {
/** 步骤类型 */
type: ObjectMoveStepType.Speed;
/** 后续移动的每格耗时,单位为 ms */
value: number;
}
export interface IObjectMoveStepFace {
/** 步骤类型 */
type: ObjectMoveStepType.Face;
/** 要设置的朝向 */
value: FaceDirection;
}
export interface IObjectMoveStepSpecial {
/** 步骤类型 */
type: ObjectMoveStepType.Special;
/** 特殊步方向 */
direction: ObjectSpecialStep;
}
export interface IObjectMoveAnimDir {
/** 步骤类型 */
type: ObjectMoveStepType.AnimDir;
/** 动画播放方向 */
dir: ObjectAnimDirection;
}
export type ObjectMoveStep =
| IObjectMoveStepDir
| IObjectMoveStepDirFace
| IObjectMoveStepSpeed
| IObjectMoveStepFace
| IObjectMoveStepSpecial
| IObjectMoveAnimDir;
export interface IMoverController {
/** 本次移动是否已经全部完成 */
done: boolean;
/** 当本次移动结束时兑现 */
onEnd: Promise<void>;
/**
* 向当前移动队列末尾追加步骤
* @param steps 要追加的步骤列表
*/
push(...steps: ObjectMoveStep[]): void;
/**
* 在当前步移动之后立刻插入指定步,顺序为参数传入的顺序
* @param steps 要插入的步骤列表
*/
insert(...steps: ObjectMoveStep[]): void;
/**
* 停止当前移动,在当前步骤完成后兑现
*/
stop(): Promise<void>;
}
export interface IObjectMoverHooks<T extends IObjectMovable> extends IHookBase {
/**
* 当移动开始时触发
* @param tile 移动器绑定的图块
* @param mover 当前移动器
*/
onMoveStart?(tile: T, mover: IObjectMover<T>): Promise<void>;
/**
* 当移动结束时触发
* @param tile 移动器绑定的图块
* @param mover 当前移动器
*/
onMoveEnd?(tile: T, mover: IObjectMover<T>): Promise<void>;
/**
* 当单步移动开始前触发,此时对象坐标仍为移动前坐标
* @param code 当前步移动代码
* @param step 当前步骤
* @param tile 移动器绑定的图块
* @param mover 当前移动器
*/
onStepStart?(
code: number,
step: ObjectMoveStep,
tile: T,
mover: IObjectMover<T>
): Promise<void>;
/**
* 当单步移动结束后触发,此时对象坐标已更新为移动后坐标
* @param code 当前步移动代码
* @param step 当前步骤
* @param tile 移动器绑定的图块
* @param mover 当前移动器
*/
onStepEnd?(
code: number,
step: ObjectMoveStep,
tile: T,
mover: IObjectMover<T>
): Promise<void>;
}
export interface IObjectMover<T extends IObjectMovable> extends IHookable<
IObjectMoverHooks<T>
> {
/** 当前是否正在移动 */
readonly moving: boolean;
/** 当前绑定的对象 */
readonly tile: T;
/** 当前朝向 */
readonly faceDirection: FaceDirection;
/** 当前移动方向 */
readonly moveDirection: FaceDirection;
/** 当前动画播放方向 */
readonly currAnimDir: ObjectAnimDirection;
/** 当前移动速度,单位毫秒 */
readonly currentSpeed: number;
/**
* 追加若干个绝对方向步,并同步更新移动方向与朝向
* @param dir 移动方向
* @param count 追加次数,默认 1
*/
step(dir: FaceDirection, count?: number): this;
/**
* 追加若干个绝对方向步,移动方向与朝向分别指定
* @param move 移动方向
* @param face 朝向方向
* @param count 追加次数,默认 1
*/
stepFace(move: FaceDirection, face: FaceDirection, count?: number): this;
/**
* 追加若干个前进步,沿当前移动方向移动
* @param count 追加次数,默认 1
*/
forward(count?: number): this;
/**
* 追加若干个后退步,沿当前移动方向的反方向移动
* @param count 追加次数,默认 1
*/
backward(count?: number): this;
/**
* 设置后续移动速度
* @param value 每格耗时,单位为 ms
*/
speed(value: number): this;
/**
* 追加一个纯转向步骤
* @param dir 目标朝向
*/
face(dir: FaceDirection): this;
/**
* 设置后续步骤的动画播放方向
* @param dir 动画播放方向
*/
animDir(dir: ObjectAnimDirection): this;
/**
* 清空尚未执行的步骤队列
*/
clear(): this;
/**
* 开始执行当前计划队列
* @returns 若当前已在移动,则返回 `null`
*/
start(): Readonly<IMoverController> | null;
}
//#endregion
//#region 移动基类
export abstract class ObjectMover<T extends IObjectMovable>
extends Hookable<IObjectMoverHooks<T>>
implements IObjectMover<T>
{
abstract readonly tile: T;
/** 尚未开始执行的移动步骤队列 */
protected readonly moveQueue: Readonly<ObjectMoveStep>[] = [];
/** 当前是否正在移动 */
moving: boolean = false;
/** 当前朝向 */
faceDirection: FaceDirection = FaceDirection.Unknown;
/** 当前移动方向 */
moveDirection: FaceDirection = FaceDirection.Unknown;
/** 当前动画播放方向 */
currAnimDir: ObjectAnimDirection = ObjectAnimDirection.Forward;
/** 当前移动速度,单位毫秒 */
currentSpeed: number = 100;
/** 是否调用了 `IMoverController.stop` 接口 */
private shouldStop: boolean = false;
/** 朝向处理 */
private readonly faceHandler: IFaceHandler<FaceDirection>;
constructor(faceHandler: IFaceHandler<FaceDirection>) {
super();
this.faceHandler = faceHandler;
}
protected createController(
hook: Partial<IObjectMoverHooks<T>>
): IHookController<IObjectMoverHooks<T>> {
return new HookController(this, hook);
}
/**
* 当移动开始时执行
* @param tile 移动图块
* @param controller 移动控制器
*/
protected abstract onMoveStart(
tile: T,
controller: Readonly<IMoverController>
): Promise<void>;
/**
* 当移动结束时触发
* @param tile 移动图块
* @param controller 移动控制器
*/
protected abstract onMoveEnd(
tile: T,
controller: Readonly<IMoverController>
): Promise<void>;
/**
* 当单步移动开始时触发,返回移动代码,此移动代码将会传递至 {@link onStepEnd}
* @param step 当前移动步对象
* @param tile 移动图块
* @param controller 移动控制器
*/
protected abstract onStepStart(
step: ObjectMoveStep,
tile: T,
controller: Readonly<IMoverController>
): Promise<number>;
/**
* 当单步移动结束时触发,返回坐标对象代表这一步移动结果
* @param code 移动代码,由 {@link onStepStart} 返回值传递而来
* @param step 当前移动步对象
* @param tile 移动图块
* @param controller 移动控制器
*/
protected abstract onStepEnd(
code: number,
step: ObjectMoveStep,
tile: T,
controller: Readonly<IMoverController>
): Promise<ITileLocator>;
/**
* 向计划队列末尾追加一个步骤
* @param step 要追加的步骤
*/
protected pushStep(step: Readonly<ObjectMoveStep>): void {
this.moveQueue.push(step);
}
/**
* 获取当前应当作为相对移动基准的方向
*/
private getCurrentDirection(): FaceDirection {
if (this.moveDirection !== FaceDirection.Unknown) {
return this.moveDirection;
} else {
return this.faceDirection;
}
}
/**
* 根据步骤内容预先同步移动器内部状态
* @param step 当前步骤
*/
private prepareStep(step: ObjectMoveStep): void {
switch (step.type) {
case ObjectMoveStepType.Dir:
this.moveDirection = step.move;
this.faceDirection = step.move;
break;
case ObjectMoveStepType.DirFace:
this.moveDirection = step.move;
this.faceDirection = step.face;
break;
case ObjectMoveStepType.Face:
this.faceDirection = step.value;
break;
case ObjectMoveStepType.Special: {
const dir = this.getCurrentDirection();
if (step.direction === ObjectSpecialStep.Backward) {
const opposite = this.faceHandler.opposite(dir);
this.moveDirection = opposite;
this.faceDirection = opposite;
} else {
this.moveDirection = dir;
this.faceDirection = dir;
}
break;
}
case ObjectMoveStepType.AnimDir:
this.currAnimDir = step.dir;
break;
case ObjectMoveStepType.Speed:
this.currentSpeed = step.value;
break;
}
}
step(dir: FaceDirection, count: number = 1): this {
for (let i = 0; i < count; i++) {
this.pushStep({
type: ObjectMoveStepType.Dir,
move: dir
});
}
return this;
}
stepFace(
move: FaceDirection,
face: FaceDirection,
count: number = 1
): this {
for (let i = 0; i < count; i++) {
this.pushStep({
type: ObjectMoveStepType.DirFace,
move,
face
});
}
return this;
}
forward(count: number = 1): this {
for (let i = 0; i < count; i++) {
this.pushStep({
type: ObjectMoveStepType.Special,
direction: ObjectSpecialStep.Forward
});
}
return this;
}
backward(count: number = 1): this {
for (let i = 0; i < count; i++) {
this.pushStep({
type: ObjectMoveStepType.Special,
direction: ObjectSpecialStep.Backward
});
}
return this;
}
speed(value: number): this {
this.pushStep({
type: ObjectMoveStepType.Speed,
value
});
return this;
}
face(dir: FaceDirection): this {
this.pushStep({
type: ObjectMoveStepType.Face,
value: dir
});
return this;
}
animDir(dir: ObjectAnimDirection): this {
this.pushStep({
type: ObjectMoveStepType.AnimDir,
dir
});
return this;
}
clear(): this {
this.moveQueue.length = 0;
return this;
}
/**
* 开始移动流程
* @param queue 移动队列
*/
private async moveProgress(
queue: ObjectMoveStep[],
controller: Readonly<IMoverController>
) {
// 移动开始
await this.onMoveStart(this.tile, controller);
await Promise.all(
this.forEachHook(hook => {
return hook.onMoveStart?.(this.tile, this);
})
);
// 移动流程
while (queue.length > 0) {
const step = queue.shift();
if (!step || !this.moving || this.shouldStop) break;
this.prepareStep(step);
const code = await this.onStepStart(step, this.tile, controller);
const stepStartHooks = this.forEachHook(hook =>
hook.onStepStart?.(code, step, this.tile, this)
);
await Promise.all(stepStartHooks);
const loc = await this.onStepEnd(code, step, this.tile, controller);
this.tile.setPos(loc.x, loc.y);
const stepEndHooks = this.forEachHook(hook =>
hook.onStepEnd?.(code, step, this.tile, this)
);
await Promise.all(stepEndHooks);
}
// 移动结束
await this.onMoveEnd(this.tile, controller);
const moveEndHooks = this.forEachHook(hook =>
hook.onMoveEnd?.(this.tile, this)
);
await Promise.all(moveEndHooks);
}
start(): IMoverController | null {
if (this.moving) return null;
const queue = this.moveQueue.slice();
this.clear();
this.shouldStop = false;
this.faceDirection = this.tile.getCurrentFaceDirection();
this.moveDirection = FaceDirection.Unknown;
const { promise, resolve } = Promise.withResolvers<void>();
const controller: IMoverController = {
done: false,
onEnd: promise,
push: (...steps: ObjectMoveStep[]) => {
if (!this.moving || this.shouldStop || controller.done) {
return;
}
queue.push(...steps);
},
insert: (...steps: ObjectMoveStep[]) => {
if (!this.moving || this.shouldStop || controller.done) {
return;
}
queue.unshift(...steps);
},
stop: () => {
this.shouldStop = true;
return controller.onEnd;
}
};
this.moving = true;
const moving = this.moveProgress(queue, controller);
moving.then(() => {
this.moving = false;
controller.done = true;
resolve();
});
return controller;
}
}
//#endregion
@@ -1,82 +0,0 @@
export const enum FaceDirection {
Unknown,
Left,
Up,
Right,
Down,
LeftUp,
RightUp,
LeftDown,
RightDown
}
export interface IFaceData {
/** 图块数字 */
readonly identifier: number;
/** 图块朝向 */
readonly face: FaceDirection;
}
export interface IRoleFaceBinder {
/**
* 给指定的图块分配朝向绑定
* @param identifier 图块数字
* @param main 主图块朝向,一般是朝下
*/
malloc(identifier: number, main: FaceDirection): void;
/**
* 将一个图块与另一个图块绑定朝向,需要注意要先调用 {@link malloc} 分配朝向信息
* @param identifier 当前图块数字
* @param main 主图块数字,即当前图块与目标图块属于主图块的另一个朝向
* @param face 当前图块的朝向方向
*/
bind(identifier: number, main: number, face: FaceDirection): void;
/**
* 获取一个图块指定朝向的图块数字
* @param identifier 图块数字,可以是任意朝向的图块数字
* @param face 要获取的朝向
*/
getFaceOf(identifier: number, face: FaceDirection): IFaceData | null;
/**
* 获取指定图块数字是哪个朝向
* @param identifier 图块数字
*/
getFaceDirection(identifier: number): FaceDirection | undefined;
/**
* 获取指定图块数字绑定至的主朝向
* @param identifier 图块数字,可以是任意朝向的图块数字
*/
getMainFace(identifier: number): IFaceData | null;
}
//#region 功能接口
export const enum SaveCompression {
/** 不进行压缩,仅提取必要数据 */
NoCompression,
/** 进行小幅度压缩,以性能为主要考虑目标 */
LowCompression,
/** 进行大幅度压缩,以体积为主要考虑目标 */
HighCompression
}
export interface ISaveableContent<T> {
/**
* 保存对象状态,返回的对象应该经过深拷贝(即 `structuedClone`)
* @param compression 压缩级别
*/
saveState(compression: SaveCompression): T;
/**
* 读取对象状态
* @param state 状态对象
* @param compression 压缩级别
*/
loadState(state: T, compression: SaveCompression): void;
}
//#endregion
-182
View File
@@ -1,182 +0,0 @@
import { FaceDirection } from './types';
/**
* 获取指定朝向的坐标偏移量
* @param dir 朝向
*/
export function getFaceMovement(dir: FaceDirection): Loc {
switch (dir) {
case FaceDirection.Left:
return { x: -1, y: 0 };
case FaceDirection.Right:
return { x: 1, y: 0 };
case FaceDirection.Up:
return { x: 0, y: -1 };
case FaceDirection.Down:
return { x: 0, y: 1 };
case FaceDirection.LeftUp:
return { x: -1, y: -1 };
case FaceDirection.RightUp:
return { x: 1, y: -1 };
case FaceDirection.LeftDown:
return { x: -1, y: 1 };
case FaceDirection.RightDown:
return { x: 1, y: 1 };
case FaceDirection.Unknown:
return { x: 0, y: 0 };
}
}
/**
* 将八方向朝向降级为四方向朝向
* @param dir 朝向
* @param unknown 如果朝向是 `FaceDirection.Unknown`,那么会返回什么,默认值是未知
*/
export function degradeFace(
dir: FaceDirection,
unknown: FaceDirection = FaceDirection.Unknown
): FaceDirection {
switch (dir) {
case FaceDirection.LeftUp:
return FaceDirection.Left;
case FaceDirection.LeftDown:
return FaceDirection.Left;
case FaceDirection.RightUp:
return FaceDirection.Right;
case FaceDirection.RightDown:
return FaceDirection.Right;
case FaceDirection.Unknown:
return unknown;
}
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;
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
import { logger } from '@motajs/common';
import { SaveCompression } from '../common';
import { SaveCompression } from '@user/data-common';
import { IEnemy, IEnemySaveState, IReadonlyEnemy, ISpecial } from './types';
export class Enemy<TAttr> implements IEnemy<TAttr> {
+1 -1
View File
@@ -10,7 +10,7 @@ import {
SpecialCreation,
IEnemySaveState
} from './types';
import { SaveCompression } from '../common';
import { SaveCompression } from '@user/data-common';
export class EnemyManager<TAttr> implements IEnemyManager<TAttr> {
/** 特殊属性注册表,code -> 创建函数 */
+1 -1
View File
@@ -1,5 +1,5 @@
import { isEqual } from 'lodash-es';
import { SaveCompression } from '../common';
import { SaveCompression } from '@user/data-common';
import { ISpecial, SpecialCreation } from './types';
// TODO: 颜色参数
+1 -1
View File
@@ -1,4 +1,4 @@
import { ISaveableContent } from '../common';
import { ISaveableContent } from '@user/data-common';
//#region 怪物基础
+1 -1
View File
@@ -1,6 +1,6 @@
//#region 字段
import { ISaveableContent } from '../common';
import { ISaveableContent } from '@user/data-common';
export interface IFlagCommonField<T> {
/** 此字段所处的 Flag 系统 */
@@ -1,5 +1,5 @@
import { logger } from '@motajs/common';
import { SaveCompression } from '../common';
import { SaveCompression } from '@user/data-common';
import { IHeroAttribute, IHeroModifier } from './types';
export abstract class BaseHeroModifier<T, V> implements IHeroModifier<T, V, V> {
+2 -2
View File
@@ -1,8 +1,8 @@
import { Hookable, HookController, IHookController } from '@motajs/common';
import { isNil } from 'lodash-es';
import { getFaceMovement, nextFaceDirection } from '../common/utils';
import { getFaceMovement, nextFaceDirection } from '@user/data-common';
import { IHeroFollower, IHeroMover, IHeroMovingHooks } from './types';
import { FaceDirection } from '../common';
import { FaceDirection } from '@user/data-common';
const DEFAULT_HERO_IMAGE: ImageIds = 'hero.png';
+1 -1
View File
@@ -8,7 +8,7 @@ import {
IModifierStateSave,
IReadonlyHeroAttribute
} from './types';
import { SaveCompression } from '../common';
import { SaveCompression } from '@user/data-common';
import { logger } from '@motajs/common';
export class HeroState<THero> implements IHeroState<THero> {
+1 -1
View File
@@ -1,5 +1,5 @@
import { IFacedTileLocator, IHookBase, IHookable } from '@motajs/common';
import { FaceDirection, ISaveableContent } from '../common';
import { FaceDirection, ISaveableContent } from '@user/data-common';
//#region 勇士属性
-2
View File
@@ -1,10 +1,8 @@
export * from './common';
export * from './enemy';
export * from './flag';
export * from './hero';
export * from './load';
export * from './map';
export * from './store';
export * from './game';
export * from './types';
@@ -11,13 +11,15 @@ import {
IDynamicTile,
IMapLayer
} from './types';
import { FaceDirection, degradeFace } from '../common';
import { FaceDirection, IDataCommon, degradeFace } from '@user/data-common';
import { DynamicTile } from './dynamicTile';
export class DynamicLayer
extends Hookable<IDynamicLayerHooks>
implements IDynamicLayer
{
readonly state: IDataCommon;
/** 坐标到动态图块集合的映射,外层 key = y,内层 key = x,不使用 index 是为了支持地图外图块 */
private readonly tilePosMap: Map<number, Map<number, Set<IDynamicTile>>> =
new Map();
@@ -26,6 +28,7 @@ export class DynamicLayer
constructor(public readonly layer: IMapLayer) {
super();
this.state = layer.state;
}
protected createController(
@@ -1,14 +1,16 @@
import { isNil } from 'lodash-es';
import {
FaceDirection,
IDataCommon,
IMoverController,
IObjectMover,
IRoleFaceBinder
} from '../common';
} from '@user/data-common';
import { IDynamicLayer, IDynamicTile } from './types';
import { DynamicTileMover } from './mover';
export class DynamicTile implements IDynamicTile {
readonly state: IDataCommon;
readonly mover: IObjectMover<IDynamicTile>;
triggerType: number;
@@ -21,6 +23,7 @@ export class DynamicTile implements IDynamicTile {
public y: number,
public readonly layer: IDynamicLayer
) {
this.state = layer.state;
this.mover = new DynamicTileMover(this);
this.triggerType = -1;
}
@@ -11,7 +11,7 @@ import {
IMapLayerHookController,
IMapLayerHooks
} from './types';
import { ITileStore } from '../store';
import { IDataCommon, ITileStore } from '@user/data-common';
import { MapLayer } from './mapLayer';
export class LayerState
@@ -39,6 +39,7 @@ export class LayerState
private dirty: boolean = false;
constructor(
public readonly state: IDataCommon,
public readonly tileStore: ITileStore,
public width: number,
public height: number
@@ -52,6 +53,7 @@ export class LayerState
array,
this.width,
this.height,
this,
this.tileStore
);
this.layerList.add(layer);
+6 -1
View File
@@ -1,6 +1,7 @@
import { isNil } from 'lodash-es';
import {
IDynamicLayer,
ILayerState,
IMapLayer,
IMapLayerData,
IMapLayerHookController,
@@ -8,7 +9,7 @@ import {
} from './types';
import { Hookable, HookController, logger } from '@motajs/common';
import { DynamicLayer } from './dynamicLayer';
import { ITileStore } from '../store';
import { IDataCommon, ITileStore } from '@user/data-common';
// todo: 提供 core.setBlock 等方法的替代方法,同时添加 setBlockList,以及前景背景的接口
@@ -16,6 +17,8 @@ export class MapLayer
extends Hookable<IMapLayerHooks, IMapLayerHookController>
implements IMapLayer
{
readonly state: IDataCommon;
width: number;
height: number;
empty: boolean = true;
@@ -34,9 +37,11 @@ export class MapLayer
array: Uint32Array,
width: number,
height: number,
public readonly layerState: ILayerState,
private readonly tileStore: ITileStore
) {
super();
this.state = layerState.state;
this.width = width;
this.height = height;
const area = width * height;
+7 -4
View File
@@ -1,6 +1,6 @@
import { logger } from '@motajs/common';
import { SaveCompression } from '../common';
import { ITileStore } from '../store';
import { IDataCommon, SaveCompression } from '@user/data-common';
import { ITileStore } from '@user/data-common';
import {
ILayerState,
ILayerStateSave,
@@ -32,7 +32,10 @@ export class MapStore implements IMapStore {
/** 自动分区激活器开关 */
private autoActivitorEnabled: boolean = false;
constructor(private readonly tileStore: ITileStore) {}
constructor(
private readonly tileStore: ITileStore,
public readonly state: IDataCommon
) {}
//#region 楼层管理
@@ -42,7 +45,7 @@ export class MapStore implements IMapStore {
} else {
this.maps.push(id);
}
const state = new LayerState(this.tileStore, width, height);
const state = new LayerState(this.state, this.tileStore, width, height);
// 若 refData 已存在,新楼层直接视为全脏
if (this.refData !== null) {
state.setDirty(true);
+4 -2
View File
@@ -4,8 +4,9 @@ import {
ObjectMover,
ObjectMoveStep,
ObjectMoveStepType
} from '../common';
} from '@user/data-common';
import { IDynamicTile } from './types';
import { DYNAMIC_MOVER_FACE } from '../shared';
//#region 动态图块
@@ -16,7 +17,8 @@ const enum DynamicMoveCode {
export class DynamicTileMover extends ObjectMover<IDynamicTile> {
constructor(public readonly tile: IDynamicTile) {
super();
const face = tile.state.faceManager;
super(face.get(DYNAMIC_MOVER_FACE)!);
}
protected onMoveStart(): Promise<void> {
+16 -10
View File
@@ -1,13 +1,14 @@
import { IHookable, IHookBase, IHookController } from '@motajs/common';
import {
FaceDirection,
IDataCommonExtended,
IMoverController,
IObjectMovable,
IObjectMover,
IRoleFaceBinder,
ISaveableContent
} from '../common';
import { ITileStore } from '../store';
} from '@user/data-common';
import { ITileStore } from '@user/data-common';
//#region 静态图层
@@ -69,10 +70,10 @@ export interface IMapLayerHookController extends IHookController<IMapLayerHooks>
getMapData(): Readonly<IMapLayerData>;
}
export interface IMapLayer extends IHookable<
IMapLayerHooks,
IMapLayerHookController
> {
export interface IMapLayer
extends
IHookable<IMapLayerHooks, IMapLayerHookController>,
IDataCommonExtended {
/** 地图宽度 */
readonly width: number;
/** 地图高度 */
@@ -85,6 +86,8 @@ export interface IMapLayer extends IHookable<
/** 图层纵深 */
readonly zIndex: number;
/** 当前图层所属的地图状态对象 */
readonly layerState: ILayerState;
/** 此图层对应的动态图块图层,z 层级与静态图块一致 */
readonly dynamicLayer: IDynamicLayer;
@@ -261,7 +264,8 @@ export interface ILayerStateHooks extends IHookBase {
onResizeLayer(layer: IMapLayer, width: number, height: number): void;
}
export interface ILayerState extends IHookable<ILayerStateHooks> {
export interface ILayerState
extends IHookable<ILayerStateHooks>, IDataCommonExtended {
/** 地图列表 */
readonly layerList: Set<IMapLayer>;
/** 当前楼层共享的图块定义 store */
@@ -395,7 +399,8 @@ export interface IMapAreaInterval {
export type MapArea = IMapAreaInterval[];
export interface IMapStore extends ISaveableContent<IMapStoreSave> {
export interface IMapStore
extends ISaveableContent<IMapStoreSave>, IDataCommonExtended {
/** 所有楼层的 id 有序数组 */
readonly maps: ReadonlyArray<string>;
@@ -524,7 +529,8 @@ export interface IDynamicLayerHooks extends IHookBase {
onUpdateTilePosition(tile: IDynamicTile, layer: IDynamicLayer): void;
}
export interface IDynamicLayer extends IHookable<IDynamicLayerHooks> {
export interface IDynamicLayer
extends IHookable<IDynamicLayerHooks>, IDataCommonExtended {
/** 当前动态图层所属的静态图层 */
readonly layer: IMapLayer;
@@ -598,7 +604,7 @@ export interface IDynamicLayer extends IHookable<IDynamicLayerHooks> {
updateDynamicTile(tile: IDynamicTile): void;
}
export interface IDynamicTile extends IObjectMovable {
export interface IDynamicTile extends IObjectMovable, IDataCommonExtended {
/** 当前图块数字 */
readonly num: number;
/** 当前动态图块携带的触发器类型,-1 表示无触发器 */
+4
View File
@@ -0,0 +1,4 @@
import { FaceGroup } from '@user/data-common';
/** 动态图块所使用的默认移动组,不知道干什么的就别动 */
export const DYNAMIC_MOVER_FACE = FaceGroup.Dir8;
@@ -1,2 +0,0 @@
export * from './tileStore';
export * from './types';
@@ -1,86 +0,0 @@
import { isNil } from 'lodash-es';
import { logger } from '@motajs/common';
import {
ITileLegacyConverter,
ITileRawData,
ITileStore,
TileType
} from './types';
export class TileStore<TLegacy = unknown> implements ITileStore<TLegacy> {
/** 以图块数字为键的原始图块定义表 */
private readonly dataMap: Map<number, ITileRawData> = new Map();
/** 由图块 id 反查图块数字的映射表 */
private readonly idMap: Map<string, number> = new Map();
/** 由图块数字反查图块 id 的映射表 */
private readonly numMap: Map<number, string> = new Map();
/** 当前挂载的旧样板图块转换器 */
private legacyConverter: ITileLegacyConverter<TLegacy> | null = null;
getData(num: number): ITileRawData | null {
return this.dataMap.get(num) ?? null;
}
getTrigger(num: number): number {
return this.dataMap.get(num)?.trigger ?? -1;
}
getType(num: number): TileType {
return this.dataMap.get(num)?.type ?? TileType.Unknown;
}
addTile(data: ITileRawData): void {
const oldData = this.dataMap.get(data.num);
const oldNum = this.idMap.get(data.id);
if (oldData) {
logger.warn(133, data.num.toString(), oldData.id);
this.deleteBy(oldData.num, oldData.id);
}
if (!isNil(oldNum) && oldNum !== data.num) {
logger.warn(134, data.id, oldNum.toString());
const oldIdData = this.dataMap.get(oldNum);
if (oldIdData) {
this.deleteBy(oldIdData.num, oldIdData.id);
} else {
this.idMap.delete(data.id);
this.numMap.delete(oldNum);
}
}
this.dataMap.set(data.num, data);
this.idMap.set(data.id, data.num);
this.numMap.set(data.num, data.id);
}
idToNumber(id: string): number | null {
return this.idMap.get(id) ?? null;
}
numberToId(num: number): string | null {
return this.numMap.get(num) ?? null;
}
attachLegacyConverter(converter: ITileLegacyConverter<TLegacy>): void {
this.legacyConverter = converter;
}
fromLegacy(num: number, legacy: TLegacy): ITileRawData {
const converter = this.legacyConverter;
if (!converter) {
logger.error(56);
throw new Error('Expected a tile legacy converter');
}
const data = converter.fromLegacy(num, legacy);
this.addTile(data);
return data;
}
/** 删除一组旧的图块定义及其双向索引 */
private deleteBy(num: number, id: string): void {
this.dataMap.delete(num);
this.idMap.delete(id);
this.numMap.delete(num);
}
}
@@ -1,91 +0,0 @@
export const enum TileType {
/** 未知或尚未归类的图块 */
Unknown,
/** 空白图块 */
None,
/** 地形类图块 */
Terrain,
/** 动画类图块 */
Animate,
/** 道具类图块 */
Item,
/** 怪物类图块 */
Enemy,
/** NPC 类图块 */
Npc,
/** 自动元件 */
Autotile,
/** Tileset 切片图块 */
Tileset
}
export interface ITileRawData {
/** 图块数字 */
readonly num: number;
/** 图块字符串 id */
readonly id: string;
/** 默认触发器类型 */
readonly trigger: number;
/** 图块逻辑类型 */
readonly type: TileType;
}
export interface ITileLegacyConverter<TLegacy> {
/**
* 将旧样板图块定义转换为新的图块原始数据
* @param num 图块数字
* @param legacy 旧样板图块定义
*/
fromLegacy(num: number, legacy: TLegacy): ITileRawData;
}
export interface ITileStore<TLegacy = unknown> {
/**
* 获取指定图块数字对应的完整原始定义
* @param num 图块数字
*/
getData(num: number): ITileRawData | null;
/**
* 获取指定图块数字对应的默认触发器类型
* @param num 图块数字
*/
getTrigger(num: number): number;
/**
* 获取指定图块数字对应的图块类型
* @param num 图块数字
*/
getType(num: number): TileType;
/**
* 添加一个图块定义;若 `num` 或 `id` 冲突则警告并覆盖
* @param data 图块原始定义
*/
addTile(data: ITileRawData): void;
/**
* 根据图块 id 查询对应图块数字
* @param id 图块 id
*/
idToNumber(id: string): number | null;
/**
* 根据图块数字查询对应图块 id
* @param num 图块数字
*/
numberToId(num: number): string | null;
/**
* 挂载一个旧样板转换器
* @param converter 旧样板转换器
*/
attachLegacyConverter(converter: ITileLegacyConverter<TLegacy>): void;
/**
* 使用当前转换器转换并写入一个旧样板图块定义
* @param num 图块数字
* @param legacy 旧样板图块定义
*/
fromLegacy(num: number, legacy: TLegacy): ITileRawData;
}
+2 -10
View File
@@ -1,23 +1,15 @@
import { IHeroFollower, IHeroState } from './hero';
import { IEnemyManager } from './enemy';
import { IFlagSystem } from './flag';
import { IFaceManager, IRoleFaceBinder, ISaveableContent } from './common';
import { IMapStore } from './map';
import { ITileStore } from './store';
import { IDataCommon, ISaveableContent } from '@user/data-common';
export interface IStateSaveData {
/** 跟随者列表 */
readonly followers: readonly IHeroFollower[];
}
export interface IStateBase<TEnemy, THero> {
/** 朝向绑定 */
readonly roleFace: IRoleFaceBinder;
/** 朝向管理 */
readonly faceManager: IFaceManager;
/** 图块定义存储 */
readonly tileStore: ITileStore;
export interface IStateBase<TEnemy, THero> extends IDataCommon {
/** 地图状态 */
readonly maps: IMapStore;
/** 勇士状态 */