template/docs/dev/map-store-improve.md

8.0 KiB
Raw Blame History

需求综述

本次改动目标:

  1. 自动化分区激活器:将楼层按游戏进程划分为若干"区域" 到达新区域时自动激活对应楼层、失活旧区域楼层, 从而替代目前繁琐的手动 setActiveStatus 调用。
  2. 楼层尺寸上移至 LayerState:同一楼层的所有图层尺寸应当 保持一致,因此将尺寸的权威来源从 MapLayer 移至 LayerState

实现思路

1. 有序地图 id 列表

当前 IMapStore.mapsReadonlySet<string>,无序且随楼层创建 自动填充。区域功能需要以下标标识范围,因此需改为有序数组。

修改方案:

  • IMapStore.maps 类型改为 ReadonlyArray<string>
  • 新增 setMapList(maps: string[]): void,由外部显式指定有序列表 (一般在游戏初始化时调用一次);
  • 新增 useManualOrder(sort: (arr: string[]) => string[]): void 允许自定义地图列表排序函数。调用时将当前 mapsslice 拷贝 传入 sort,再对输出做合法性校验:将新旧数组各转为 Set 校验 size 相等且新集合是旧集合的子集(利用 Set.prototype.isSubsetOf 校验通过后用返回值替换内部的 maps。这样当地图是动态生成时, 作者依然可以自定义顺序,而不必手动维护全量列表;
  • createLayerState 不再维护 mapsmaps 完全由 setMapList 管理;
  • createLayerState 传入的 id 不在 maps 中,仍可正常创建, 不影响存档逻辑,但该楼层不参与任何区域判断。

2. 区域定义与管理

类型定义

/** 单段闭区间 [start, end]start 和 end 均为 maps 下标 */
export interface IMapAreaInterval {
    readonly start: number;
    readonly end: number;
}

/** 一个区域由一个或多个独立区间组成 */
export type MapArea = IMapAreaInterval[];

接口

  • setArea(areas: Set<MapArea>): void:一次性设置所有区域信息, 覆盖原有区域定义;每个元素代表一个区域,区域可包含多个区间, 使用 Set<MapArea> 表示无序区域集合;
  • activeArea(id: string): void:手动激活指定楼层所在区域的所有楼层。 系统遍历 areaList,找到包含该楼层 id 的区域后,对该区域内的所有 楼层调用 setMapActiveStatus(floor, true)
  • deactiveArea(id: string): void:手动取消激活指定楼层所在区域的 所有楼层,逻辑与 activeArea 对称;判断时遍历 areaList 此操作为低频调用,无需缓存;

3. 自动分区激活器

接口

  • useAutoActivitor(enable: boolean): void:是否启用自动激活器。

触发接口

需要一个通知接口供玩家相关模块调用:

  • notifyEnterFloor(id: string): void:玩家进入指定楼层时调用此接口, 通知地图管理器进行自动激活判断。

逻辑

notifyEnterFloor(id) 的执行流程(每次进入楼层均调用,内部短路):

  1. 若自动激活器未启用,直接返回;
  2. isMapActive(id)true,直接返回(楼层已激活,无需操作);
  3. 遍历 areaList,找出包含 id 的区域;
  4. 若未找到,直接返回(该楼层不在任何区域内);
  5. lastFloorId !== null,调用 deactiveArea(lastFloorId) 失活上一个区域;
  6. 调用 activeArea(id) 激活新区域,更新 lastFloorId = id

内部状态

MapStore 新增:

  • private areaList: Set<MapArea>:所有区域定义;
  • private lastFloorId: string | null = null:上一次触发 notifyEnterFloor 的楼层 id用于定位并失活上一个激活区域
  • private autoActivitorEnabled: boolean = false:自动激活器开关。

4. 楼层尺寸上移至 LayerState

动机

当前 MapLayer.width / MapLayer.height 存储在图层中, 但同一楼层的所有图层尺寸必须一致,权威来源应当是 LayerState

接口变动

ILayerState 新增

readonly width: number;
readonly height: number;

addLayer 签名调整

目前 addLayer(width: number, height: number): IMapLayer 移除 width/height 参数,改为 addLayer(): IMapLayer 使用 LayerState 内部存储的尺寸创建图层。

楼层尺寸在 createLayerState 创建时指定,createLayerState 签名改为:

createLayerState(id: string, width: number, height: number): ILayerState;

运行时仍可通过 resizeLayer 修改楼层尺寸,该方法会同步对楼层内所有 图层执行 resize保持尺寸一致。

resizeLayer 签名调整

当前 resizeLayer(layer, width, height, keepBlock?) 只 resize 单个图层, 但既然尺寸是楼层级的,建议改为对该楼层的所有图层同步 resize

resizeLayer(width: number, height: number, keepBlock?: boolean): void;

IMapLayer.resize / IMapLayer.resize2

IMapLayer 接口中移除,保留为 MapLayer 的内部实现, 仅由 LayerState.resizeLayer 调用。

IMapLayer.width / IMapLayer.height

保留在 IMapLayer 接口中,供外部通过图层对象直接获取尺寸。 其值始终与所属 LayerStatewidth/height 保持一致。


附加建议结论

  1. IMapLayer.setMapRef 可见性:保留现有设计,偶尔有外部需求。
  2. active 状态管理:不需要单独维护区域激活状态; activeArea(id) / deactiveArea(id)setMapActiveStatus 的 快捷方式,遍历区域楼层批量调用即可,无需额外的区域状态字段。
  3. notifyEnterFloor 返回值:暂不添加,后续有需求再改进。

涉及文件

需要引用的文件

  • @user/data-base/src/map/types.ts: 全部现有地图接口
  • @user/data-base/src/map/mapStore.ts: MapStore 实现类
  • @user/data-base/src/map/layerState.ts: LayerState 实现类
  • @user/data-base/src/map/mapLayer.ts: MapLayer 实现类

需要修改的文件

@user/data-base/src/map/types.ts

  • 新增 IMapAreaInterval 接口:区间定义,含 startend
  • 新增 MapArea 类型别名:IMapAreaInterval[],表示一个区域
  • 修改 ILayerState
    • 新增 readonly width: numberreadonly height: number
    • 修改 addLayer 签名,移除 width/height 参数(使用 LayerState 自身尺寸)
    • 修改 resizeLayer 签名:移除 layer 参数,改为对整个楼层所有图层同步 resize
  • 修改 IMapLayer
    • 移除 resize / resize2(改为 MapLayer 内部方法)
  • 修改 IMapStore
    • readonly maps 类型改为 ReadonlyArray<string>
    • 修改 createLayerState 签名:新增 width: numberheight: number 参数
    • 新增 setMapList(maps: string[]): void
    • 新增 useManualOrder(sort: (arr: string[]) => string[]): void
    • 新增 setArea(areas: Set<MapArea>): void
    • 新增 activeArea(id: string): void
    • 新增 deactiveArea(id: string): void
    • 新增 useAutoActivitor(enable: boolean): void
    • 新增 notifyEnterFloor(id: string): void

@user/data-base/src/map/mapStore.ts

  • maps: Set<string> 改为 maps: string[]
  • 修改 createLayerState:添加 width/height 参数,不再维护 maps
  • 实现 setMapList
  • 实现 useManualOrder
  • 新增 private areaList: Set<MapArea>
  • 新增 private lastFloorId: string | null
  • 新增 private autoActivitorEnabled: boolean
  • 实现 setAreaactiveAreadeactiveArea
  • 实现 useAutoActivitor
  • 实现 notifyEnterFloor

@user/data-base/src/map/layerState.ts

  • 新增 width: numberheight: number 成员(由构造参数初始化)
  • 修改 addLayer,移除 width/height 参数,使用 this.width/this.height
  • 修改 resizeLayer,移除 layer 参数,改为对所有图层同步 resize

@user/data-base/src/map/mapLayer.ts

  • resize/resize2 改为内部方法(从公共接口移除)