template/docs/dev/hero/hero-mover.md

7.8 KiB
Raw Blame History

需求综述

将旧样板中的 HeroMoverpackages-user/data-state/src/legacy/move.ts)基于新的 IObjectMover / ObjectMover 基类进行彻底性重构,编写新的 IHeroMover 接口和 HeroMover 实现类。

新实现的核心变化:

  • 基类从旧 ObjectMoverBaseEventEmitter 模式)迁移至 ObjectMover<IHeroLocation>Hook 模式)。
  • inLockControl 删除,重构后不再需要。
  • 移动速度不再由 HeroMover 存储,速度变更通过 ObjectMover.speed() 方法体现,实际动画时长在 Hook 中自行处理。
  • noRouteignoreTerrainautoSave 不再作为公开属性暴露,改为通过 config() / getConfig() 方法管理,配置对象为 IHeroMoverConfig
  • 摒弃所有 core.xxx 调用,这些功能将在后续通过新接口逐步补充。
  • HeroMover 的实例化由 IHeroLocation 的实现类内部完成,构造时传入 this 作为 tile,解决循环依赖。

接口设计分析

IHeroMover 直接扩展 IObjectMover<IHeroLocation>,以下仅分析新增内容。

IHeroMover

接口综述

IHeroMover 在通用对象移动器基础上,通过 config() 方法接收一个 IHeroMoverConfig 配置对象来控制本次移动的行为模式(是否忽略地形、是否记录路径、是否触发自动存档)。这种方法将三个相关标志聚合到统一的配置接口中,调用方便且后续扩展新配置项时无需新增独立属性。getConfig() 返回当前生效的只读配置,供内部逻辑和 Hook 查询移动上下文。

接口分析

  • IHeroMover.config(config):预期频率中频。在移动开始前统一配置本次移动的行为标志,一次性设置多个相关选项,比分别设置三个独立属性更加便利。典型使用场景:自动寻路系统在每次移动前调用 mover.config({ noRoute: true }).forward(3).start(),通过链式调用一气呵成。

  • IHeroMover.getConfig():预期频率低频。查询当前移动器的配置快照,主要用于 Hook 内部判断移动上下文或调试时检查配置状态。典型使用场景Hook 中的 onStepStart 获取 mover.getConfig() 以判断当前步是否需要路线记录。

IHeroMoverConfig 成员分析

  • noRoute:预期频率中频。控制本次移动是否记录进路线系统。路线回放、自动寻路等系统均需跳过路线记录,涉及面较广,故为中频。

  • ignoreTerrain:预期频率低频。控制本次移动是否跳过地形碰撞检测,仅用于瞬移、强制移动等特殊场景。

  • autoSave:预期频率低频。控制本次移动是否在特定时机触发自动存档,仅在地图伤害相关全局系统内部设置。

三个配置项在 config() 参数中均为可选,未显式设置的项保持当前值不变,getConfig() 返回的是已补全默认值的完整配置只读快照。

预期体量

接口定义部分(IHeroMoverIHeroMoverConfig)约 15-20 行。

HeroMover 类的预期代码体量为 200-250 行。分析如下:

  • 类定义与私有属性(noRouteignoreTerrainautoSave 各自独立声明),以及 config / getConfig 实现,约 30 行。
  • onMoveStart 实现(同步渲染端状态、预检查首步地形等),约 30 行。
  • onMoveEnd 实现(恢复状态、通知渲染端结束、清除自动寻路状态),约 20 行。
  • onStepStart 实现(地形检测、自动存档判断、渲染端动画调用等),约 55 行。
  • onStepEnd 实现(根据移动代码分发处理、返回新坐标、路线记录、触发器等),约 65 行。
  • 辅助方法(坐标计算、地形检测等),约 30 行。
  • HeroMoveCode 枚举定义,约 10 行。

可能风险

  • IHeroLocation 接口已定义 readonly mover: IObjectMover<this>。由于 IHeroMover extends IObjectMover<IHeroLocation>,若 HeroMover 的构造在 IHeroLocation 内部完成(传入 this),类型可自然满足且无循环依赖问题。但需确保 IHeroLocation 的实现类确实在其构造过程中创建并持有 HeroMover 实例。

