mirror of
https://github.com/motajs/template.git
synced 2026-07-17 09:21:09 +08:00
feat: 图块信息接口
This commit is contained in:
parent
3e150c4a1d
commit
eb34d63e96
@ -4,14 +4,18 @@ import {
|
||||
IDataCommon,
|
||||
IMoverController,
|
||||
IObjectMover,
|
||||
IRoleFaceBinder
|
||||
IRoleFaceBinder,
|
||||
ITileRawData
|
||||
} from '@user/data-common';
|
||||
import { IDynamicLayer, IDynamicTile } from './types';
|
||||
import { DynamicTileMover } from './mover';
|
||||
import { logger } from '@motajs/common';
|
||||
|
||||
export class DynamicTile implements IDynamicTile {
|
||||
readonly state: IDataCommon;
|
||||
readonly mover: IObjectMover<IDynamicTile>;
|
||||
|
||||
raw: ITileRawData | null;
|
||||
triggerType: number;
|
||||
|
||||
/** 当前的朝向绑定对象 */
|
||||
@ -26,6 +30,13 @@ export class DynamicTile implements IDynamicTile {
|
||||
this.state = layer.state;
|
||||
this.mover = new DynamicTileMover(this);
|
||||
this.triggerType = -1;
|
||||
const data = this.state.tileStore.getData(num);
|
||||
if (!data) {
|
||||
logger.warn(143, num.toString());
|
||||
this.raw = null;
|
||||
} else {
|
||||
this.raw = data;
|
||||
}
|
||||
}
|
||||
|
||||
setFaceBinder(binder: IRoleFaceBinder | null): void {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { isNil } from 'lodash-es';
|
||||
import {
|
||||
IDynamicLayer,
|
||||
ILayerLocation,
|
||||
ILayerState,
|
||||
IMapLayer,
|
||||
IMapLayerData,
|
||||
@ -55,6 +56,10 @@ export class MapLayer
|
||||
this.dynamicLayer = new DynamicLayer(this);
|
||||
}
|
||||
|
||||
inMap(x: number, y: number): boolean {
|
||||
return x >= 0 && y >= 0 && x < this.width && y < this.height;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在地图尺寸变化后重新映射手动触发器覆盖表
|
||||
*/
|
||||
@ -150,15 +155,32 @@ export class MapLayer
|
||||
}
|
||||
|
||||
getBlock(x: number, y: number): number {
|
||||
if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
|
||||
// 不在地图内,返回 -1
|
||||
if (!this.inMap(x, y)) {
|
||||
return -1;
|
||||
}
|
||||
return this.mapArray[y * this.width + x];
|
||||
}
|
||||
|
||||
getLocationData(x: number, y: number): ILayerLocation | null {
|
||||
if (!this.inMap(x, y)) return null;
|
||||
const index = y * this.width + x;
|
||||
const num = this.mapArray[index];
|
||||
const raw = this.state.tileStore.getData(num);
|
||||
const dynamics = this.dynamicLayer.getDynamicTilesAt(x, y);
|
||||
const trigger = this.triggerMap.get(index) ?? -1;
|
||||
|
||||
const data: ILayerLocation = {
|
||||
tile: num,
|
||||
raw,
|
||||
trigger,
|
||||
dynamics
|
||||
};
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
getTriggerType(x: number, y: number): number {
|
||||
if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
|
||||
if (!this.inMap(x, y)) {
|
||||
return -1;
|
||||
}
|
||||
const index = y * this.width + x;
|
||||
@ -169,7 +191,7 @@ export class MapLayer
|
||||
}
|
||||
|
||||
setTriggerType(type: number, x: number, y: number): void {
|
||||
if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
|
||||
if (!this.inMap(x, y)) {
|
||||
return;
|
||||
}
|
||||
const index = y * this.width + x;
|
||||
@ -181,7 +203,7 @@ export class MapLayer
|
||||
}
|
||||
|
||||
revertTrigger(x: number, y: number): void {
|
||||
if (x >= 0 && y >= 0 && x < this.width && y < this.height) {
|
||||
if (this.inMap(x, y)) {
|
||||
this.triggerMap.delete(y * this.width + x);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,8 @@ import {
|
||||
IObjectMovable,
|
||||
IObjectMover,
|
||||
IRoleFaceBinder,
|
||||
ISaveableContent
|
||||
ISaveableContent,
|
||||
ITileRawData
|
||||
} from '@user/data-common';
|
||||
import { ITileStore } from '@user/data-common';
|
||||
|
||||
@ -15,10 +16,21 @@ import { ITileStore } from '@user/data-common';
|
||||
export interface IMapLayerData {
|
||||
/** 当前引用是否过期,当地图图层内部的地图数组引用更新时,此项会变为 `true` */
|
||||
expired: boolean;
|
||||
/** 地图图块数组,是对内部存储的直接引用 */
|
||||
/** 地图图块数组,是对内部存储的直接引用,仅建议读取,不建议修改 */
|
||||
array: Uint32Array;
|
||||
}
|
||||
|
||||
export interface ILayerLocation {
|
||||
/** 该点的静态图块数字 */
|
||||
readonly tile: number;
|
||||
/** 该点的静态图块信息 */
|
||||
readonly raw: ITileRawData | null;
|
||||
/** 该点的静态触发器,-1 表示未设置(即使用图块本身的触发器),否则表示该点的静态触发器,覆盖图块本身的触发器 */
|
||||
readonly trigger: number;
|
||||
/** 该点包含的所有动态图块 */
|
||||
readonly dynamics: Iterable<IDynamicTile>;
|
||||
}
|
||||
|
||||
export interface IMapLayerHooks extends IHookBase {
|
||||
/**
|
||||
* 当地图大小发生变化时执行,如果调用了地图的 `resize` 方法,但是地图大小没变,则不会触发
|
||||
@ -91,6 +103,13 @@ export interface IMapLayer
|
||||
/** 此图层对应的动态图块图层,z 层级与静态图块一致 */
|
||||
readonly dynamicLayer: IDynamicLayer;
|
||||
|
||||
/**
|
||||
* 判断指定坐标是否在地图内
|
||||
* @param x 横坐标
|
||||
* @param y 纵坐标
|
||||
*/
|
||||
inMap(x: number, y: number): boolean;
|
||||
|
||||
/**
|
||||
* 设置某一点的图块
|
||||
* @param block 图块数字
|
||||
@ -107,6 +126,13 @@ export interface IMapLayer
|
||||
*/
|
||||
getBlock(x: number, y: number): number;
|
||||
|
||||
/**
|
||||
* 获取指定点的所有图块信息
|
||||
* @param x 横坐标
|
||||
* @param y 纵坐标
|
||||
*/
|
||||
getLocationData(x: number, y: number): ILayerLocation | null;
|
||||
|
||||
/**
|
||||
* 获取指定点的静态图块对应的有效触发器类型,若手动覆盖不存在则回退到图块默认触发器
|
||||
* @param x 图块横坐标
|
||||
@ -512,21 +538,21 @@ export interface IDynamicLayerHooks extends IHookBase {
|
||||
* @param tile 被创建的动态图块
|
||||
* @param layer 所属的动态图层
|
||||
*/
|
||||
onCreateTile(tile: IDynamicTile, layer: IDynamicLayer): void;
|
||||
onCreateTile?(tile: IDynamicTile, layer: IDynamicLayer): void;
|
||||
|
||||
/**
|
||||
* 当图块被删除时触发
|
||||
* @param tile 被删除的动态图块
|
||||
* @param layer 所属的动态图层
|
||||
*/
|
||||
onDeleteTile(tile: IDynamicTile, layer: IDynamicLayer): Promise<void>;
|
||||
onDeleteTile?(tile: IDynamicTile, layer: IDynamicLayer): Promise<void>;
|
||||
|
||||
/**
|
||||
* 当更新动态图块的位置时触发(包括使用 `mover` 触发的移动)
|
||||
* @param tile 更新位置的图块
|
||||
* @param layer 所属的动态图层
|
||||
*/
|
||||
onUpdateTilePosition(tile: IDynamicTile, layer: IDynamicLayer): void;
|
||||
onUpdateTilePosition?(tile: IDynamicTile, layer: IDynamicLayer): void;
|
||||
}
|
||||
|
||||
export interface IDynamicLayer
|
||||
@ -613,6 +639,8 @@ export interface IDynamicTile extends IObjectMovable, IDataCommonExtended {
|
||||
readonly layer: IDynamicLayer;
|
||||
/** 当前动态图块的移动器 */
|
||||
readonly mover: IObjectMover<IDynamicTile>;
|
||||
/** 当前动态图块的图块数据 */
|
||||
readonly raw: ITileRawData | null;
|
||||
|
||||
/**
|
||||
* 设置图块朝向,会一并修改 {@link num},返回设置后的当前图块数字
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
//#region tile
|
||||
|
||||
export const enum TileType {
|
||||
/** 未知或尚未归类的图块 */
|
||||
Unknown,
|
||||
@ -19,6 +21,26 @@ export const enum TileType {
|
||||
Tileset
|
||||
}
|
||||
|
||||
export const enum PassBit {
|
||||
/** 上方向掩码 */
|
||||
Up = 0b0001,
|
||||
/** 右方向掩码 */
|
||||
Right = 0b0010,
|
||||
/** 下方向掩码 */
|
||||
Down = 0b0100,
|
||||
/** 左方向掩码 */
|
||||
Left = 0b1000
|
||||
}
|
||||
|
||||
export interface ITilePassData {
|
||||
/** 是否仅当图块处在事件层时生效 */
|
||||
readonly onlyEvents: boolean;
|
||||
/** 可以离开的方向 */
|
||||
readonly outPass: number;
|
||||
/** 可以进入的方向 */
|
||||
readonly inPass: number;
|
||||
}
|
||||
|
||||
export interface ITileRawData {
|
||||
/** 图块数字 */
|
||||
readonly num: number;
|
||||
@ -28,6 +50,8 @@ export interface ITileRawData {
|
||||
readonly trigger: number;
|
||||
/** 图块逻辑类型 */
|
||||
readonly type: TileType;
|
||||
/** 图块的通行性对象 */
|
||||
readonly pass: ITilePassData;
|
||||
}
|
||||
|
||||
export interface ITileLegacyConverter<TLegacy> {
|
||||
@ -89,3 +113,5 @@ export interface ITileStore<TLegacy = unknown> {
|
||||
*/
|
||||
fromLegacy(num: number, legacy: TLegacy): ITileRawData;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
@ -17,7 +17,6 @@ import {
|
||||
} from '@user/data-common';
|
||||
import {
|
||||
EnemyManager,
|
||||
HeroMoveController,
|
||||
IEnemyManager,
|
||||
HeroAttribute,
|
||||
HeroState,
|
||||
@ -129,9 +128,8 @@ export class CoreState implements ICoreState {
|
||||
this.maps = new MapStore(tileStore, this);
|
||||
|
||||
// 勇士
|
||||
const heroMover = new HeroMoveController();
|
||||
const heroAttribute = new HeroAttribute(HERO_DEFAULT_ATTRIBUTE);
|
||||
const heroState = new HeroState(heroMover, heroAttribute);
|
||||
const heroState = new HeroState(this, dir8, heroAttribute);
|
||||
this.hero = heroState;
|
||||
|
||||
this.loadProgress = new LoadProgressTotal();
|
||||
|
||||
@ -1,21 +1,14 @@
|
||||
import {
|
||||
ITileLegacyConverter,
|
||||
ITilePassData,
|
||||
ITileRawData,
|
||||
PassBit,
|
||||
TileType
|
||||
} from '@user/data-common';
|
||||
|
||||
export type LegacyTileData = MapDataOf<keyof NumberToId>;
|
||||
|
||||
export class TileLegacyBridge implements ITileLegacyConverter<LegacyTileData> {
|
||||
fromLegacy(num: number, legacy: LegacyTileData): ITileRawData {
|
||||
return {
|
||||
num,
|
||||
id: legacy.id,
|
||||
trigger: -1,
|
||||
type: this.getTileType(num, legacy)
|
||||
};
|
||||
}
|
||||
|
||||
private getTileType(num: number, legacy: LegacyTileData): TileType {
|
||||
if (num === 0) return TileType.None;
|
||||
switch (legacy.cls) {
|
||||
@ -40,4 +33,76 @@ export class TileLegacyBridge implements ITileLegacyConverter<LegacyTileData> {
|
||||
return TileType.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
private getPass(num: number, legacy: LegacyTileData): ITilePassData {
|
||||
if (num === 0) {
|
||||
return {
|
||||
onlyEvents: true,
|
||||
inPass: 0b1111,
|
||||
outPass: 0b1111
|
||||
};
|
||||
} else if (num === 17) {
|
||||
return {
|
||||
onlyEvents: false,
|
||||
inPass: 0b0000,
|
||||
outPass: 0b0000
|
||||
};
|
||||
} else {
|
||||
if (legacy.noPass) {
|
||||
return {
|
||||
onlyEvents: true,
|
||||
inPass: 0b0000,
|
||||
outPass: 0b1111
|
||||
};
|
||||
} else if (legacy.cannotIn && legacy.cannotOut) {
|
||||
let inPass = 0b1111;
|
||||
let outPass = 0b1111;
|
||||
if (legacy.cannotIn.includes('up')) {
|
||||
inPass &= ~PassBit.Up;
|
||||
}
|
||||
if (legacy.cannotIn.includes('right')) {
|
||||
inPass &= ~PassBit.Right;
|
||||
}
|
||||
if (legacy.cannotIn.includes('down')) {
|
||||
inPass &= ~PassBit.Down;
|
||||
}
|
||||
if (legacy.cannotIn.includes('left')) {
|
||||
inPass &= ~PassBit.Left;
|
||||
}
|
||||
if (legacy.cannotOut.includes('up')) {
|
||||
outPass &= ~PassBit.Up;
|
||||
}
|
||||
if (legacy.cannotOut.includes('right')) {
|
||||
outPass &= ~PassBit.Right;
|
||||
}
|
||||
if (legacy.cannotOut.includes('down')) {
|
||||
outPass &= ~PassBit.Down;
|
||||
}
|
||||
if (legacy.cannotOut.includes('left')) {
|
||||
outPass &= ~PassBit.Left;
|
||||
}
|
||||
return {
|
||||
onlyEvents: false,
|
||||
inPass,
|
||||
outPass
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
onlyEvents: true,
|
||||
inPass: 0b1111,
|
||||
outPass: 0b1111
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fromLegacy(num: number, legacy: LegacyTileData): ITileRawData {
|
||||
return {
|
||||
num,
|
||||
id: legacy.id,
|
||||
trigger: -1,
|
||||
type: this.getTileType(num, legacy),
|
||||
pass: this.getPass(num, legacy)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,6 +199,7 @@
|
||||
"139": "Expected $1 binding before start battle flow, but got a null object.",
|
||||
"140": "Different priority of combat script is expected, but got a same one.",
|
||||
"141": "Some issue may occur in binded damage system on combat flow, please check the console.",
|
||||
"142": "Expected a specific tile number after convert id '$1' to number, but got null."
|
||||
"142": "Expected a specific tile number after convert id '$1' to number, but got null.",
|
||||
"143": "Cannot create dynamic tile for $1 since its raw data is not found."
|
||||
}
|
||||
}
|
||||
|
||||
1
src/types/declaration/core.d.ts
vendored
1
src/types/declaration/core.d.ts
vendored
@ -1282,6 +1282,7 @@ interface MapDataOf<T extends keyof NumberToId> {
|
||||
*/
|
||||
cls: ClsOf<NumberToId[T]>;
|
||||
|
||||
noPass?: boolean;
|
||||
bigImage?: ImageIds;
|
||||
faceIds?: Record<Dir, AllIds>;
|
||||
animate?: number;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user