mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-11-27 13:42:58 +08:00
refactor: 地图渲染器改为与 LayerState 绑定
This commit is contained in:
parent
6ae0d6ca5f
commit
ebaa35ea5b
@ -225,9 +225,10 @@ export class AutotileProcessor implements IAutotileProcessor {
|
|||||||
const size = texture.height === 32 * 48 ? 32 : 48;
|
const size = texture.height === 32 * 48 ? 32 : 48;
|
||||||
const index = distinctConnectionMap.get(connection);
|
const index = distinctConnectionMap.get(connection);
|
||||||
if (isNil(index)) return null;
|
if (isNil(index)) return null;
|
||||||
|
const { rect } = texture.render();
|
||||||
return {
|
return {
|
||||||
source: texture.source,
|
source: texture.source,
|
||||||
rect: { x: 0, y: size * index, w: size, h: size }
|
rect: { x: rect.x, y: rect.y + size * index, w: size, h: size }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { Animate } from './animate';
|
|||||||
import { createItemDetail } from './itemDetail';
|
import { createItemDetail } from './itemDetail';
|
||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import { MapRender } from '../map/element';
|
import { MapRender } from '../map/element';
|
||||||
|
import { state } from '@user/data-state';
|
||||||
|
|
||||||
export function createElements() {
|
export function createElements() {
|
||||||
createCache();
|
createCache();
|
||||||
@ -71,14 +72,14 @@ export function createElements() {
|
|||||||
tagMap.register('map-render', (_0, _1, props) => {
|
tagMap.register('map-render', (_0, _1, props) => {
|
||||||
if (!props) {
|
if (!props) {
|
||||||
logger.error(42);
|
logger.error(42);
|
||||||
return new MapRender([]);
|
return new MapRender(state.layer);
|
||||||
}
|
}
|
||||||
const { layerList } = props;
|
const { layerState } = props;
|
||||||
if (!layerList) {
|
if (!layerState) {
|
||||||
logger.error(42);
|
logger.error(42);
|
||||||
return new MapRender([]);
|
return new MapRender(state.layer);
|
||||||
}
|
}
|
||||||
return new MapRender(layerList);
|
return new MapRender(layerState);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import {
|
|||||||
import { EAnimateEvent } from './animate';
|
import { EAnimateEvent } from './animate';
|
||||||
import { EIconEvent, EWinskinEvent } from './misc';
|
import { EIconEvent, EWinskinEvent } from './misc';
|
||||||
import { IEnemyCollection } from '@motajs/types';
|
import { IEnemyCollection } from '@motajs/types';
|
||||||
import { IRenderLayerData } from '../map/element';
|
import { ILayerState } from '@user/data-state';
|
||||||
|
|
||||||
export interface AnimateProps extends BaseProps {}
|
export interface AnimateProps extends BaseProps {}
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ export interface LayerProps extends BaseProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface MapRenderProps extends BaseProps {
|
export interface MapRenderProps extends BaseProps {
|
||||||
layerList: Iterable<IRenderLayerData>;
|
layerState: ILayerState;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module 'vue/jsx-runtime' {
|
declare module 'vue/jsx-runtime' {
|
||||||
|
|||||||
@ -3,26 +3,13 @@ import {
|
|||||||
RenderItem,
|
RenderItem,
|
||||||
Transform
|
Transform
|
||||||
} from '@motajs/render-core';
|
} from '@motajs/render-core';
|
||||||
import { IMapLayer } from '@user/data-state';
|
import { ILayerState, state } from '@user/data-state';
|
||||||
import {
|
import { IMapRenderer, IMapRendererHooks } from './types';
|
||||||
IMapRenderer,
|
|
||||||
IMapRendererExtends,
|
|
||||||
MapTileAlign,
|
|
||||||
MapTileBehavior
|
|
||||||
} from './types';
|
|
||||||
import { MapRenderer } from './renderer';
|
import { MapRenderer } from './renderer';
|
||||||
import { materials } from '@user/client-base';
|
import { materials } from '@user/client-base';
|
||||||
import { ElementNamespace, ComponentInternalInstance } from 'vue';
|
import { ElementNamespace, ComponentInternalInstance } from 'vue';
|
||||||
import { CELL_HEIGHT, CELL_WIDTH, MAP_HEIGHT, MAP_WIDTH } from '../shared';
|
import { CELL_HEIGHT, CELL_WIDTH, MAP_HEIGHT, MAP_WIDTH } from '../shared';
|
||||||
|
import { IHookController } from '@motajs/common';
|
||||||
export interface IRenderLayerData {
|
|
||||||
/** 图层对象 */
|
|
||||||
readonly layer: IMapLayer;
|
|
||||||
/** 图层纵深 */
|
|
||||||
readonly zIndex: number;
|
|
||||||
/** 图层别名 */
|
|
||||||
readonly alias?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MapRender extends RenderItem {
|
export class MapRender extends RenderItem {
|
||||||
/** 地图渲染器 */
|
/** 地图渲染器 */
|
||||||
@ -35,43 +22,31 @@ export class MapRender extends RenderItem {
|
|||||||
/** 画布上下文 */
|
/** 画布上下文 */
|
||||||
readonly gl: WebGL2RenderingContext;
|
readonly gl: WebGL2RenderingContext;
|
||||||
|
|
||||||
constructor(layerList: Iterable<IRenderLayerData>) {
|
private rendererHook: IHookController<IMapRendererHooks>;
|
||||||
|
|
||||||
|
constructor(readonly layerState: ILayerState) {
|
||||||
super('static');
|
super('static');
|
||||||
|
|
||||||
this.canvas = document.createElement('canvas');
|
this.canvas = document.createElement('canvas');
|
||||||
const gl = this.canvas.getContext('webgl2')!;
|
const gl = this.canvas.getContext('webgl2')!;
|
||||||
this.gl = gl;
|
this.gl = gl;
|
||||||
|
|
||||||
this.renderer = new MapRenderer(materials, this.gl, this.camera);
|
this.renderer = new MapRenderer(
|
||||||
for (const layer of layerList) {
|
materials,
|
||||||
this.renderer.addLayer(layer.layer, layer.alias);
|
this.gl,
|
||||||
this.renderer.setZIndex(layer.layer, layer.zIndex);
|
this.camera,
|
||||||
}
|
state.layer
|
||||||
|
);
|
||||||
|
this.renderer.setLayerState(layerState);
|
||||||
this.renderer.useAsset(materials.trackedAsset);
|
this.renderer.useAsset(materials.trackedAsset);
|
||||||
this.renderer.addExtends(new MapUpdateExtends(this));
|
this.rendererHook = this.renderer.addHook(new RendererUpdateHook(this));
|
||||||
|
this.rendererHook.load();
|
||||||
this.renderer.setTileBackground(1);
|
|
||||||
|
|
||||||
this.renderer.setCellSize(CELL_WIDTH, CELL_HEIGHT);
|
this.renderer.setCellSize(CELL_WIDTH, CELL_HEIGHT);
|
||||||
this.renderer.setRenderSize(MAP_WIDTH, MAP_HEIGHT);
|
this.renderer.setRenderSize(MAP_WIDTH, MAP_HEIGHT);
|
||||||
|
|
||||||
gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新图层列表
|
|
||||||
* @param layerList 图层列表
|
|
||||||
*/
|
|
||||||
updateLayerList(layerList: Iterable<IRenderLayerData>) {
|
|
||||||
this.renderer
|
|
||||||
.getSortedLayer()
|
|
||||||
.forEach(v => this.renderer.removeLayer(v));
|
|
||||||
for (const layer of layerList) {
|
|
||||||
this.renderer.addLayer(layer.layer, layer.alias);
|
|
||||||
this.renderer.setZIndex(layer.layer, layer.zIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private sizeGL(width: number, height: number) {
|
private sizeGL(width: number, height: number) {
|
||||||
const ratio = this.highResolution ? devicePixelRatio : 1;
|
const ratio = this.highResolution ? devicePixelRatio : 1;
|
||||||
const scale = ratio * this.scale;
|
const scale = ratio * this.scale;
|
||||||
@ -115,8 +90,8 @@ export class MapRender extends RenderItem {
|
|||||||
parentComponent?: ComponentInternalInstance | null
|
parentComponent?: ComponentInternalInstance | null
|
||||||
): void {
|
): void {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'layerList': {
|
case 'layerState': {
|
||||||
this.updateLayerList(nextValue);
|
this.renderer.setLayerState(nextValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,7 +99,7 @@ export class MapRender extends RenderItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MapUpdateExtends implements IMapRendererExtends {
|
class RendererUpdateHook implements Partial<IMapRendererHooks> {
|
||||||
constructor(readonly element: MapRender) {}
|
constructor(readonly element: MapRender) {}
|
||||||
|
|
||||||
onUpdate(): void {
|
onUpdate(): void {
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import {
|
|||||||
IMapBackgroundConfig,
|
IMapBackgroundConfig,
|
||||||
IMapRenderConfig,
|
IMapRenderConfig,
|
||||||
IMapRenderer,
|
IMapRenderer,
|
||||||
IMapRendererExtends,
|
IMapRendererHooks,
|
||||||
IMapVertexGenerator,
|
IMapVertexGenerator,
|
||||||
IMapViewportController,
|
IMapViewportController,
|
||||||
IMovingBlock,
|
IMovingBlock,
|
||||||
@ -26,13 +26,13 @@ import {
|
|||||||
MapTileBehavior,
|
MapTileBehavior,
|
||||||
MapTileSizeTestMode
|
MapTileSizeTestMode
|
||||||
} from './types';
|
} from './types';
|
||||||
|
import { ILayerState, ILayerStateHooks, IMapLayer } from '@user/data-state';
|
||||||
import {
|
import {
|
||||||
IMapLayer,
|
Hookable,
|
||||||
IMapLayerData,
|
HookController,
|
||||||
IMapLayerExtends,
|
IHookController,
|
||||||
IMapLayerExtendsController
|
logger
|
||||||
} from '@user/data-state';
|
} from '@motajs/common';
|
||||||
import { logger } from '@motajs/common';
|
|
||||||
import { compileProgramWith } from '@motajs/client-base';
|
import { compileProgramWith } from '@motajs/client-base';
|
||||||
import { isNil, maxBy } from 'lodash-es';
|
import { isNil, maxBy } from 'lodash-es';
|
||||||
import { IMapDataGetter, MapVertexGenerator } from './vertex';
|
import { IMapDataGetter, MapVertexGenerator } from './vertex';
|
||||||
@ -57,23 +57,8 @@ const enum BackgroundType {
|
|||||||
Tile
|
Tile
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ILayerRenderData {
|
|
||||||
/** 顶点数组,与总的数组共享 ArrayBuffer */
|
|
||||||
readonly vertexArray: Float32Array;
|
|
||||||
/** 偏移数组,与总的数组共享 ArrayBuffer */
|
|
||||||
readonly offsetArray: Int16Array;
|
|
||||||
|
|
||||||
/** 顶点数组在原数组的起始索引值 */
|
|
||||||
readonly vertexStart: number;
|
|
||||||
/** 顶点数组在原数组的终止索引值 */
|
|
||||||
readonly vertexEnd: number;
|
|
||||||
/** 偏移数组在原数组的起始索引值 */
|
|
||||||
readonly offsetStart: number;
|
|
||||||
/** 偏移数组在原数组的终止索引值 */
|
|
||||||
readonly offsetEnd: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MapRenderer
|
export class MapRenderer
|
||||||
|
extends Hookable<IMapRendererHooks>
|
||||||
implements
|
implements
|
||||||
IMapRenderer,
|
IMapRenderer,
|
||||||
IMovingRenderer,
|
IMovingRenderer,
|
||||||
@ -99,17 +84,10 @@ export class MapRenderer
|
|||||||
assetWidth: number = 4096;
|
assetWidth: number = 4096;
|
||||||
assetHeight: number = 4096;
|
assetHeight: number = 4096;
|
||||||
|
|
||||||
/** 拓展列表 */
|
layerState: ILayerState;
|
||||||
private readonly extendList: Set<IMapRendererExtends> = new Set();
|
/** 地图状态钩子控制器 */
|
||||||
|
private layerStateHook: IHookController<ILayerStateHooks>;
|
||||||
|
|
||||||
/** 这个渲染器添加的图层 */
|
|
||||||
readonly layers: Set<IMapLayer> = new Set();
|
|
||||||
/** 图层的 zIndex 映射 */
|
|
||||||
private layerZIndex: Map<IMapLayer, number> = new Map();
|
|
||||||
/** 图层的别名 */
|
|
||||||
private layerAlias: Map<string, IMapLayer> = new Map();
|
|
||||||
/** 图层到其对应别名的映射 */
|
|
||||||
private layerAliasInv: Map<IMapLayer, string> = new Map();
|
|
||||||
/** 排序后的图层 */
|
/** 排序后的图层 */
|
||||||
private sortedLayers: IMapLayer[] = [];
|
private sortedLayers: IMapLayer[] = [];
|
||||||
/** 图层到排序索引的映射 */
|
/** 图层到排序索引的映射 */
|
||||||
@ -171,14 +149,12 @@ export class MapRenderer
|
|||||||
/** 是否应该更新偏移池 uniform */
|
/** 是否应该更新偏移池 uniform */
|
||||||
private needUpdateOffsetPool: boolean = true;
|
private needUpdateOffsetPool: boolean = true;
|
||||||
|
|
||||||
/** 地图渲染数据 */
|
|
||||||
private layerData: Map<IMapLayer, ILayerRenderData> = new Map();
|
|
||||||
/** 地图拓展映射 */
|
|
||||||
private layerController: Map<IMapLayer, IMapLayerExtendsController>;
|
|
||||||
/** 顶点数组的图层列表是否需要更新 */
|
/** 顶点数组的图层列表是否需要更新 */
|
||||||
private layerDirty: boolean = false;
|
private layerListDirty: boolean = false;
|
||||||
/** 顶点数组的图层的尺寸是否需要更新 */
|
/** 顶点数组的图层的尺寸是否需要更新 */
|
||||||
private layerSizeDirty: boolean = false;
|
private layerSizeDirty: boolean = false;
|
||||||
|
/** 是否整个地图都需要更新,一般只有在地图尺寸等发生变动时才会执行 */
|
||||||
|
private layerAllDirty: boolean = false;
|
||||||
|
|
||||||
/** 所有正在移动的图块 */
|
/** 所有正在移动的图块 */
|
||||||
private movingBlock: Set<IMovingBlock> = new Set();
|
private movingBlock: Set<IMovingBlock> = new Set();
|
||||||
@ -223,8 +199,15 @@ export class MapRenderer
|
|||||||
constructor(
|
constructor(
|
||||||
readonly manager: IMaterialManager,
|
readonly manager: IMaterialManager,
|
||||||
readonly gl: WebGL2RenderingContext,
|
readonly gl: WebGL2RenderingContext,
|
||||||
readonly transform: Transform
|
readonly transform: Transform,
|
||||||
|
layerState: ILayerState
|
||||||
) {
|
) {
|
||||||
|
super();
|
||||||
|
this.layerState = layerState;
|
||||||
|
this.layerStateHook = layerState.addHook(
|
||||||
|
new RendererLayerStateHook(this)
|
||||||
|
);
|
||||||
|
this.layerStateHook.load();
|
||||||
// 上下文初始化要依赖于 offsetPool,因此提前调用
|
// 上下文初始化要依赖于 offsetPool,因此提前调用
|
||||||
const offsetPool = this.getOffsetPool();
|
const offsetPool = this.getOffsetPool();
|
||||||
this.offsetPool = offsetPool;
|
this.offsetPool = offsetPool;
|
||||||
@ -233,7 +216,6 @@ export class MapRenderer
|
|||||||
v => v / data.tileTextureWidth
|
v => v / data.tileTextureWidth
|
||||||
);
|
);
|
||||||
this.contextData = data;
|
this.contextData = data;
|
||||||
this.layerController = new Map();
|
|
||||||
this.vertex = new MapVertexGenerator(this, data);
|
this.vertex = new MapVertexGenerator(this, data);
|
||||||
this.autotile = new AutotileProcessor(manager);
|
this.autotile = new AutotileProcessor(manager);
|
||||||
this.tick = this.tick.bind(this);
|
this.tick = this.tick.bind(this);
|
||||||
@ -242,6 +224,7 @@ export class MapRenderer
|
|||||||
this.viewport.bindTransform(this.transform);
|
this.viewport.bindTransform(this.transform);
|
||||||
this.tileAnimater = new TextureColumnAnimater();
|
this.tileAnimater = new TextureColumnAnimater();
|
||||||
this.initVertexPointer(gl, data);
|
this.initVertexPointer(gl, data);
|
||||||
|
layerState.addHook(new RendererLayerStateHook(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -314,6 +297,12 @@ export class MapRenderer
|
|||||||
gl.bindVertexArray(null);
|
gl.bindVertexArray(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected createController(
|
||||||
|
hook: Partial<IMapRendererHooks>
|
||||||
|
): IHookController<IMapRendererHooks> {
|
||||||
|
return new HookController(this, hook);
|
||||||
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region 图层处理
|
//#region 图层处理
|
||||||
@ -322,82 +311,58 @@ export class MapRenderer
|
|||||||
* 图层排序
|
* 图层排序
|
||||||
*/
|
*/
|
||||||
private sortLayer() {
|
private sortLayer() {
|
||||||
this.sortedLayers = [...this.layers].sort((a, b) => {
|
this.sortedLayers = [...this.layerState.layerList].sort((a, b) => {
|
||||||
const za = this.layerZIndex.get(a) ?? -1;
|
return a.zIndex - b.zIndex;
|
||||||
const zb = this.layerZIndex.get(b) ?? -1;
|
|
||||||
return za - zb;
|
|
||||||
});
|
});
|
||||||
this.sortedLayers.forEach((v, i) => this.layerIndexMap.set(v, i));
|
this.sortedLayers.forEach((v, i) => this.layerIndexMap.set(v, i));
|
||||||
|
this.forEachHook((hook, controller) => {
|
||||||
|
hook.onUpdate?.(controller);
|
||||||
|
});
|
||||||
|
this.layerListDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
addLayer(layer: IMapLayer, identifier?: string): void {
|
private updateAllLayers() {
|
||||||
this.layers.add(layer);
|
this.layerState.layerList.forEach(v => {
|
||||||
this.layerZIndex.set(layer, 0);
|
this.vertex.updateArea(v, 0, 0, v.width, v.height);
|
||||||
if (identifier) {
|
});
|
||||||
this.layerAlias.set(identifier, layer);
|
|
||||||
}
|
|
||||||
const ex = new MapRendererExtends(this);
|
|
||||||
const controller = layer.addExtends(ex);
|
|
||||||
controller.load();
|
|
||||||
this.layerController.set(layer, controller);
|
|
||||||
this.sortLayer();
|
|
||||||
this.layerDirty = true;
|
|
||||||
this.layerCount = this.layers.size;
|
|
||||||
this.resizeLayer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removeLayer(layer: IMapLayer): void {
|
updateLayerList() {
|
||||||
this.layers.delete(layer);
|
|
||||||
this.layerData.delete(layer);
|
|
||||||
this.layerZIndex.delete(layer);
|
|
||||||
const ex = this.layerController.get(layer);
|
|
||||||
if (ex) {
|
|
||||||
ex.unload();
|
|
||||||
}
|
|
||||||
this.layerController.delete(layer);
|
|
||||||
const alias = this.layerAliasInv.get(layer);
|
|
||||||
if (!isNil(alias)) {
|
|
||||||
this.layerAlias.delete(alias);
|
|
||||||
}
|
|
||||||
this.layerAliasInv.delete(layer);
|
|
||||||
this.sortLayer();
|
this.sortLayer();
|
||||||
this.layerDirty = true;
|
|
||||||
this.layerCount = this.layers.size;
|
|
||||||
this.resizeLayer();
|
this.resizeLayer();
|
||||||
|
this.layerCount = this.layerState.layerList.size;
|
||||||
|
this.layerAllDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLayerState(layerState: ILayerState): void {
|
||||||
|
this.layerStateHook.unload();
|
||||||
|
this.layerState = layerState;
|
||||||
|
this.layerStateHook = layerState.addHook(
|
||||||
|
new RendererLayerStateHook(this)
|
||||||
|
);
|
||||||
|
this.layerStateHook.load();
|
||||||
|
this.sortLayer();
|
||||||
|
this.resizeLayer();
|
||||||
|
this.layerCount = layerState.layerList.size;
|
||||||
|
this.layerAllDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getLayer(identifier: string): IMapLayer | null {
|
getLayer(identifier: string): IMapLayer | null {
|
||||||
return this.layerAlias.get(identifier) ?? null;
|
return this.layerState.getLayerByAlias(identifier) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasLayer(layer: IMapLayer): boolean {
|
hasLayer(layer: IMapLayer): boolean {
|
||||||
return this.layers.has(layer);
|
return this.layerState.hasLayer(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSortedLayer(): IMapLayer[] {
|
getSortedLayer(): IMapLayer[] {
|
||||||
return this.sortedLayers.slice();
|
return this.sortedLayers.slice();
|
||||||
}
|
}
|
||||||
|
|
||||||
setZIndex(layer: IMapLayer, zIndex: number): void {
|
|
||||||
this.layerZIndex.set(layer, zIndex);
|
|
||||||
this.sortLayer();
|
|
||||||
this.layerDirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
getZIndex(layer: IMapLayer): number | undefined {
|
|
||||||
return this.layerZIndex.get(layer);
|
|
||||||
}
|
|
||||||
|
|
||||||
getLayerIndex(layer: IMapLayer): number {
|
getLayerIndex(layer: IMapLayer): number {
|
||||||
return this.layerIndexMap.get(layer) ?? -1;
|
return this.layerIndexMap.get(layer) ?? -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
getMapLayerData(layer: IMapLayer): Readonly<IMapLayerData> | null {
|
|
||||||
const ex = this.layerController.get(layer);
|
|
||||||
const data = ex?.getMapData();
|
|
||||||
return data ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重新适应新的图层大小
|
* 重新适应新的图层大小
|
||||||
*/
|
*/
|
||||||
@ -409,13 +374,13 @@ export class MapRenderer
|
|||||||
}
|
}
|
||||||
this.mapWidth = maxWidth;
|
this.mapWidth = maxWidth;
|
||||||
this.mapHeight = maxHeight;
|
this.mapHeight = maxHeight;
|
||||||
this.layerDirty = true;
|
|
||||||
this.updateBackgroundVertex(
|
this.updateBackgroundVertex(
|
||||||
this.gl,
|
this.gl,
|
||||||
this.contextData,
|
this.contextData,
|
||||||
this.contextData.backgroundWidth,
|
this.contextData.backgroundWidth,
|
||||||
this.contextData.backgroundHeight
|
this.contextData.backgroundHeight
|
||||||
);
|
);
|
||||||
|
this.layerAllDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
@ -699,9 +664,9 @@ export class MapRenderer
|
|||||||
tileTextureWidth: 4096,
|
tileTextureWidth: 4096,
|
||||||
tileTextureHeight: 4096,
|
tileTextureHeight: 4096,
|
||||||
tileTextureDepth: 1,
|
tileTextureDepth: 1,
|
||||||
backgroundWidth: 32,
|
backgroundWidth: 0,
|
||||||
backgroundHeight: 32,
|
backgroundHeight: 0,
|
||||||
backgroundDepth: 1,
|
backgroundDepth: 0,
|
||||||
tileTextureMark: Symbol(),
|
tileTextureMark: Symbol(),
|
||||||
vertexMark: Symbol()
|
vertexMark: Symbol()
|
||||||
};
|
};
|
||||||
@ -789,7 +754,6 @@ export class MapRenderer
|
|||||||
data.tileTextureMark = this.assetData.mark();
|
data.tileTextureMark = this.assetData.mark();
|
||||||
gl.bindTexture(gl.TEXTURE_2D_ARRAY, tile);
|
gl.bindTexture(gl.TEXTURE_2D_ARRAY, tile);
|
||||||
this.checkTextureArraySize(gl, data, sourceArray);
|
this.checkTextureArraySize(gl, data, sourceArray);
|
||||||
console.time('texture-upload');
|
|
||||||
source.forEach((v, i) => {
|
source.forEach((v, i) => {
|
||||||
gl.texSubImage3D(
|
gl.texSubImage3D(
|
||||||
gl.TEXTURE_2D_ARRAY,
|
gl.TEXTURE_2D_ARRAY,
|
||||||
@ -817,7 +781,6 @@ export class MapRenderer
|
|||||||
gl.TEXTURE_MIN_FILTER,
|
gl.TEXTURE_MIN_FILTER,
|
||||||
gl.NEAREST
|
gl.NEAREST
|
||||||
);
|
);
|
||||||
console.timeEnd('texture-upload');
|
|
||||||
} else {
|
} else {
|
||||||
const dirty = this.assetData.dirtySince(data.tileTextureMark);
|
const dirty = this.assetData.dirtySince(data.tileTextureMark);
|
||||||
if (dirty.size === 0) return;
|
if (dirty.size === 0) return;
|
||||||
@ -829,7 +792,6 @@ export class MapRenderer
|
|||||||
data,
|
data,
|
||||||
sourceArray
|
sourceArray
|
||||||
);
|
);
|
||||||
console.time('texture-upload');
|
|
||||||
if (sizeChanged) {
|
if (sizeChanged) {
|
||||||
// 尺寸变化,需要全部重新传递
|
// 尺寸变化,需要全部重新传递
|
||||||
source.forEach((v, i) => {
|
source.forEach((v, i) => {
|
||||||
@ -866,7 +828,6 @@ export class MapRenderer
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
console.timeEnd('texture-upload');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1226,8 +1187,10 @@ export class MapRenderer
|
|||||||
gl.NEAREST
|
gl.NEAREST
|
||||||
);
|
);
|
||||||
this.backgroundPending = false;
|
this.backgroundPending = false;
|
||||||
this.extendList.forEach(v => v.onUpdate?.());
|
|
||||||
gl.bindTexture(gl.TEXTURE_2D_ARRAY, null);
|
gl.bindTexture(gl.TEXTURE_2D_ARRAY, null);
|
||||||
|
this.forEachHook((hook, controller) => {
|
||||||
|
hook.onUpdate?.(controller);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): void {
|
render(): void {
|
||||||
@ -1260,14 +1223,18 @@ export class MapRenderer
|
|||||||
|
|
||||||
console.time('layer-check');
|
console.time('layer-check');
|
||||||
// 图层检查
|
// 图层检查
|
||||||
if (this.layerDirty) {
|
|
||||||
this.vertex.updateLayerArray();
|
|
||||||
this.layerDirty = false;
|
|
||||||
}
|
|
||||||
if (this.layerSizeDirty) {
|
if (this.layerSizeDirty) {
|
||||||
this.vertex.resizeMap();
|
this.vertex.resizeMap();
|
||||||
this.layerSizeDirty = false;
|
this.layerSizeDirty = false;
|
||||||
}
|
}
|
||||||
|
if (this.layerListDirty) {
|
||||||
|
this.vertex.updateLayerArray();
|
||||||
|
this.layerListDirty = false;
|
||||||
|
}
|
||||||
|
if (this.layerAllDirty) {
|
||||||
|
this.updateAllLayers();
|
||||||
|
this.layerAllDirty = false;
|
||||||
|
}
|
||||||
this.vertex.checkRebuild();
|
this.vertex.checkRebuild();
|
||||||
console.timeEnd('layer-check');
|
console.timeEnd('layer-check');
|
||||||
|
|
||||||
@ -1352,9 +1319,6 @@ export class MapRenderer
|
|||||||
// 由于 WebGL2 没有 glDrawArraysInstancedBaseInstance,只能每次渲染的时候临时修改 VBO 读取方式
|
// 由于 WebGL2 没有 glDrawArraysInstancedBaseInstance,只能每次渲染的时候临时修改 VBO 读取方式
|
||||||
const stride = INSTANCED_COUNT * 4;
|
const stride = INSTANCED_COUNT * 4;
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, instancedBuffer);
|
gl.bindBuffer(gl.ARRAY_BUFFER, instancedBuffer);
|
||||||
|
|
||||||
console.log(area);
|
|
||||||
|
|
||||||
area.render.forEach(v => {
|
area.render.forEach(v => {
|
||||||
const s = v.startIndex * INSTANCED_COUNT;
|
const s = v.startIndex * INSTANCED_COUNT;
|
||||||
const o1 = s + 0;
|
const o1 = s + 0;
|
||||||
@ -1393,7 +1357,9 @@ export class MapRenderer
|
|||||||
h: number
|
h: number
|
||||||
) {
|
) {
|
||||||
this.vertex.updateArea(layer, x, y, w, h);
|
this.vertex.updateArea(layer, x, y, w, h);
|
||||||
this.extendList.forEach(v => v.onUpdate?.());
|
this.forEachHook((hook, controller) => {
|
||||||
|
hook.onUpdate?.(controller);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1405,7 +1371,9 @@ export class MapRenderer
|
|||||||
*/
|
*/
|
||||||
updateLayerBlock(layer: IMapLayer, block: number, x: number, y: number) {
|
updateLayerBlock(layer: IMapLayer, block: number, x: number, y: number) {
|
||||||
this.vertex.updateBlock(layer, block, x, y);
|
this.vertex.updateBlock(layer, block, x, y);
|
||||||
this.extendList.forEach(v => v.onUpdate?.());
|
this.forEachHook((hook, controller) => {
|
||||||
|
hook.onUpdate?.(controller);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
@ -1570,48 +1538,50 @@ export class MapRenderer
|
|||||||
|
|
||||||
updateTransform(): void {
|
updateTransform(): void {
|
||||||
this.needUpdateTransform = true;
|
this.needUpdateTransform = true;
|
||||||
this.extendList.forEach(v => v.onUpdate?.());
|
this.forEachHook((hook, controller) => {
|
||||||
}
|
hook.onUpdate?.(controller);
|
||||||
|
});
|
||||||
addExtends(ex: IMapRendererExtends): void {
|
|
||||||
this.extendList.add(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
close(): void {
|
|
||||||
this.layers.clear();
|
|
||||||
this.layerAlias.clear();
|
|
||||||
this.layerZIndex.clear();
|
|
||||||
this.extendList.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
class MapRendererExtends implements IMapLayerExtends {
|
class RendererLayerStateHook implements Partial<ILayerStateHooks> {
|
||||||
readonly id: string = 'map-render';
|
|
||||||
|
|
||||||
constructor(readonly renderer: MapRenderer) {}
|
constructor(readonly renderer: MapRenderer) {}
|
||||||
|
|
||||||
onResize(): void {
|
onChangeBackground(
|
||||||
|
_: IHookController<ILayerStateHooks>,
|
||||||
|
tile: number
|
||||||
|
): void {
|
||||||
|
this.renderer.setTileBackground(tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
onResizeLayer(): void {
|
||||||
this.renderer.resizeLayer();
|
this.renderer.resizeLayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpdateArea(
|
onUpdateLayer(): void {
|
||||||
controller: IMapLayerExtendsController,
|
this.renderer.updateLayerList();
|
||||||
|
}
|
||||||
|
|
||||||
|
onUpdateLayerArea(
|
||||||
|
_: IHookController<ILayerStateHooks>,
|
||||||
|
layer: IMapLayer,
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
width: number,
|
width: number,
|
||||||
height: number
|
height: number
|
||||||
): void {
|
): void {
|
||||||
this.renderer.updateLayerArea(controller.layer, x, y, width, height);
|
this.renderer.updateLayerArea(layer, x, y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpdateBlock(
|
onUpdateLayerBlock(
|
||||||
controller: IMapLayerExtendsController,
|
_: IHookController<ILayerStateHooks>,
|
||||||
|
layer: IMapLayer,
|
||||||
block: number,
|
block: number,
|
||||||
x: number,
|
x: number,
|
||||||
y: number
|
y: number
|
||||||
): void {
|
): void {
|
||||||
this.renderer.updateLayerBlock(controller.layer, block, x, y);
|
this.renderer.updateLayerBlock(layer, block, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,10 @@
|
|||||||
import { IDirtyMark, IDirtyTracker } from '@motajs/common';
|
import {
|
||||||
|
IDirtyMark,
|
||||||
|
IDirtyTracker,
|
||||||
|
IHookable,
|
||||||
|
IHookBase,
|
||||||
|
IHookController
|
||||||
|
} from '@motajs/common';
|
||||||
import { ITextureRenderable } from '@motajs/render-assets';
|
import { ITextureRenderable } from '@motajs/render-assets';
|
||||||
import { Transform } from '@motajs/render-core';
|
import { Transform } from '@motajs/render-core';
|
||||||
import {
|
import {
|
||||||
@ -7,7 +13,7 @@ import {
|
|||||||
IMaterialManager,
|
IMaterialManager,
|
||||||
ITrackedAssetData
|
ITrackedAssetData
|
||||||
} from '@user/client-base';
|
} from '@user/client-base';
|
||||||
import { IMapLayer } from '@user/data-state';
|
import { ILayerState, IMapLayer } from '@user/data-state';
|
||||||
import { TimingFn } from 'mutate-animate';
|
import { TimingFn } from 'mutate-animate';
|
||||||
|
|
||||||
export const enum MapBackgroundRepeat {
|
export const enum MapBackgroundRepeat {
|
||||||
@ -221,14 +227,14 @@ export interface IMovingBlock {
|
|||||||
destroy(): void;
|
destroy(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMapRendererExtends {
|
export interface IMapRendererHooks extends IHookBase {
|
||||||
/**
|
/**
|
||||||
* 当需要更新画面时执行
|
* 当需要更新画面时执行
|
||||||
*/
|
*/
|
||||||
onUpdate?(): void;
|
onUpdate(controller: IHookController<this>): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMapRenderer {
|
export interface IMapRenderer extends IHookable<IMapRendererHooks> {
|
||||||
/** 地图渲染器使用的资源管理器 */
|
/** 地图渲染器使用的资源管理器 */
|
||||||
readonly manager: IMaterialManager;
|
readonly manager: IMaterialManager;
|
||||||
/** 画布渲染上下文 */
|
/** 画布渲染上下文 */
|
||||||
@ -242,6 +248,8 @@ export interface IMapRenderer {
|
|||||||
readonly viewport: IMapViewportController;
|
readonly viewport: IMapViewportController;
|
||||||
/** 顶点数组生成器 */
|
/** 顶点数组生成器 */
|
||||||
readonly vertex: IMapVertexGenerator;
|
readonly vertex: IMapVertexGenerator;
|
||||||
|
/** 使用的地图状态对象 */
|
||||||
|
readonly layerState: ILayerState;
|
||||||
|
|
||||||
/** 地图宽度 */
|
/** 地图宽度 */
|
||||||
readonly mapWidth: number;
|
readonly mapWidth: number;
|
||||||
@ -268,12 +276,6 @@ export interface IMapRenderer {
|
|||||||
*/
|
*/
|
||||||
useAsset(asset: ITrackedAssetData): void;
|
useAsset(asset: ITrackedAssetData): void;
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加地图渲染拓展
|
|
||||||
* @param ex 拓展对象
|
|
||||||
*/
|
|
||||||
addExtends(ex: IMapRendererExtends): void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 摧毁此地图渲染器,表示当前渲染器不会再被使用到
|
* 摧毁此地图渲染器,表示当前渲染器不会再被使用到
|
||||||
*/
|
*/
|
||||||
@ -286,17 +288,10 @@ export interface IMapRenderer {
|
|||||||
render(gl: WebGL2RenderingContext): void;
|
render(gl: WebGL2RenderingContext): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加地图图层
|
* 设置渲染器使用的地图状态
|
||||||
* @param layer 地图图层
|
* @param layerState 地图状态
|
||||||
* @param identifier 图层的标识符,可以用于 {@link getLayer} 获取图层
|
|
||||||
*/
|
*/
|
||||||
addLayer(layer: IMapLayer, identifier?: string): void;
|
setLayerState(layerState: ILayerState): void;
|
||||||
|
|
||||||
/**
|
|
||||||
* 移除指定图层
|
|
||||||
* @param layer 要移除的图层
|
|
||||||
*/
|
|
||||||
removeLayer(layer: IMapLayer): void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据标识符获取图层
|
* 根据标识符获取图层
|
||||||
@ -315,19 +310,6 @@ export interface IMapRenderer {
|
|||||||
*/
|
*/
|
||||||
getSortedLayer(): IMapLayer[];
|
getSortedLayer(): IMapLayer[];
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置当前渲染器中指定图层的纵深
|
|
||||||
* @param layer 要设置的图层
|
|
||||||
* @param zIndex 目标纵深
|
|
||||||
*/
|
|
||||||
setZIndex(layer: IMapLayer, zIndex: number): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取指定图层的纵深
|
|
||||||
* @param layer 要获取的图层
|
|
||||||
*/
|
|
||||||
getZIndex(layer: IMapLayer): number | undefined;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取指定图层排序后的索引位置
|
* 获取指定图层排序后的索引位置
|
||||||
* @param layer 要获取的图层
|
* @param layer 要获取的图层
|
||||||
@ -394,11 +376,6 @@ export interface IMapRenderer {
|
|||||||
*/
|
*/
|
||||||
setCellSize(width: number, height: number): void;
|
setCellSize(width: number, height: number): void;
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取变换矩阵
|
|
||||||
*/
|
|
||||||
getTransform(): Transform;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加一个移动图块
|
* 添加一个移动图块
|
||||||
* @param layer 图块所属的图层
|
* @param layer 图块所属的图层
|
||||||
@ -449,11 +426,6 @@ export interface IMapRenderer {
|
|||||||
* @param y 图块纵坐标
|
* @param y 图块纵坐标
|
||||||
*/
|
*/
|
||||||
setTileAlpha(layer: IMapLayer, alpha: number, x: number, y: number): void;
|
setTileAlpha(layer: IMapLayer, alpha: number, x: number, y: number): void;
|
||||||
|
|
||||||
/**
|
|
||||||
* 结束此渲染器的使用,释放所有相关资源
|
|
||||||
*/
|
|
||||||
close(): void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMapVertexArray {
|
export interface IMapVertexArray {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { IMapLayer, IMapLayerData } from '@user/data-state';
|
import { IMapLayer } from '@user/data-state';
|
||||||
import {
|
import {
|
||||||
IBlockData,
|
IBlockData,
|
||||||
IBlockSplitter,
|
IBlockSplitter,
|
||||||
@ -24,8 +24,6 @@ import { BlockCls, IMaterialFramedData } from '@user/client-base';
|
|||||||
import { IRect, SizedCanvasImageSource } from '@motajs/render-assets';
|
import { IRect, SizedCanvasImageSource } from '@motajs/render-assets';
|
||||||
import { INSTANCED_COUNT } from './constant';
|
import { INSTANCED_COUNT } from './constant';
|
||||||
|
|
||||||
// todo: 潜在优化点:顶点数组的 z 坐标以及纹理的 z 坐标可以换为实例化绘制
|
|
||||||
|
|
||||||
export interface IMapDataGetter {
|
export interface IMapDataGetter {
|
||||||
/** 图块缩小行为,即图块比格子大时应该如何处理 */
|
/** 图块缩小行为,即图块比格子大时应该如何处理 */
|
||||||
readonly tileMinifyBehavior: MapTileBehavior;
|
readonly tileMinifyBehavior: MapTileBehavior;
|
||||||
@ -38,12 +36,6 @@ export interface IMapDataGetter {
|
|||||||
/** 图块大小与格子大小判断方式 */
|
/** 图块大小与格子大小判断方式 */
|
||||||
readonly tileTestMode: MapTileSizeTestMode;
|
readonly tileTestMode: MapTileSizeTestMode;
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取指定图层的图块信息,是对内部存储的直接引用
|
|
||||||
* @param layer 地图图层
|
|
||||||
*/
|
|
||||||
getMapLayerData(layer: IMapLayer): Readonly<IMapLayerData> | null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据图集的图像源获取其索引
|
* 根据图集的图像源获取其索引
|
||||||
* @param source 图像源
|
* @param source 图像源
|
||||||
@ -593,8 +585,8 @@ export class MapVertexGenerator
|
|||||||
const block = this.block.getBlockByDataLoc(x, y);
|
const block = this.block.getBlockByDataLoc(x, y);
|
||||||
if (!block) return;
|
if (!block) return;
|
||||||
const vertex = block.data.getLayerData(layer);
|
const vertex = block.data.getLayerData(layer);
|
||||||
const data = this.renderer.getMapLayerData(layer);
|
const data = layer.getMapRef();
|
||||||
if (!vertex || !data) return;
|
if (!vertex) return;
|
||||||
const { array } = data;
|
const { array } = data;
|
||||||
const dx = x - block.dataX;
|
const dx = x - block.dataX;
|
||||||
const dy = y - block.dataY;
|
const dy = y - block.dataY;
|
||||||
@ -789,8 +781,8 @@ export class MapVertexGenerator
|
|||||||
if (!dirty || !dirty.dirty) return;
|
if (!dirty || !dirty.dirty) return;
|
||||||
block.data.updated();
|
block.data.updated();
|
||||||
const vertex = block.data.getLayerData(layer);
|
const vertex = block.data.getLayerData(layer);
|
||||||
const mapData = this.renderer.getMapLayerData(layer);
|
const mapData = layer.getMapRef();
|
||||||
if (!vertex || !mapData) return;
|
if (!vertex) return;
|
||||||
const { array } = mapData;
|
const { array } = mapData;
|
||||||
const { dirtyLeft, dirtyTop, dirtyRight, dirtyBottom } = dirty;
|
const { dirtyLeft, dirtyTop, dirtyRight, dirtyBottom } = dirty;
|
||||||
for (let nx = dirtyLeft; nx < dirtyRight; nx++) {
|
for (let nx = dirtyLeft; nx < dirtyRight; nx++) {
|
||||||
@ -823,9 +815,9 @@ export class MapVertexGenerator
|
|||||||
//#region 图块配置
|
//#region 图块配置
|
||||||
|
|
||||||
enableStaticFrameAnimate(layer: IMapLayer, x: number, y: number): void {
|
enableStaticFrameAnimate(layer: IMapLayer, x: number, y: number): void {
|
||||||
const data = this.renderer.getMapLayerData(layer);
|
const data = layer.getMapRef();
|
||||||
const block = this.block.getBlockByDataLoc(x, y);
|
const block = this.block.getBlockByDataLoc(x, y);
|
||||||
if (!data || !block) return;
|
if (!block) return;
|
||||||
const vertexArray = block.data.getLayerInstanced(layer);
|
const vertexArray = block.data.getLayerInstanced(layer);
|
||||||
if (!vertexArray) return;
|
if (!vertexArray) return;
|
||||||
const mapIndex = y * this.mapWidth + x;
|
const mapIndex = y * this.mapWidth + x;
|
||||||
|
|||||||
@ -48,37 +48,9 @@ import { mainUIController } from './controller';
|
|||||||
import { LayerGroup } from '../elements';
|
import { LayerGroup } from '../elements';
|
||||||
import { isNil } from 'lodash-es';
|
import { isNil } from 'lodash-es';
|
||||||
import { materials } from '@user/client-base';
|
import { materials } from '@user/client-base';
|
||||||
import { IRenderLayerData } from '../map/element';
|
|
||||||
|
|
||||||
const MainScene = defineComponent(() => {
|
const MainScene = defineComponent(() => {
|
||||||
//#region 基本定义
|
//#region 基本定义
|
||||||
const layerList: IRenderLayerData[] = [
|
|
||||||
{
|
|
||||||
layer: state.layer.getLayerByAlias('bg')!,
|
|
||||||
zIndex: 10,
|
|
||||||
alias: 'bg'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
layer: state.layer.getLayerByAlias('bg2')!,
|
|
||||||
zIndex: 20,
|
|
||||||
alias: 'bg2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
layer: state.layer.getLayerByAlias('event')!,
|
|
||||||
zIndex: 30,
|
|
||||||
alias: 'event'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
layer: state.layer.getLayerByAlias('fg')!,
|
|
||||||
zIndex: 40,
|
|
||||||
alias: 'fg'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
layer: state.layer.getLayerByAlias('fg2')!,
|
|
||||||
zIndex: 50,
|
|
||||||
alias: 'fg2'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const mainTextboxProps: Props<typeof Textbox> = {
|
const mainTextboxProps: Props<typeof Textbox> = {
|
||||||
text: '',
|
text: '',
|
||||||
@ -312,7 +284,7 @@ const MainScene = defineComponent(() => {
|
|||||||
onMove={moveMap}
|
onMove={moveMap}
|
||||||
>
|
>
|
||||||
<map-render
|
<map-render
|
||||||
layerList={layerList}
|
layerState={state.layer}
|
||||||
loc={[0, 0, MAP_WIDTH, MAP_HEIGHT]}
|
loc={[0, 0, MAP_WIDTH, MAP_HEIGHT]}
|
||||||
/>
|
/>
|
||||||
<Textbox id="main-textbox" {...mainTextboxProps}></Textbox>
|
<Textbox id="main-textbox" {...mainTextboxProps}></Textbox>
|
||||||
|
|||||||
@ -1,18 +1,43 @@
|
|||||||
import { logger } from '@motajs/common';
|
import {
|
||||||
import { IMapLayer, MapLayer } from '../map';
|
Hookable,
|
||||||
import { ILayerState } from './types';
|
HookController,
|
||||||
|
IHookController,
|
||||||
|
logger
|
||||||
|
} from '@motajs/common';
|
||||||
|
import {
|
||||||
|
IMapLayer,
|
||||||
|
IMapLayerHookController,
|
||||||
|
IMapLayerHooks,
|
||||||
|
MapLayer
|
||||||
|
} from '../map';
|
||||||
|
import { ILayerState, ILayerStateHooks } from './types';
|
||||||
|
|
||||||
export class LayerState implements ILayerState {
|
export class LayerState
|
||||||
readonly layerList: WeakSet<IMapLayer> = new WeakSet();
|
extends Hookable<ILayerStateHooks>
|
||||||
|
implements ILayerState
|
||||||
|
{
|
||||||
|
readonly layerList: Set<IMapLayer> = new Set();
|
||||||
/** 图层到图层别名映射 */
|
/** 图层到图层别名映射 */
|
||||||
readonly layerAliasMap: WeakMap<IMapLayer, string> = new WeakMap();
|
readonly layerAliasMap: WeakMap<IMapLayer, string> = new WeakMap();
|
||||||
/** 图层别名到图层的映射 */
|
/** 图层别名到图层的映射 */
|
||||||
readonly aliasLayerMap: Map<symbol, IMapLayer> = new Map();
|
readonly aliasLayerMap: Map<symbol, IMapLayer> = new Map();
|
||||||
|
|
||||||
|
/** 背景图块 */
|
||||||
|
private backgroundTile: number = 0;
|
||||||
|
|
||||||
|
/** 图层钩子映射 */
|
||||||
|
private layerHookMap: Map<IMapLayer, IMapLayerHookController> = new Map();
|
||||||
|
|
||||||
addLayer(width: number, height: number): IMapLayer {
|
addLayer(width: number, height: number): IMapLayer {
|
||||||
const array = new Uint32Array(width * height);
|
const array = new Uint32Array(width * height);
|
||||||
const layer = new MapLayer(array, width, height);
|
const layer = new MapLayer(array, width, height);
|
||||||
this.layerList.add(layer);
|
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;
|
return layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,6 +49,17 @@ export class LayerState implements ILayerState {
|
|||||||
this.aliasLayerMap.delete(symbol);
|
this.aliasLayerMap.delete(symbol);
|
||||||
this.layerAliasMap.delete(layer);
|
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 {
|
setLayerAlias(layer: IMapLayer, alias: string): void {
|
||||||
@ -57,4 +93,58 @@ export class LayerState implements ILayerState {
|
|||||||
layer.resize2(width, height);
|
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';
|
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;
|
removeLayer(layer: IMapLayer): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前地图状态对象是否包含指定图层对象
|
||||||
|
* @param layer 图层对象
|
||||||
|
*/
|
||||||
|
hasLayer(layer: IMapLayer): boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置图层别名
|
* 设置图层别名
|
||||||
* @param layer 图层对象
|
* @param layer 图层对象
|
||||||
@ -49,6 +123,17 @@ export interface ILayerState {
|
|||||||
height: number,
|
height: number,
|
||||||
keepBlock?: boolean
|
keepBlock?: boolean
|
||||||
): void;
|
): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置背景图块
|
||||||
|
* @param tile 背景图块数字
|
||||||
|
*/
|
||||||
|
setBackground(tile: number): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取背景图块数字,如果没有设置过,则返回 0
|
||||||
|
*/
|
||||||
|
getBackground(): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICoreState {
|
export interface ICoreState {
|
||||||
|
|||||||
@ -2,25 +2,19 @@ import { isNil } from 'lodash-es';
|
|||||||
import {
|
import {
|
||||||
IMapLayer,
|
IMapLayer,
|
||||||
IMapLayerData,
|
IMapLayerData,
|
||||||
IMapLayerExtends,
|
IMapLayerHookController,
|
||||||
IMapLayerExtendsController
|
IMapLayerHooks
|
||||||
} from './types';
|
} from './types';
|
||||||
import { logger } from '@motajs/common';
|
import { Hookable, HookController, logger } from '@motajs/common';
|
||||||
|
|
||||||
interface IExtendsData {
|
export class MapLayer
|
||||||
readonly ex: IMapLayerExtends;
|
extends Hookable<IMapLayerHooks, IMapLayerHookController>
|
||||||
readonly controller: IMapLayerExtendsController;
|
implements IMapLayer
|
||||||
}
|
{
|
||||||
|
|
||||||
export class MapLayer implements IMapLayer {
|
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
empty: boolean = true;
|
empty: boolean = true;
|
||||||
|
zIndex: number = 0;
|
||||||
/** 已经加载完毕的图层拓展 */
|
|
||||||
private loadedExtends: Set<IExtendsData> = new Set();
|
|
||||||
/** 添加的图层拓展 */
|
|
||||||
private addedExtends: Map<string, IExtendsData> = new Map();
|
|
||||||
|
|
||||||
/** 地图图块数组 */
|
/** 地图图块数组 */
|
||||||
private mapArray: Uint32Array;
|
private mapArray: Uint32Array;
|
||||||
@ -28,6 +22,7 @@ export class MapLayer implements IMapLayer {
|
|||||||
private mapData: IMapLayerData;
|
private mapData: IMapLayerData;
|
||||||
|
|
||||||
constructor(array: Uint32Array, width: number, height: number) {
|
constructor(array: Uint32Array, width: number, height: number) {
|
||||||
|
super();
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
const area = width * height;
|
const area = width * height;
|
||||||
@ -42,9 +37,6 @@ export class MapLayer implements IMapLayer {
|
|||||||
|
|
||||||
resize(width: number, height: number): void {
|
resize(width: number, height: number): void {
|
||||||
if (this.width === width && this.height === height) {
|
if (this.width === width && this.height === height) {
|
||||||
this.loadedExtends.forEach(v => {
|
|
||||||
v.ex.onResize?.(v.controller, width, height);
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.mapData.expired = true;
|
this.mapData.expired = true;
|
||||||
@ -78,17 +70,14 @@ export class MapLayer implements IMapLayer {
|
|||||||
expired: false,
|
expired: false,
|
||||||
array: this.mapArray
|
array: this.mapArray
|
||||||
};
|
};
|
||||||
this.loadedExtends.forEach(v => {
|
this.forEachHook((hook, controller) => {
|
||||||
v.ex.onResize?.(v.controller, width, height);
|
hook.onResize?.(controller, width, height);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
resize2(width: number, height: number): void {
|
resize2(width: number, height: number): void {
|
||||||
if (this.width === width && this.height === height) {
|
if (this.width === width && this.height === height) {
|
||||||
this.mapArray.fill(0);
|
this.mapArray.fill(0);
|
||||||
this.loadedExtends.forEach(v => {
|
|
||||||
v.ex.onResize?.(v.controller, width, height);
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.mapData.expired = true;
|
this.mapData.expired = true;
|
||||||
@ -99,17 +88,18 @@ export class MapLayer implements IMapLayer {
|
|||||||
expired: false,
|
expired: false,
|
||||||
array: this.mapArray
|
array: this.mapArray
|
||||||
};
|
};
|
||||||
this.loadedExtends.forEach(v => {
|
|
||||||
v.ex.onResize?.(v.controller, width, height);
|
|
||||||
});
|
|
||||||
this.empty = true;
|
this.empty = true;
|
||||||
|
this.forEachHook((hook, controller) => {
|
||||||
|
hook.onResize?.(controller, width, height);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setBlock(block: number, x: number, y: number): void {
|
setBlock(block: number, x: number, y: number): void {
|
||||||
const index = y * this.width + x;
|
const index = y * this.width + x;
|
||||||
|
if (block === this.mapArray[index]) return;
|
||||||
this.mapArray[index] = block;
|
this.mapArray[index] = block;
|
||||||
this.loadedExtends.forEach(v => {
|
this.forEachHook((hook, controller) => {
|
||||||
v.ex.onUpdateBlock?.(v.controller, block, x, y);
|
hook.onUpdateBlock?.(controller, block, x, y);
|
||||||
});
|
});
|
||||||
if (block !== 0) {
|
if (block !== 0) {
|
||||||
this.empty = false;
|
this.empty = false;
|
||||||
@ -131,8 +121,8 @@ export class MapLayer implements IMapLayer {
|
|||||||
const height = Math.ceil(array.length / width);
|
const height = Math.ceil(array.length / width);
|
||||||
if (width === this.width && height === this.height) {
|
if (width === this.width && height === this.height) {
|
||||||
this.mapArray.set(array);
|
this.mapArray.set(array);
|
||||||
this.loadedExtends.forEach(v => {
|
this.forEachHook((hook, controller) => {
|
||||||
v.ex.onUpdateArea?.(v.controller, x, y, width, height);
|
hook.onUpdateArea?.(controller, x, y, width, height);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -159,8 +149,8 @@ export class MapLayer implements IMapLayer {
|
|||||||
}
|
}
|
||||||
this.mapArray.set(array.subarray(start, start + nw), offset);
|
this.mapArray.set(array.subarray(start, start + nw), offset);
|
||||||
}
|
}
|
||||||
this.loadedExtends.forEach(v => {
|
this.forEachHook((hook, controller) => {
|
||||||
v.ex.onUpdateArea?.(v.controller, x, y, width, height);
|
hook.onUpdateArea?.(controller, x, y, width, height);
|
||||||
});
|
});
|
||||||
this.empty &&= empty;
|
this.empty &&= empty;
|
||||||
}
|
}
|
||||||
@ -213,51 +203,32 @@ export class MapLayer implements IMapLayer {
|
|||||||
return this.mapData;
|
return this.mapData;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadExtends(ex: IMapLayerExtends): boolean {
|
protected createController(
|
||||||
if (!this.addedExtends.has(ex.id)) return false;
|
hook: Partial<IMapLayerHooks>
|
||||||
ex.awake?.();
|
): IMapLayerHookController {
|
||||||
const data = this.addedExtends.get(ex.id)!;
|
return new MapLayerHookController(this, hook);
|
||||||
this.loadedExtends.add(data);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addExtends(ex: IMapLayerExtends): IMapLayerExtendsController {
|
setZIndex(zIndex: number): void {
|
||||||
const controller = new MapLayerExtendsController(this, ex);
|
this.zIndex = zIndex;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MapLayerExtendsController implements IMapLayerExtendsController {
|
class MapLayerHookController
|
||||||
loaded: boolean = false;
|
extends HookController<IMapLayerHooks>
|
||||||
|
implements IMapLayerHookController
|
||||||
|
{
|
||||||
|
hookable: MapLayer;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly layer: MapLayer,
|
readonly layer: MapLayer,
|
||||||
readonly ex: IMapLayerExtends
|
hook: Partial<IMapLayerHooks>
|
||||||
) {}
|
) {
|
||||||
|
super(layer, hook);
|
||||||
load(): void {
|
this.hookable = layer;
|
||||||
this.loaded = this.layer.loadExtends(this.ex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getMapData(): Readonly<IMapLayerData> {
|
getMapData(): Readonly<IMapLayerData> {
|
||||||
return this.layer.getMapRef();
|
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 {
|
export interface IMapLayerData {
|
||||||
/** 当前引用是否过期,当地图图层内部的地图数组引用更新时,此项会变为 `true` */
|
/** 当前引用是否过期,当地图图层内部的地图数组引用更新时,此项会变为 `true` */
|
||||||
expired: boolean;
|
expired: boolean;
|
||||||
@ -5,26 +7,15 @@ export interface IMapLayerData {
|
|||||||
array: Uint32Array;
|
array: Uint32Array;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMapLayerHooks {
|
export interface IMapLayerHooks extends IHookBase {
|
||||||
/**
|
/**
|
||||||
* 当钩子准备完毕时执行,会自动分析依赖,并把依赖实例作为参数传入,遵循依赖列表的顺序
|
* 当地图大小发生变化时执行,如果调用了地图的 `resize` 方法,但是地图大小没变,则不会触发
|
||||||
* @param dependencies 依赖列表
|
|
||||||
*/
|
|
||||||
awake(): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当拓展被移除之前执行,可以用来清理相关内容
|
|
||||||
*/
|
|
||||||
destroy(): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当地图大小发生变化时执行
|
|
||||||
* @param controller 拓展控制器
|
* @param controller 拓展控制器
|
||||||
* @param width 地图宽度
|
* @param width 地图宽度
|
||||||
* @param height 地图高度
|
* @param height 地图高度
|
||||||
*/
|
*/
|
||||||
onResize(
|
onResize(
|
||||||
controller: IMapLayerExtendsController,
|
controller: IMapLayerHookController,
|
||||||
width: number,
|
width: number,
|
||||||
height: number
|
height: number
|
||||||
): void;
|
): void;
|
||||||
@ -38,7 +29,7 @@ export interface IMapLayerHooks {
|
|||||||
* @param height 更新区域高度
|
* @param height 更新区域高度
|
||||||
*/
|
*/
|
||||||
onUpdateArea(
|
onUpdateArea(
|
||||||
controller: IMapLayerExtendsController,
|
controller: IMapLayerHookController,
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
width: number,
|
width: number,
|
||||||
@ -53,47 +44,37 @@ export interface IMapLayerHooks {
|
|||||||
* @param y 更新点纵坐标
|
* @param y 更新点纵坐标
|
||||||
*/
|
*/
|
||||||
onUpdateBlock(
|
onUpdateBlock(
|
||||||
controller: IMapLayerExtendsController,
|
controller: IMapLayerHookController,
|
||||||
block: number,
|
block: number,
|
||||||
x: number,
|
x: number,
|
||||||
y: number
|
y: number
|
||||||
): void;
|
): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMapLayerExtends extends Partial<IMapLayerHooks> {
|
export interface IMapLayerHookController
|
||||||
/** 这个拓展对象的标识符 */
|
extends IHookController<IMapLayerHooks> {
|
||||||
readonly id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IMapLayerExtendsController {
|
|
||||||
/** 当前图层拓展是否已经被加载 */
|
|
||||||
readonly loaded: boolean;
|
|
||||||
/** 拓展所属的图层对象 */
|
/** 拓展所属的图层对象 */
|
||||||
readonly layer: IMapLayer;
|
readonly layer: IMapLayer;
|
||||||
|
|
||||||
/**
|
|
||||||
* 加载此图层拓展,如果拓展依赖了其他拓展并且已经添加,将会自动加载其他拓展
|
|
||||||
*/
|
|
||||||
load(): void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取地图数据,是对内部存储的直接引用
|
* 获取地图数据,是对内部存储的直接引用
|
||||||
*/
|
*/
|
||||||
getMapData(): Readonly<IMapLayerData>;
|
getMapData(): Readonly<IMapLayerData>;
|
||||||
|
|
||||||
/**
|
|
||||||
* 结束此拓展的生命周期,释放相关资源
|
|
||||||
*/
|
|
||||||
unload(): void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMapLayer {
|
export interface IMapLayer
|
||||||
|
extends IHookable<IMapLayerHooks, IMapLayerHookController> {
|
||||||
/** 地图宽度 */
|
/** 地图宽度 */
|
||||||
readonly width: number;
|
readonly width: number;
|
||||||
/** 地图高度 */
|
/** 地图高度 */
|
||||||
readonly height: number;
|
readonly height: number;
|
||||||
/** 地图是否全部空白,此值具有保守性,即如果其为 `true`,则地图一定空白,但是如果其为 `false`,那么地图也有可能空白 */
|
/**
|
||||||
|
* 地图是否全部空白,此值具有充分性,但不具有必要性,
|
||||||
|
* 即如果其为 `true`,则地图一定空白,但是如果其为 `false`,那么地图也有可能空白
|
||||||
|
*/
|
||||||
readonly empty: boolean;
|
readonly empty: boolean;
|
||||||
|
/** 图层纵深 */
|
||||||
|
readonly zIndex: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调整地图尺寸,维持原有图块。如果尺寸变大,那么会补零,如果尺寸变小,那么会将当前数组裁剪
|
* 调整地图尺寸,维持原有图块。如果尺寸变大,那么会补零,如果尺寸变小,那么会将当前数组裁剪
|
||||||
@ -153,15 +134,13 @@ export interface IMapLayer {
|
|||||||
): Uint32Array;
|
): Uint32Array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加图层拓展,使用一系列钩子与图层本身通讯。不同图层拓展没有顺序关系。
|
* 获取整个地图的地图数组,是对内部数组的直接引用
|
||||||
* @param ex 图层拓展对象
|
|
||||||
* @returns 图层拓展控制对象,可以通过它来控制拓展的生命周期,也可以用于获取图层内的一些数据
|
|
||||||
*/
|
*/
|
||||||
addExtends(ex: IMapLayerExtends): IMapLayerExtendsController;
|
getMapRef(): IMapLayerData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移除指定的图层拓展对象
|
* 设置地图纵深,会影响渲染的遮挡顺序
|
||||||
* @param ex 要移除的图层拓展对象,也可以填拓展对象的标识符
|
* @param zIndex 纵深
|
||||||
*/
|
*/
|
||||||
removeExtends(ex: IMapLayerExtends | string): void;
|
setZIndex(zIndex: number): void;
|
||||||
}
|
}
|
||||||
|
|||||||
82
packages/common/src/hook.ts
Normal file
82
packages/common/src/hook.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import { logger } from './logger';
|
||||||
|
import { IHookable, IHookBase, IHookController, IHookObject } from './types';
|
||||||
|
|
||||||
|
export abstract class Hookable<
|
||||||
|
H extends IHookBase = IHookBase,
|
||||||
|
C extends IHookController<H> = IHookController<H>
|
||||||
|
> implements IHookable<H, C>
|
||||||
|
{
|
||||||
|
/** 加载完成的钩子列表 */
|
||||||
|
protected readonly loadedList: Set<IHookObject<H, C>> = new Set();
|
||||||
|
|
||||||
|
/** 钩子列表 */
|
||||||
|
private readonly hookList: Set<IHookObject<H, C>> = new Set();
|
||||||
|
/** 钩子对象到钩子存储对象的映射 */
|
||||||
|
private readonly hookMap: Map<Partial<H>, IHookObject<H, C>> = new Map();
|
||||||
|
/** 钩子控制器到钩子存储对象的映射 */
|
||||||
|
private readonly controllerMap: Map<C, IHookObject<H, C>> = new Map();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建钩子对象的控制器
|
||||||
|
* @param hook 钩子对象
|
||||||
|
*/
|
||||||
|
protected abstract createController(hook: Partial<H>): C;
|
||||||
|
|
||||||
|
addHook(hook: Partial<H>): C {
|
||||||
|
const controller = this.createController(hook);
|
||||||
|
const obj: IHookObject<H, C> = { hook, controller };
|
||||||
|
this.hookMap.set(hook, obj);
|
||||||
|
this.controllerMap.set(controller, obj);
|
||||||
|
this.hookList.add(obj);
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadHook(hook: Partial<H>): void {
|
||||||
|
const obj = this.hookMap.get(hook);
|
||||||
|
if (!obj) {
|
||||||
|
logger.warn(85);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hook.awake?.(obj.controller);
|
||||||
|
this.loadedList.add(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeHook(hook: Partial<H>): void {
|
||||||
|
const obj = this.hookMap.get(hook);
|
||||||
|
if (!obj) return;
|
||||||
|
obj.hook.destroy?.(obj.controller);
|
||||||
|
this.hookList.delete(obj);
|
||||||
|
this.loadedList.delete(obj);
|
||||||
|
this.hookMap.delete(hook);
|
||||||
|
this.controllerMap.delete(obj.controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeHookByController(hook: C): void {
|
||||||
|
const obj = this.controllerMap.get(hook);
|
||||||
|
if (!obj) return;
|
||||||
|
obj.hook.destroy?.(obj.controller);
|
||||||
|
this.hookList.delete(obj);
|
||||||
|
this.loadedList.delete(obj);
|
||||||
|
this.controllerMap.delete(hook);
|
||||||
|
this.hookMap.delete(obj.hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
forEachHook(fn: (hook: Partial<H>, controller: C) => void): void {
|
||||||
|
this.loadedList.forEach(v => fn(v.hook, v.controller));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class HookController<H extends IHookBase> implements IHookController<H> {
|
||||||
|
constructor(
|
||||||
|
readonly hookable: IHookable<H, IHookController<H>>,
|
||||||
|
readonly hook: Partial<H>
|
||||||
|
) {}
|
||||||
|
|
||||||
|
load(): void {
|
||||||
|
this.hookable.loadHook(this.hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
unload(): void {
|
||||||
|
this.hookable.removeHookByController(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
export * from './dirtyTracker';
|
export * from './dirtyTracker';
|
||||||
|
export * from './hook';
|
||||||
export * from './logger';
|
export * from './logger';
|
||||||
export * from './utils';
|
export * from './utils';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
|||||||
@ -41,7 +41,7 @@
|
|||||||
"39": "Offset pool size exceeds WebGL2 limitation, ensure size type of your big image is less than $1.",
|
"39": "Offset pool size exceeds WebGL2 limitation, ensure size type of your big image is less than $1.",
|
||||||
"40": "Material used by map block $1 is not found in built asset. Please ensure you have pack it into asset.",
|
"40": "Material used by map block $1 is not found in built asset. Please ensure you have pack it into asset.",
|
||||||
"41": "You are trying to use a texture on moving block whose offset is not in the offset pool, please build it into asset after loading.",
|
"41": "You are trying to use a texture on moving block whose offset is not in the offset pool, please build it into asset after loading.",
|
||||||
"42": "The layerList property of map-render element is required.",
|
"42": "The layerState property of map-render element is required.",
|
||||||
"1101": "Shadow extension needs 'floor-hero' extension as dependency.",
|
"1101": "Shadow extension needs 'floor-hero' extension as dependency.",
|
||||||
"1201": "Floor-damage extension needs 'floor-binder' extension as dependency.",
|
"1201": "Floor-damage extension needs 'floor-binder' extension as dependency.",
|
||||||
"1301": "Portal extension need 'floor-binder' extension as dependency.",
|
"1301": "Portal extension need 'floor-binder' extension as dependency.",
|
||||||
@ -132,6 +132,7 @@
|
|||||||
"82": "Big image offset size is larger than 64. Considier reduce big image offset bucket.",
|
"82": "Big image offset size is larger than 64. Considier reduce big image offset bucket.",
|
||||||
"83": "It seems that you call '$1' too frequently. This will extremely affect game's performance, so considering integrate them into one 'updateArea' or 'updateBlockList' call.",
|
"83": "It seems that you call '$1' too frequently. This will extremely affect game's performance, so considering integrate them into one 'updateArea' or 'updateBlockList' call.",
|
||||||
"84": "Cannot set alias '$1' for layer, since '$1' is already an alias for another layer.",
|
"84": "Cannot set alias '$1' for layer, since '$1' is already an alias for another layer.",
|
||||||
|
"85": "Hook to load does not belong to current hookable object.",
|
||||||
"1001": "Item-detail extension needs 'floor-binder' and 'floor-damage' extension as dependency.",
|
"1001": "Item-detail extension needs 'floor-binder' and 'floor-damage' extension as dependency.",
|
||||||
"1101": "Cannot add new effect to point effect instance, for there's no more reserve space for it. Please increase the max count of the instance."
|
"1101": "Cannot add new effect to point effect instance, for there's no more reserve space for it. Please increase the max count of the instance."
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
//#region 脏标记
|
||||||
|
|
||||||
export interface IDirtyMarker<T> {
|
export interface IDirtyMarker<T> {
|
||||||
/**
|
/**
|
||||||
* 标记为脏,即进行了一次更新
|
* 标记为脏,即进行了一次更新
|
||||||
@ -32,3 +34,83 @@ export interface IDirtyTracker<T> {
|
|||||||
*/
|
*/
|
||||||
hasMark(symbol: IDirtyMark): boolean;
|
hasMark(symbol: IDirtyMark): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 钩子
|
||||||
|
|
||||||
|
export interface IHookObject<
|
||||||
|
H extends IHookBase,
|
||||||
|
C extends IHookController<H>
|
||||||
|
> {
|
||||||
|
/** 钩子对象 */
|
||||||
|
readonly hook: Partial<H>;
|
||||||
|
/** 钩子控制器 */
|
||||||
|
readonly controller: C;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IHookController<H extends IHookBase = IHookBase> {
|
||||||
|
/** 控制器的钩子对象 */
|
||||||
|
readonly hook: Partial<H>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载此控制器对应的钩子对象
|
||||||
|
*/
|
||||||
|
load(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 卸载此控制器对应的钩子对象,之后此钩子将不会再被触发
|
||||||
|
*/
|
||||||
|
unload(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IHookBase {
|
||||||
|
/**
|
||||||
|
* 加载此钩子对象
|
||||||
|
* @param controller 钩子控制器对象
|
||||||
|
*/
|
||||||
|
awake(controller: IHookController<this>): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 摧毁此钩子对象
|
||||||
|
* @param controller 钩子控制器对象
|
||||||
|
*/
|
||||||
|
destroy(controller: IHookController<this>): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IHookable<
|
||||||
|
H extends IHookBase = IHookBase,
|
||||||
|
C extends IHookController<H> = IHookController<H>
|
||||||
|
> {
|
||||||
|
/**
|
||||||
|
* 添加钩子对象,返回控制该钩子对象的控制器
|
||||||
|
* @param hook 钩子对象
|
||||||
|
*/
|
||||||
|
addHook(hook: Partial<H>): C;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载指定的钩子对象
|
||||||
|
* @param hook 钩子对象
|
||||||
|
*/
|
||||||
|
loadHook(hook: Partial<H>): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除钩子对象,会调用钩子对象的 `destroy` 方法
|
||||||
|
* @param hook 钩子对象
|
||||||
|
*/
|
||||||
|
removeHook(hook: Partial<H>): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 传入钩子控制器,移除对应的钩子对象
|
||||||
|
* @param hook 钩子控制器
|
||||||
|
*/
|
||||||
|
removeHookByController(hook: C): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 遍历每个钩子
|
||||||
|
* @param fn 对每个钩子执行的函数
|
||||||
|
*/
|
||||||
|
forEachHook(fn: (hook: Partial<H>, controller: C) => void): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|||||||
@ -199,6 +199,9 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
|
|||||||
const array = new Uint32Array(fg2.flat());
|
const array = new Uint32Array(fg2.flat());
|
||||||
fg2Layer.putMapData(array, 0, 0, width);
|
fg2Layer.putMapData(array, 0, 0, width);
|
||||||
}
|
}
|
||||||
|
const back = core.floors[floorId].defaultGround;
|
||||||
|
const id = core.maps.getNumberById(back);
|
||||||
|
state.layer.setBackground(id);
|
||||||
|
|
||||||
// 设置勇士的位置
|
// 设置勇士的位置
|
||||||
heroLoc.direction = core.turnDirection(heroLoc.direction);
|
heroLoc.direction = core.turnDirection(heroLoc.direction);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user