mirror of
https://github.com/unanmed/HumanBreak.git
synced 2026-11-13 09:25:59 +08:00
refactor: 地图渲染器改为与 LayerState 绑定
This commit is contained in:
1 parent
6ae0d6ca5f
commit
ebaa35ea5b
17 files changed
+564
-387
No files matched your search
@@ -1,18 +1,43 @@
|
||||
import { logger } from '@motajs/common';
|
||||
import { IMapLayer, MapLayer } from '../map';
|
||||
import { ILayerState } from './types';
|
||||
import {
|
||||
Hookable,
|
||||
HookController,
|
||||
IHookController,
|
||||
logger
|
||||
} from '@motajs/common';
|
||||
import {
|
||||
IMapLayer,
|
||||
IMapLayerHookController,
|
||||
IMapLayerHooks,
|
||||
MapLayer
|
||||
} from '../map';
|
||||
import { ILayerState, ILayerStateHooks } from './types';
|
||||
|
||||
export class LayerState implements ILayerState {
|
||||
readonly layerList: WeakSet<IMapLayer> = new WeakSet();
|
||||
export class LayerState
|
||||
extends Hookable<ILayerStateHooks>
|
||||
implements ILayerState
|
||||
{
|
||||
readonly layerList: Set<IMapLayer> = new Set();
|
||||
/** 图层到图层别名映射 */
|
||||
readonly layerAliasMap: WeakMap<IMapLayer, string> = new WeakMap();
|
||||
/** 图层别名到图层的映射 */
|
||||
readonly aliasLayerMap: Map<symbol, IMapLayer> = new Map();
|
||||
|
||||
/** 背景图块 */
|
||||
private backgroundTile: number = 0;
|
||||
|
||||
/** 图层钩子映射 */
|
||||
private layerHookMap: Map<IMapLayer, IMapLayerHookController> = new Map();
|
||||
|
||||
addLayer(width: number, height: number): IMapLayer {
|
||||
const array = new Uint32Array(width * height);
|
||||
const layer = new MapLayer(array, width, height);
|
||||
this.layerList.add(layer);
|
||||
this.forEachHook((hook, controller) => {
|
||||
hook.onUpdateLayer?.(controller, this.layerList);
|
||||
});
|
||||
const controller = layer.addHook(new StateMapLayerHook(this));
|
||||
this.layerHookMap.set(layer, controller);
|
||||
controller.load();
|
||||
return layer;
|
||||
}
|
||||
|
||||
@@ -24,6 +49,17 @@ export class LayerState implements ILayerState {
|
||||
this.aliasLayerMap.delete(symbol);
|
||||
this.layerAliasMap.delete(layer);
|
||||
}
|
||||
this.forEachHook((hook, controller) => {
|
||||
hook.onUpdateLayer?.(controller, this.layerList);
|
||||
});
|
||||
const controller = this.layerHookMap.get(layer);
|
||||
if (!controller) return;
|
||||
controller.unload();
|
||||
this.layerHookMap.delete(layer);
|
||||
}
|
||||
|
||||
hasLayer(layer: IMapLayer): boolean {
|
||||
return this.layerList.has(layer);
|
||||
}
|
||||
|
||||
setLayerAlias(layer: IMapLayer, alias: string): void {
|
||||
@@ -57,4 +93,58 @@ export class LayerState implements ILayerState {
|
||||
layer.resize2(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
setBackground(tile: number): void {
|
||||
this.backgroundTile = tile;
|
||||
this.forEachHook((hook, controller) => {
|
||||
hook.onChangeBackground?.(controller, tile);
|
||||
});
|
||||
}
|
||||
|
||||
getBackground(): number {
|
||||
return this.backgroundTile;
|
||||
}
|
||||
|
||||
protected createController(
|
||||
hook: Partial<ILayerStateHooks>
|
||||
): IHookController<ILayerStateHooks> {
|
||||
return new HookController(this, hook);
|
||||
}
|
||||
}
|
||||
|
||||
class StateMapLayerHook implements Partial<IMapLayerHooks> {
|
||||
constructor(readonly state: LayerState) {}
|
||||
|
||||
onUpdateArea(
|
||||
controller: IMapLayerHookController,
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number
|
||||
): void {
|
||||
this.state.forEachHook((hook, c) => {
|
||||
hook.onUpdateLayerArea?.(c, controller.layer, x, y, width, height);
|
||||
});
|
||||
}
|
||||
|
||||
onUpdateBlock(
|
||||
controller: IMapLayerHookController,
|
||||
block: number,
|
||||
x: number,
|
||||
y: number
|
||||
): void {
|
||||
this.state.forEachHook((hook, c) => {
|
||||
hook.onUpdateLayerBlock?.(c, controller.layer, block, x, y);
|
||||
});
|
||||
}
|
||||
|
||||
onResize(
|
||||
controller: IMapLayerHookController,
|
||||
width: number,
|
||||
height: number
|
||||
): void {
|
||||
this.state.forEachHook((hook, c) => {
|
||||
hook.onResizeLayer?.(c, controller.layer, width, height);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,76 @@
|
||||
import { IHookable, IHookBase, IHookController } from '@motajs/common';
|
||||
import { IMapLayer } from '../map';
|
||||
|
||||
export interface ILayerState {
|
||||
export interface ILayerStateHooks extends IHookBase {
|
||||
/**
|
||||
* 当设置背景图块时执行,如果设置的背景图块与原先一样,则不会执行
|
||||
* @param controller 钩子控制器
|
||||
* @param tile 背景图块
|
||||
*/
|
||||
onChangeBackground(controller: IHookController<this>, tile: number): void;
|
||||
|
||||
/**
|
||||
* 当地图列表发生变化时执行
|
||||
* @param controller 钩子控制器
|
||||
* @param layerList 地图图层列表
|
||||
*/
|
||||
onUpdateLayer(
|
||||
controller: IHookController<this>,
|
||||
layerList: Set<IMapLayer>
|
||||
): void;
|
||||
|
||||
/**
|
||||
* 当地图状态对象的某个图层发生区域更新时执行
|
||||
* @param controller 钩子控制器
|
||||
* @param layer 触发更新的地图图层对象
|
||||
* @param x 更新区域左上角横坐标
|
||||
* @param y 更新区域左上角纵坐标
|
||||
* @param width 更新区域宽度
|
||||
* @param height 更新区域高度
|
||||
*/
|
||||
onUpdateLayerArea(
|
||||
controller: IHookController<this>,
|
||||
layer: IMapLayer,
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number
|
||||
): void;
|
||||
|
||||
/**
|
||||
* 当地图状态对象的某个图层设置图块时执行,如果设置的图块与原先一样则不会触发
|
||||
* @param controller 钩子控制器
|
||||
* @param layer 触发更新的地图图层对象
|
||||
* @param block 设置为的图块
|
||||
* @param x 图块横坐标
|
||||
* @param y 图块纵坐标
|
||||
*/
|
||||
onUpdateLayerBlock(
|
||||
controller: IHookController<this>,
|
||||
layer: IMapLayer,
|
||||
block: number,
|
||||
x: number,
|
||||
y: number
|
||||
): void;
|
||||
|
||||
/**
|
||||
* 当地图状态对象的某个图层大小发生变化时执行
|
||||
* @param controller 钩子控制器
|
||||
* @param layer 触发更新的地图图层对象
|
||||
* @param width 地图的新宽度
|
||||
* @param height 地图的新高度
|
||||
*/
|
||||
onResizeLayer(
|
||||
controller: IHookController<this>,
|
||||
layer: IMapLayer,
|
||||
width: number,
|
||||
height: number
|
||||
): void;
|
||||
}
|
||||
|
||||
export interface ILayerState extends IHookable<ILayerStateHooks> {
|
||||
/** 地图列表 */
|
||||
readonly layerList: WeakSet<IMapLayer>;
|
||||
readonly layerList: Set<IMapLayer>;
|
||||
|
||||
/**
|
||||
* 添加图层
|
||||
@@ -17,6 +85,12 @@ export interface ILayerState {
|
||||
*/
|
||||
removeLayer(layer: IMapLayer): void;
|
||||
|
||||
/**
|
||||
* 当前地图状态对象是否包含指定图层对象
|
||||
* @param layer 图层对象
|
||||
*/
|
||||
hasLayer(layer: IMapLayer): boolean;
|
||||
|
||||
/**
|
||||
* 设置图层别名
|
||||
* @param layer 图层对象
|
||||
@@ -49,6 +123,17 @@ export interface ILayerState {
|
||||
height: number,
|
||||
keepBlock?: boolean
|
||||
): void;
|
||||
|
||||
/**
|
||||
* 设置背景图块
|
||||
* @param tile 背景图块数字
|
||||
*/
|
||||
setBackground(tile: number): void;
|
||||
|
||||
/**
|
||||
* 获取背景图块数字,如果没有设置过,则返回 0
|
||||
*/
|
||||
getBackground(): number;
|
||||
}
|
||||
|
||||
export interface ICoreState {
|
||||
|
||||
@@ -2,25 +2,19 @@ import { isNil } from 'lodash-es';
|
||||
import {
|
||||
IMapLayer,
|
||||
IMapLayerData,
|
||||
IMapLayerExtends,
|
||||
IMapLayerExtendsController
|
||||
IMapLayerHookController,
|
||||
IMapLayerHooks
|
||||
} from './types';
|
||||
import { logger } from '@motajs/common';
|
||||
import { Hookable, HookController, logger } from '@motajs/common';
|
||||
|
||||
interface IExtendsData {
|
||||
readonly ex: IMapLayerExtends;
|
||||
readonly controller: IMapLayerExtendsController;
|
||||
}
|
||||
|
||||
export class MapLayer implements IMapLayer {
|
||||
export class MapLayer
|
||||
extends Hookable<IMapLayerHooks, IMapLayerHookController>
|
||||
implements IMapLayer
|
||||
{
|
||||
width: number;
|
||||
height: number;
|
||||
empty: boolean = true;
|
||||
|
||||
/** 已经加载完毕的图层拓展 */
|
||||
private loadedExtends: Set<IExtendsData> = new Set();
|
||||
/** 添加的图层拓展 */
|
||||
private addedExtends: Map<string, IExtendsData> = new Map();
|
||||
zIndex: number = 0;
|
||||
|
||||
/** 地图图块数组 */
|
||||
private mapArray: Uint32Array;
|
||||
@@ -28,6 +22,7 @@ export class MapLayer implements IMapLayer {
|
||||
private mapData: IMapLayerData;
|
||||
|
||||
constructor(array: Uint32Array, width: number, height: number) {
|
||||
super();
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
const area = width * height;
|
||||
@@ -42,9 +37,6 @@ export class MapLayer implements IMapLayer {
|
||||
|
||||
resize(width: number, height: number): void {
|
||||
if (this.width === width && this.height === height) {
|
||||
this.loadedExtends.forEach(v => {
|
||||
v.ex.onResize?.(v.controller, width, height);
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.mapData.expired = true;
|
||||
@@ -78,17 +70,14 @@ export class MapLayer implements IMapLayer {
|
||||
expired: false,
|
||||
array: this.mapArray
|
||||
};
|
||||
this.loadedExtends.forEach(v => {
|
||||
v.ex.onResize?.(v.controller, width, height);
|
||||
this.forEachHook((hook, controller) => {
|
||||
hook.onResize?.(controller, width, height);
|
||||
});
|
||||
}
|
||||
|
||||
resize2(width: number, height: number): void {
|
||||
if (this.width === width && this.height === height) {
|
||||
this.mapArray.fill(0);
|
||||
this.loadedExtends.forEach(v => {
|
||||
v.ex.onResize?.(v.controller, width, height);
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.mapData.expired = true;
|
||||
@@ -99,17 +88,18 @@ export class MapLayer implements IMapLayer {
|
||||
expired: false,
|
||||
array: this.mapArray
|
||||
};
|
||||
this.loadedExtends.forEach(v => {
|
||||
v.ex.onResize?.(v.controller, width, height);
|
||||
});
|
||||
this.empty = true;
|
||||
this.forEachHook((hook, controller) => {
|
||||
hook.onResize?.(controller, width, height);
|
||||
});
|
||||
}
|
||||
|
||||
setBlock(block: number, x: number, y: number): void {
|
||||
const index = y * this.width + x;
|
||||
if (block === this.mapArray[index]) return;
|
||||
this.mapArray[index] = block;
|
||||
this.loadedExtends.forEach(v => {
|
||||
v.ex.onUpdateBlock?.(v.controller, block, x, y);
|
||||
this.forEachHook((hook, controller) => {
|
||||
hook.onUpdateBlock?.(controller, block, x, y);
|
||||
});
|
||||
if (block !== 0) {
|
||||
this.empty = false;
|
||||
@@ -131,8 +121,8 @@ export class MapLayer implements IMapLayer {
|
||||
const height = Math.ceil(array.length / width);
|
||||
if (width === this.width && height === this.height) {
|
||||
this.mapArray.set(array);
|
||||
this.loadedExtends.forEach(v => {
|
||||
v.ex.onUpdateArea?.(v.controller, x, y, width, height);
|
||||
this.forEachHook((hook, controller) => {
|
||||
hook.onUpdateArea?.(controller, x, y, width, height);
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -159,8 +149,8 @@ export class MapLayer implements IMapLayer {
|
||||
}
|
||||
this.mapArray.set(array.subarray(start, start + nw), offset);
|
||||
}
|
||||
this.loadedExtends.forEach(v => {
|
||||
v.ex.onUpdateArea?.(v.controller, x, y, width, height);
|
||||
this.forEachHook((hook, controller) => {
|
||||
hook.onUpdateArea?.(controller, x, y, width, height);
|
||||
});
|
||||
this.empty &&= empty;
|
||||
}
|
||||
@@ -213,51 +203,32 @@ export class MapLayer implements IMapLayer {
|
||||
return this.mapData;
|
||||
}
|
||||
|
||||
loadExtends(ex: IMapLayerExtends): boolean {
|
||||
if (!this.addedExtends.has(ex.id)) return false;
|
||||
ex.awake?.();
|
||||
const data = this.addedExtends.get(ex.id)!;
|
||||
this.loadedExtends.add(data);
|
||||
return true;
|
||||
protected createController(
|
||||
hook: Partial<IMapLayerHooks>
|
||||
): IMapLayerHookController {
|
||||
return new MapLayerHookController(this, hook);
|
||||
}
|
||||
|
||||
addExtends(ex: IMapLayerExtends): IMapLayerExtendsController {
|
||||
const controller = new MapLayerExtendsController(this, ex);
|
||||
this.addedExtends.set(ex.id, {
|
||||
ex,
|
||||
controller
|
||||
});
|
||||
return controller;
|
||||
}
|
||||
|
||||
removeExtends(ex: IMapLayerExtends | string): void {
|
||||
const id = typeof ex === 'string' ? ex : ex.id;
|
||||
const data = this.addedExtends.get(id);
|
||||
if (!data) return;
|
||||
data.ex.destroy?.();
|
||||
this.addedExtends.delete(id);
|
||||
this.loadedExtends.delete(data);
|
||||
setZIndex(zIndex: number): void {
|
||||
this.zIndex = zIndex;
|
||||
}
|
||||
}
|
||||
|
||||
class MapLayerExtendsController implements IMapLayerExtendsController {
|
||||
loaded: boolean = false;
|
||||
class MapLayerHookController
|
||||
extends HookController<IMapLayerHooks>
|
||||
implements IMapLayerHookController
|
||||
{
|
||||
hookable: MapLayer;
|
||||
|
||||
constructor(
|
||||
readonly layer: MapLayer,
|
||||
readonly ex: IMapLayerExtends
|
||||
) {}
|
||||
|
||||
load(): void {
|
||||
this.loaded = this.layer.loadExtends(this.ex);
|
||||
hook: Partial<IMapLayerHooks>
|
||||
) {
|
||||
super(layer, hook);
|
||||
this.hookable = layer;
|
||||
}
|
||||
|
||||
getMapData(): Readonly<IMapLayerData> {
|
||||
return this.layer.getMapRef();
|
||||
}
|
||||
|
||||
unload(): void {
|
||||
this.layer.removeExtends(this.ex);
|
||||
this.loaded = false;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import { IHookable, IHookBase, IHookController } from '@motajs/common';
|
||||
|
||||
export interface IMapLayerData {
|
||||
/** 当前引用是否过期,当地图图层内部的地图数组引用更新时,此项会变为 `true` */
|
||||
expired: boolean;
|
||||
@@ -5,26 +7,15 @@ export interface IMapLayerData {
|
||||
array: Uint32Array;
|
||||
}
|
||||
|
||||
export interface IMapLayerHooks {
|
||||
export interface IMapLayerHooks extends IHookBase {
|
||||
/**
|
||||
* 当钩子准备完毕时执行,会自动分析依赖,并把依赖实例作为参数传入,遵循依赖列表的顺序
|
||||
* @param dependencies 依赖列表
|
||||
*/
|
||||
awake(): void;
|
||||
|
||||
/**
|
||||
* 当拓展被移除之前执行,可以用来清理相关内容
|
||||
*/
|
||||
destroy(): void;
|
||||
|
||||
/**
|
||||
* 当地图大小发生变化时执行
|
||||
* 当地图大小发生变化时执行,如果调用了地图的 `resize` 方法,但是地图大小没变,则不会触发
|
||||
* @param controller 拓展控制器
|
||||
* @param width 地图宽度
|
||||
* @param height 地图高度
|
||||
*/
|
||||
onResize(
|
||||
controller: IMapLayerExtendsController,
|
||||
controller: IMapLayerHookController,
|
||||
width: number,
|
||||
height: number
|
||||
): void;
|
||||
@@ -38,7 +29,7 @@ export interface IMapLayerHooks {
|
||||
* @param height 更新区域高度
|
||||
*/
|
||||
onUpdateArea(
|
||||
controller: IMapLayerExtendsController,
|
||||
controller: IMapLayerHookController,
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
@@ -53,47 +44,37 @@ export interface IMapLayerHooks {
|
||||
* @param y 更新点纵坐标
|
||||
*/
|
||||
onUpdateBlock(
|
||||
controller: IMapLayerExtendsController,
|
||||
controller: IMapLayerHookController,
|
||||
block: number,
|
||||
x: number,
|
||||
y: number
|
||||
): void;
|
||||
}
|
||||
|
||||
export interface IMapLayerExtends extends Partial<IMapLayerHooks> {
|
||||
/** 这个拓展对象的标识符 */
|
||||
readonly id: string;
|
||||
}
|
||||
|
||||
export interface IMapLayerExtendsController {
|
||||
/** 当前图层拓展是否已经被加载 */
|
||||
readonly loaded: boolean;
|
||||
export interface IMapLayerHookController
|
||||
extends IHookController<IMapLayerHooks> {
|
||||
/** 拓展所属的图层对象 */
|
||||
readonly layer: IMapLayer;
|
||||
|
||||
/**
|
||||
* 加载此图层拓展,如果拓展依赖了其他拓展并且已经添加,将会自动加载其他拓展
|
||||
*/
|
||||
load(): void;
|
||||
|
||||
/**
|
||||
* 获取地图数据,是对内部存储的直接引用
|
||||
*/
|
||||
getMapData(): Readonly<IMapLayerData>;
|
||||
|
||||
/**
|
||||
* 结束此拓展的生命周期,释放相关资源
|
||||
*/
|
||||
unload(): void;
|
||||
}
|
||||
|
||||
export interface IMapLayer {
|
||||
export interface IMapLayer
|
||||
extends IHookable<IMapLayerHooks, IMapLayerHookController> {
|
||||
/** 地图宽度 */
|
||||
readonly width: number;
|
||||
/** 地图高度 */
|
||||
readonly height: number;
|
||||
/** 地图是否全部空白,此值具有保守性,即如果其为 `true`,则地图一定空白,但是如果其为 `false`,那么地图也有可能空白 */
|
||||
/**
|
||||
* 地图是否全部空白,此值具有充分性,但不具有必要性,
|
||||
* 即如果其为 `true`,则地图一定空白,但是如果其为 `false`,那么地图也有可能空白
|
||||
*/
|
||||
readonly empty: boolean;
|
||||
/** 图层纵深 */
|
||||
readonly zIndex: number;
|
||||
|
||||
/**
|
||||
* 调整地图尺寸,维持原有图块。如果尺寸变大,那么会补零,如果尺寸变小,那么会将当前数组裁剪
|
||||
@@ -153,15 +134,13 @@ export interface IMapLayer {
|
||||
): Uint32Array;
|
||||
|
||||
/**
|
||||
* 添加图层拓展,使用一系列钩子与图层本身通讯。不同图层拓展没有顺序关系。
|
||||
* @param ex 图层拓展对象
|
||||
* @returns 图层拓展控制对象,可以通过它来控制拓展的生命周期,也可以用于获取图层内的一些数据
|
||||
* 获取整个地图的地图数组,是对内部数组的直接引用
|
||||
*/
|
||||
addExtends(ex: IMapLayerExtends): IMapLayerExtendsController;
|
||||
getMapRef(): IMapLayerData;
|
||||
|
||||
/**
|
||||
* 移除指定的图层拓展对象
|
||||
* @param ex 要移除的图层拓展对象,也可以填拓展对象的标识符
|
||||
* 设置地图纵深,会影响渲染的遮挡顺序
|
||||
* @param zIndex 纵深
|
||||
*/
|
||||
removeExtends(ex: IMapLayerExtends | string): void;
|
||||
setZIndex(zIndex: number): void;
|
||||
}
|
||||
Reference in new issue
Block a user