实现思路

1. 在 types.ts 中新增相关接口与枚举

新增 IHeroMoverConfig 接口,包含 noRouteignoreTerrainautoSave 三个可选布尔成员。

新增 IHeroMover 接口,继承 IObjectMover<IHeroLocation>,新增 config(config)getConfig() 两个方法。

新增 HeroMoveCode 枚举,公开导出,包含正常移动、停止、撞击、不可移动等代码,供 Hook 用户判断每步移动结果。

2. 完成 HeroMover

packages-user/data-state/src/hero/mover.ts 中实现 HeroMover extends ObjectMover<IHeroLocation>

构造函数接收两个参数:

  • tile: IHeroLocation — 勇士位置对象,同时满足 IObjectMovable,作为基类移动操作的绑定目标。
  • faceHandler: IFaceHandler<FaceDirection> — 朝向处理器,由 IHeroLocation 实现类在创建 HeroMover 时传入(本样式中为 Dir4FaceHandler)。

config(config):将传入配置中已显式提供的字段分别赋值到对应的私有属性 noRouteignoreTerrainautoSave,未传入的字段保持原值,返回 this 以支持链式调用。

getConfig():从三个私有属性分别读取当前值,组装为 Readonly<IHeroMoverConfig> 返回,默认值均为 false

onMoveStart:移动开始时读取当前配置,通过 IHeroLocation.mover(渲染端 HeroMoveController 实例)启动渲染端移动动画。若 ignoreTerrainfalse,预检查第一步是否能通过。

onMoveEnd:移动结束时通知渲染端移动结束,清除自动寻路相关状态。

onStepStart:根据 ignoreTerrain 判断是否进行地形检测,若不可通过则返回对应的 HeroMoveCode。处理 autoSave 的存档判断逻辑。启动渲染端单步移动动画。根据 noRoute 判断是否记录路线。

注意:地形检测、路线记录、触发器、中毒伤害等具体逻辑依赖的新接口尚不存在,core.xxx 调用在此重构中摒弃。当前在这些位置以 // TODO: 标记占位,等待后续接口补充。

onStepEnd:根据 onStepStart 返回的 HeroMoveCode 执行对应逻辑:

  • Step:返回目标坐标 ITileLocator 让基类更新位置,执行路线记录与后置逻辑。
  • Hit:停止移动,触发目标格触发器。
  • CannotMove:停止移动,不触发触发器。
  • Stop:停止移动,清除自动寻路。

3. 在 hero/index.ts 中导出

packages-user/data-state/src/hero/index.ts 中新增 export * from './mover'

涉及文件

需要引用的文件

  • @motajs/common:引用 ITileLocator 等基础接口。
  • @user/data-common:引用 IObjectMoverIObjectMovableObjectMoverObjectMoveStepObjectMoveStepTypeFaceDirectionIFaceHandlerIFaceDescriptor 等类型。
  • @user/data-base:引用 IHeroLocationIHeroMoveController 等勇士相关接口。
  • types.ts(同包顶层):引用 IHeroMoverIHeroMoverConfigHeroMoveCode(类实现接口时自引用)。

需要修改的文件

packages-user/data-state/src/types.ts

  • 新增 IHeroMoverConfig 接口:定义移动配置对象的三个可选布尔成员 noRouteignoreTerrainautoSave
  • 新增 IHeroMover 接口:继承 IObjectMover<IHeroLocation>,新增 config()getConfig() 方法。
  • 新增 HeroMoveCode 枚举:定义勇士移动步骤返回码,公开导出供 Hook 使用。

packages-user/data-state/src/hero/mover.ts(新建)

  • 实现 HeroMover 类:继承 ObjectMover<IHeroLocation>,实现 configgetConfig 及基类四个抽象方法。

packages-user/data-state/src/hero/index.ts

  • 新增 export * from './mover':导出新模块。