joywayer and Claude Opus 5
bf7899f91a
feat(combat): 接通弹反反制——弹反成功让发起攻击的敌人硬直
...
EnemyBase.ReceiveParry 早就存在且形态正确(强制 Stagger + 打断全部能力 +
定时恢复,小怪 Boss 通用),但一直零调用者:弹反判定点拿不到攻击者引用。
硬直时长的权威也早就存在——ParryConfigSO.StaggerDuration,注释写着
「被弹反敌人的受击硬直时长」,同样零消费者。本次只是把这两端接上,没有新造语义。
接缝选在 DamageInfo 而非"弹反成功时回调 HitBox"(spec §6.2 留的两个选项):
攻击者引用与既有的 SourceProjectile 完全同构——都是"攻击从哪来"的引用,
供弹反分支反向作用于来源。落到代码上就是弹反分支里并列的两行,不引入第二条回调链路。
- Combat 新增 IParryable(攻击被弹反时的反制承受方)。用接口是因为程序集方向:
Combat 不能反向依赖 Enemies,而 HurtBox.ReceiveDamage 是唯一同时握有
弹反结果与 DamageInfo 的地方。与 IDamageable 同款做法。
- DamageInfo 加 Attacker 字段([NonSerialized],Builder 与 From 工厂同步支持)。
- HitBox 在 Activate 时按宿主解析并缓存 IParryable——与 _ownerRigidbody 同源、
与 _ownerProjectile 同手法。放 Activate 而非 Awake:attacker 可由调用方传入。
- ParrySystem 暴露 StaggerDuration,HurtBox 在弹反成功时读它,不另立常量。
- EnemyBase 声明实现 IParryable(方法签名本就匹配,无需改实现)。
顺带确认旧的全局误伤路径确实已随 Boss 单轨合并删净:全库不再有
HandleParrySuccess,ParryInfoEventChannelSO 只剩 ParrySystem 自己 Raise,
不存在"弹反小怪导致场上 Boss 一起硬直"的双重路径。
验证:编译 0 错;EditMode 276/276(273 + 新增 3)。
测试走完整 HurtBox 流水线:反射仅用于喂配置与跑真实 Awake,被测逻辑全程生产代码
(与 BossPhaseAbilityGateTests 同一手法)。硬直时长断言取 1.25f 这个非默认值,
才能证明读的是配置而非常量。用例把完美弹反阈值设为负数以避开会改 Time.timeScale
的子弹时间协程(编辑模式下它 yield 后不会恢复),TearDown 另有兜底还原。
变异验证——注释掉 HurtBox 里那一行后,恰好只有反制用例变红;还原后复验 276/276。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-03 11:36:52 +08:00
joywayer and Claude Opus 5
1e3c060c8d
fix(core): 对象池真正通知 IPoolable,复用的敌人不再以死亡状态出场
...
IPoolable 的接口文档写着「由 PooledObject 子类或同 GameObject 上的其他
MonoBehaviour 实现,并在 PooledObject.OnSpawn/OnDespawn 中手动驱动」,
但那两个方法是空的 public virtual,全库无任何 PooledObject 子类,
GlobalObjectPool 也从不查找 IPoolable 组件——这份契约从未生效过。
全库 .OnSpawn(/.OnDespawn( 的调用点只有 4 处,真正驱动 EnemyBase
(唯一的 IPoolable 实现者)的只有 EnemyRespawner 一处手动补调。后果:
- EnemyBase.OnDespawn 在生产中从未被调用,其中的 _nav?.Stop() 是死代码;
- 更严重的是取出侧:PerformDeath 会 ForceState(Dead) 并禁用全部碰撞体后归池,
而 EnemySpawnerOnEvent / ChaoFengBoss 召唤 / RangedEnemy 这些取用方
没有补调 OnSpawn,拿到的复用敌人仍停在 Dead 态、碰撞体全关、HP 为 0——
一个不可交互也不会动的幽灵。EnemyRespawner 路径侥幸没暴露,只因为它手动补了。
修法是让池履行它自己声明的契约,而不是让各调用方继续手动补调:
PooledObject.OnSpawn/OnDespawn 转发给本物体上的 IPoolable。只扫本物体、
不向下扫子物体——接口文档限定的就是「同 GameObject」,向下扫会让嵌套的
可池化对象被两个 PooledObject 各通知一次。组件集惰性解析一次并缓存
(池化本就是为省开销,不能每次进出都遍历组件)。
同时统一两条归池路径的顺序:GlobalObjectPool.Despawn 原本先 SetActive(false)
再 OnDespawn,而 PooledObject.ForceReturnToPool 是反过来的。转发接通后这个
顺序就成了可观察行为,两条路径必须给出同一份契约——统一为「先通知再停用」,
清理才跑在还活跃的对象上。
EnemyRespawner 那次手动 OnSpawn 随之改为只在兜底实例化路径调用:池化路径
现在由转发完成,重复调用会让 OnSpawn 末尾的 Spawned?.Invoke() 触发两次,
即重复执行出生能力。(今天重复触发会被 Execute() 的 !_isRunning 门挡住,
但那是运气不是设计。)
验证:编译 0 错;EditMode 273/273(269 + 新增 4)。
分阶段观察过失败面:只加转发时,2 条转发测试转绿、顺序测试仍红在
WasActiveOnDespawn 上;补顺序后全绿。
变异验证——把扫描范围改成 GetComponentsInChildren 后,边界测试恰好变红
(该测试在修复前是平凡通过的,需确认它真有约束力),还原后复验 273/273。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-07-31 16:03:57 +08:00
joywayer and Claude Opus 5
0f676b0e88
feat(ai): Build() 校验「非终态必须有出口」,堵住零报错的永久卡死
...
BrainBuilder.Build() 此前只做正向校验——边指向的态是否已声明(RequireState
的同款关切);反向从不检查。一个已声明却没有任何出边的非终态,会让敌人进去
就永久停在那里,且全程零报错。计划里点名的风险点是 BossFragments.PhaseTransition:
它按设计不自带出边,出口全靠调用方补挂,漏一条就把 Boss 锁死。
做法:AiState 加 IsTerminal,StateBuilder 加 .Terminal() 显式标记,
AiStateFragments.Terminal() 自带该标记;Build() 对「非终态且无出口」抛异常。
「有出口」的判定比计划原话严一档,两点都是照 AiRuntime 的实际行为定的:
- 自转换不算——Switch 对 Target == 当前态直接 return false,根本出不去;
- 全局转换不算——全局事件边要外部推信号才触发,不是自主出口。把它算作出口,
等于让「只有死了才出得去」的死角通过校验,而那恰是本校验要暴露的东西。
校验放在 Build() 而非各生产入口:生产的完整图装配点是 AiScript.GetOrBuildGraph
与 AiRecipeSO 两处,放 Build() 能让将来新增的入口默认受保护。代价是模块单测
需要一条别的路——单个 IUnawareModule / IEngagementModule 按设计只声明自己的态,
升级边由 PerceptionSkeleton 事后挂,单独构建时的死角是正常中间态而非缺陷。
为此加 BuildPartial():跳过本项校验,其余照旧。
测试侧按语义分两类处理,没有一刀切:
- 概念上确实是终态的(Dead)标 .Terminal(),保留 Build() 的全量校验;
- 隔离验证单个模块/片段的部分图改用 BuildPartial();
- AiScriptTests / AiDefinitionRegistryTests 的夹具经 GetOrBuildGraph 走生产
Build(),给桩汇态补了回边——这两条本就该验完整图。
- 断言 Build() 因别的原因抛异常的用例原样保留。
PerceptionSkeleton 与嘲风图建的都是完整图,无需改动即通过——这本身就是覆盖。
验证:编译 0 错;EditMode 269/269(264 + 新增 5)。
加校验后曾有 49 条既有测试变红,全部为上述两类夹具,逐条按语义修正后转绿。
变异验证:注释掉 ChaoFengAi 里 PhaseTx 的 txDone 出边后,ChaoFengAiTests
8 条全部变红,报错精确点名 'PhaseTransition';还原后复验 269/269。
本改动之前,同样的删除是零报错的——Boss 会静默锁死在过渡态,
这正是本校验存在的理由。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-07-31 13:21:07 +08:00
joywayer and Claude Opus 5
6414fa2dfe
fix(enemy): 池化复活的敌人不再带着上一条命的能力冷却
...
EnemyBase.OnSpawn 里 InterruptAll 那行的注释写着「重置能力冷却」,
三处都不成立:
1. EnemyAbilityRegistry.InterruptAll 有 `if (ab.IsRunning)` 门;
2. EnemyAbilityBase.Interrupt 里还有一道 `if (!_isRunning) return`;
出生时没有能力在跑,循环体一次都不执行;
3. 即便执行到,末行是 `_cooldownEndTime = Time.time + cooldown * 0.5f`——
那是「中断后计半程冷却」的写入语义,本就不是清零。
冷却以绝对 Time.time 记时,于是上一条命的剩余冷却原样活到下一条命。
活路径是 EnemyRespawner.SpawnEnemy():敌人死亡归池、延迟复活后取出复用,
按 1.5–10 秒的冷却量级,新生的敌人有数秒出不了招。
修法是补一条真正的清除路径而非改动中断语义:
EnemyAbilityBase.ResetCooldown() 把 _cooldownEndTime 清回出生态的 -1,
EnemyAbilityRegistry.ResetAllCooldowns() 不看 IsRunning 逐个调用,
OnSpawn 显式调用它。原 InterruptAll 保留为兜底中断,但注释改为陈述它
实际做的事——那句失真的注释正是这个缺陷藏了这么久的原因。
测试的冷却全程由生产代码写入:Execute() 启真实协程(编辑模式下跑到首个
yield 即挂起,_isRunning 留 true),再由 Interrupt() 经真实路径写冷却,
不反射直写字段,否则测到的是伪造状态而非真实时序的产物。
验证:编译 0 错 0 警;EditMode 264/264。
修复前该用例是唯一变红的一条(263/264),失败值 5.0f 恰为
cooldown(10) × 0.5,精确指向上述第 3 点。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-07-31 11:13:49 +08:00
joywayer
9120964be0
fix(enemy): 无受击/僵直动画时不再永久卡死
...
EnemyHurtState 与 EnemyStaggerState 的 Enter 在对应 Clip 为空时守卫式早退,
**同时丢掉了恢复安排**:_currentState 永远停在该态,IsControllable 恒假,
AiRuntime 的让位门永久挡住条件边求值——敌人被打一次即永久失能。
美术未接入时这影响的是大部分敌人。
TakeDamage 是分发点:霸体被破进 Stagger、否则进 Hurt,两条都可达,
所以这是两个活 bug 而非一个。EnemyKnockUpState 本就有 else 分支走
ScheduleStateRecovery,是正确范式;本次把该分支补给另外两个,并加一条
KnockUp 回归测试守住它。
时长权威没有新造:
- Hurt 接上 DamageSourceSO.HitStunDuration——该字段一路铺到 DamageInfo
却零消费者,本就是「这一击让对方僵多久」的既有权威;经 PendingHitStun
传给状态,形状与既有的 PendingLaunchDir 一致。
- Stagger 用 HitTierConfig.staggerDuration——该结构 tooltip 本就写着
「Stagger / KnockUp 参数」却只有 KnockUp 的字段,属补齐而非发明。
顺带修 ScheduleStateRecovery 不取消前一次安排的问题:两个重叠安排里较短的
会先把状态改回 Controlled,静默缩短调用方想要的时长(ReceiveParry 接线后
就会撞上)。并在 OnSpawn 清掉跨池化周期残留的协程句柄。
注:Knockback 目前零调用者,其中的 PendingHitStun 赋值今天是死代码,
但它是 public virtual 且会进 Hurt 态,不设则将来接线时会用到陈旧时长。
验证:编译 0 错;EditMode 263/263(260 + 新增 3)。
变异验证——移除两个 else 分支后恰好 Hurt/Stagger 两条测试变红、
KnockUp 回归测试保持绿,恢复后复验 263/263。
2026-07-31 09:40:47 +08:00
joywayer
0d81d29527
feat(enemy): 嘲风 AI 图(BrainGraph 定制路径)
...
Wait →(Engaged) Intro → Ground⇄GroundAttack →(hp<50%) PhaseTx → Air⇄AirAttack。
Boss 不脱战(rest 指回自身)、阶段单向推进、起手就打完。
死亡不在图上:全局 Died 边进 Death 终态,演出归物理层。
8 条 EditMode 断言覆盖状态序列、过渡只发起一次、过渡结束必须转出、
脱离感知区不脱战、血量回升不回退阶段。
2026-07-30 14:51:08 +08:00
joywayer
5cc93483d3
feat(combat): HurtBox 自带受击伤害倍率
...
倍率归 HurtBox 自己(弱点部位就是一个倍率 > 1 的 HurtBox),
取代 WeakPointSystem 那份写进私有字段却零调用者的倍率——
其注释称由 BossStats 调用,而项目里根本没有 BossStats 类型。
倍率 1 时数值原样返回而非"乘完再钳最低 1":本改动先于任何消费者落地,
若默认路径引入钳制会静默改变游戏里每一次伤害计算。
测试用 ApplyDamageMultiplier(0)==0 守住这条——10 在两种实现下都得 10,
只有 0 能把二者区分开。变异验证:去掉该捷径后恰好该断言变红。
2026-07-30 14:15:12 +08:00
joywayer
50f505279d
feat(enemy): BossPhaseAbilityGate——阶段即换招池
...
按阶段启停能力组件,被禁用的招经 CanUse 自动退出选招候选,
阶段门不需要碰选招器。取代 BossSkillSO.availablePhaseIndices。
EnterPhase 先换池后广播;OnSpawn 回阶段 0(对象池复用)。
2026-07-30 13:50:34 +08:00
joywayer
64d2087adc
fix(enemy): 禁用的能力组件不再报告可用
...
CanUse 纳入 enabled。此前禁用组件仍返回 true,选招器会选中一个
StartCoroutine 必然失败的招。这也是阶段门(按阶段启停能力)的前提。
2026-07-30 13:28:23 +08:00
joywayer and Claude Opus 5
0a92d21ce1
fix(enemy): 应用 Task 3 代码审查意见
...
补上池化路径的防重复记忆重置——ResetRepeatMemory 此前文档承诺了
「对象池复用时清除」却无任何调用点,而它要取代的 BossBase.LastUsedSkillId
恰好在 OnSpawn 里有重置。放 EnemyBase.OnSpawn 以覆盖全部池化敌人。
折扣系数改为每次选招前刷新,与 attackSelectionMode 的读取时机对齐——
此前策划在播放模式下调系数无效、调模式却立即生效,容易误判为功能没生效。
默认值收敛为 EnemyAttackSelector.DefaultAntiRepeatFactor 单一常量。
测试:IneligiblePrevious 用例改用系数 0.5——原先用 0 时,把折扣错写在
eligibility 归零之前也照样通过,是个永远不会失败的测试;统计用例边界由
7σ 收紧到 5σ 使其真正验证该系数;补 ResetRepeatMemory 的确定性用例、
系数 1.0 无惩罚、三候选三条。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-07-30 13:00:28 +08:00
joywayer and Claude Opus 5
eb3f4888a4
feat(enemy): 选招器支持防重复折扣——WeightedRandomAntiRepeat
...
上一次选中的招按 EnemyStatsSO.attackAntiRepeatFactor 折扣权重(默认 0.3)。
折扣把唯一候选压到 0 时退化为 Priority 路径,不会出现敌人永不出手。
阶段切换清空防重复记忆。取代 BossBase.UseBossSkillWeighted 里的同名逻辑。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-07-30 12:43:01 +08:00
joywayer and Claude Opus 5
2a1ada4388
fix(ai): 应用 Task 1+2 代码审查意见
...
ResourceFull 未挂 BossResource 时改为显式抛——原先静默返回 false,
是 CLAUDE.md 第 6 条禁止的下游兜底,且与紧邻的 Boss facet 行为不一致。
FakeBossControl.DistanceToAnchor 不再忽略 index。测试改用 TearDown 清理
(本项目关闭了 Domain/Scene Reload,失败断言会把物体永久留在打开的场景里)。
BeginPhaseTransition 去掉死的默认参数;接口补充重入契约说明。
顺带去重:FakeAiContext 实现 IEnemyActor,删除两个测试内的本地 Ctx 副本
——一个接口成员改动要同步三份是复发性成本。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-07-30 12:31:39 +08:00
joywayer and Claude Opus 5
3665504a58
feat(ai): 新增 IBossControl facet——Boss 阶段状态经 IAiContext 供图读取
...
非 Boss 敌人访问 IAiContext.Boss 显式抛 InvalidOperationException,
不返回空对象掩盖小怪图误挂 Boss 边的错误。BossResource 补 IsFull 供图条件边判定。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-07-30 12:15:54 +08:00
joywayer
afcc0b10ee
fix(enemy): 配方校验改用一次性 builder 探测,不再干扰共享图缓存
2026-07-30 08:33:53 +08:00
joywayer
da217af113
feat(enemy): AI 配方接入 SO 校验——漏配/歧义/零冷却 Committed 在编辑期与构建期报错
2026-07-29 17:20:12 +08:00
joywayer
6df4a259b7
docs(enemy): 修正作者指南与两处注释残留的死亡层表述
2026-07-29 16:34:21 +08:00
joywayer
ecdb0040cb
feat(editor): 敌人 AI 配方脚手架向导;AssignModules 改名并失效缓存
...
- AiRecipeSO 新增 protected InvalidateGraph(),子类装配模块后调用以丢弃缓存图,
避免改动要等到下次进 Play 才生效的静默陈旧图问题。
- PerceptionRecipeSO.SetModulesForTests 改名为 AssignModules(向导也要用它装配模块,
旧名字具有误导性),并在装配后调用 InvalidateGraph。
- 新增 EnemyAiRecipeWizard:按 AssetFolderSpec 定名定路径创建感知型 AI 配方资产
(Assets/_Game/Data/Enemies/{EnemyID}/ENM_{EnemyID}_Ai.asset),已存在则选中不覆盖。
- PerceptionRecipeSoTests 同步改名调用点,并新增测试钉住"装配后缓存必须失效"契约。
2026-07-29 15:28:25 +08:00
joywayer
825cae7977
feat(enemy): PerceptionRecipeSO 配方资产 + SubclassSelector 模块下拉
...
未发现层/交战层各用 [SerializeReference]+[SubclassSelector] 下拉挑选模块,
新增模块类自动出现在下拉里,无需改枚举或已有文件。默认交战模块仍为
RushEngagement——未配能力时建图必须显式报错,而非静默产出打不出手的图。
2026-07-29 14:46:41 +08:00
joywayer
7327a5fe09
refactor(enemy): 退役 PerceptionStateMachine,E001 切换到两层模块组装
2026-07-29 14:24:48 +08:00
joywayer
9dc10e0398
test(enemy): 补测骨架 × 另两个模块的组合,以及入口覆盖契约
2026-07-29 14:21:36 +08:00
joywayer
bf8101b3f5
feat(enemy): PerceptionSkeleton——两层可插拔的感知骨架,自声明死亡终态
2026-07-29 14:10:46 +08:00
joywayer
faa210c789
revert(enemy): 收掉死亡层——死亡归物理层,AI 只需一个终态
2026-07-29 14:02:13 +08:00
joywayer
5a9c1fd569
chore(enemy): 补齐死亡层模块的 .meta 文件
2026-07-29 13:46:45 +08:00
joywayer
3bc7eb1855
feat(enemy): 死亡层三模块(终态/单段/两段)
2026-07-29 13:46:20 +08:00
joywayer
3d00c66677
test(enemy): 补测 Attack 单出边的自愈路径,写明边序依赖的射程前提
...
Approach 边序注释:attackInRange 先于 leftAllZones 的前提是攻击射程恒小于
感知区(EnemyAttackSelector.Eligible 的 InAttackRange 门),故两条件不会相争;
若未来出现射程更大的招式,应由 AI 配方校验器报错,而非靠调边序绕开。
FakeCombat 新增 BestAttackFails 开关(与 Eligible 解耦),补测 Attack 唯一出边
attackDone 的自愈不变量:UseBestAttack 触发失败时不留下运行中能力,下一帧即可
自愈回 Approach,不会永久卡死。
2026-07-29 13:08:46 +08:00
joywayer
9d632cd103
fix(enemy): 退回 Approach 边序——脱战优先属假件失真,改由测试贴合真实射程语义
...
HasEligibleAttack() 只看攻击射程圆(远小于追击/视野区),脱离全部感知区在真实系统里
必然已脱离攻击射程,原顺序(attackInRange 先于 leftAllZones)本就正确。
FakeCombat.Eligible 是裸字段不会随 Chase/Vision 联动,才让上一版看似需要调边序。
改法:边序退回原样,测试里玩家离开感知区时手工同步清 Eligible,贴合真实耦合关系。
2026-07-29 12:59:07 +08:00
joywayer
a700bef352
feat(enemy): ApproachAttackEngagement——攻击改为起手即打完,不中途收招
...
寻路逼近↔到射程选招攻击的交战模块。招式射程/冷却/权重归 EnemyAttackSelector,
本模块只决定何时逼近、何时出手。
有意的行为变更:Attack 态去掉 leftAllZones 边,玩家在前摇中跑出感知区不再
中途打断招式,招式完整打完后经 Approach 自然脱战。
2026-07-29 12:53:49 +08:00
joywayer
5771ac414e
test(enemy): 补测 Committed 冲锋的防抖动闭环,RushExit 写明冷却前提
2026-07-29 12:45:43 +08:00
joywayer
bb1e2f7705
feat(enemy): RushEngagement——两个耦合 flag 合并为 RushExit 语义枚举
2026-07-29 12:32:50 +08:00
joywayer and Claude Opus 5
1c6ce57648
test(enemy): 修正测试名——该用例只验证空 Link 不加边,不涉及单向不可逆
...
原名 DisguiseThenPatrol_HasNoInternalEdges_DisguiseIsOneWay 承诺了
"伪装态不可逆",但那需要骨架的升级边才能验证(T10 覆盖)。
此用例实际只证明 Link 为空时状态不会自行跑掉,按实测内容改名。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-07-29 12:26:42 +08:00
joywayer
acfba66c5d
feat(enemy): 未发现层三模块(单一态/单向降级/定时交替)
2026-07-29 12:19:26 +08:00
joywayer
894ae99984
test(ai): 补测经 AiStateFragments 的跨模块状态撞名,State() 补引导注释
2026-07-29 12:11:07 +08:00
joywayer
80fdc36762
feat(ai): BrainBuilder.DeclareState——重复声明状态即报错,防模块间同名静默覆盖
...
State() 仍保持宽松(有则取),用于给已声明的态挂边;DeclareState() 只用于
首次声明行为,重复声明同名状态会抛异常。AiStateFragments 的四个建态原语
(Locomotion/Ability/AbilityOnce/Terminal)改用 DeclareState。同时给
IEngagementModule/IDeathModule/IUnawareModule 补充不变量说明。
2026-07-29 12:01:19 +08:00
joywayer
68f615e9c1
fix(enemy): AiStateFragments 空能力 id 建图期报错,补 OnExit 收尾测试
...
Ability/AbilityOnce 建图期校验 abilityId 非空,与 BrainBuilder.RequireState
同一类"漏配即快速失败"约束保持一致,避免定制 AiScript 漏配 id 时产出静默
不作为的状态。同时补 4 个测试:Locomotion/Ability 的 OnExit 收尾行为,以及
两个原语对空 id 的报错行为。
2026-07-29 11:42:47 +08:00
joywayer
77a32cbf8a
feat(enemy): AiStateFragments 建态原语,新增 AbilityOnce 修死亡态重触发隐患
...
从 PerceptionStateMachine 的 private static 辅助方法提升为公开原语,供后续
模块化重构(骨架+可插拔模块)与定制 AiScript 复用。新增 AbilityOnce:
只在进入时触发能力、不每帧重触发,修复用 Ability() 驱动死亡态时演出播完
被 Tick 无限重播的隐患(现有 PerceptionStateMachine 因 E001 死亡能力 id
为空未暴露,本次不改它,留待 T11 整体退役)。
2026-07-29 11:35:47 +08:00
joywayer
084354fa6c
test(enemy): AbilityRef 补测资产已挂但 abilityId 为空的误配路径
2026-07-29 11:29:47 +08:00
joywayer
474e89de3a
feat(enemy): AbilityRef——AI 层能力引用资产化,字符串仅作定制脚本兜底
2026-07-29 11:22:15 +08:00
joywayer
fd238b71f1
refactor(ai): AiSignal 8→1,删除零发送方零消费方的死枚举
2026-07-29 11:14:29 +08:00
joywayer
e76d6bc118
feat(ai): BrainBuilder.RequireState——未声明状态挂边时构建期报错
2026-07-29 11:08:23 +08:00
joywayer
3c622a69f2
refactor(enemy): NavLinkType 迁入 INavLinkHandler 并改述为能力驱动的地形穿越;补交新脚本 .meta
2026-07-28 11:50:17 +08:00
joywayer
c041712e99
fix(test): 到达边界用例改用二进制可精确表示的值(1.25/0.25),避免浮点噪声误判
2026-07-28 11:15:16 +08:00
joywayer
668bc3500e
feat(enemy): 新增 GroundNavigator 地面直接移动导航(+7 纯函数单测)
...
补充 EditMode 测试程序集对 BaseGames.Enemies.Navigation 的引用(此前缺失,新测试无法编译)
2026-07-28 11:12:11 +08:00
joywayer
8ea919a7f1
chore(enemy): 补交 StallDetector 与其测试的 .meta
2026-07-28 11:07:06 +08:00
joywayer
5cfacf199a
feat(enemy): 新增 StallDetector 推进停滞检测(+8 单测),为收敛三处重复实现做准备
2026-07-28 11:01:01 +08:00
joywayer
b1d3c169ec
chore(enemy): 补交 EnemyBody 与其测试的 .meta
2026-07-27 12:07:46 +08:00
joywayer
b0e1ebfecc
feat(enemy): 新增 IEnemyBody 身体几何权威接口与 EnemyBody 实现(+14 纯函数单测)
2026-07-27 11:48:26 +08:00
joywayer
86e3637d8e
chore(core): 补交 WeightedPick 与其测试的 .meta
2026-07-27 10:00:59 +08:00
joywayer
3d85f65965
feat(core): 新增 WeightedPick 加权随机共享原语(+10 单测),为消除四处平行实现做准备
2026-07-27 09:54:34 +08:00
joywayer
568b6e46c0
chore(enemy): 补交新脚本的 .meta(AbilityCategory/AttackSelectionMode/IAttackCandidate/EnemyAttackSelector+测试)
2026-07-24 14:55:17 +08:00
joywayer
022e4f18d2
fix(enemy): Approach 逼近改用 aggro/视野双刷新的 LastKnown(修 aggro 先命中扑向错误点)+补 Attack 退出测试
2026-07-24 12:47:48 +08:00