SKILL.md
Full skill instructions
技能系统架构设计
当前技能系统已经彻底切换为 纯代码驱动的 ECS + Observer 架构。
系统中不再存在以下能力:
SkillEffectSkillAction- “静态动作表”
- 基于 effect 资产的技能执行分发
所有技能都必须通过 Rust 代码响应 EventSkillCast,由 observer 直接编排动作、状态、窗口和冷却。
设计目标
docs/champions 中的英雄技能包含大量固定动作表无法正确表达的机制:
- 分段技能:锐雯 Q、剑魔 Q、鳄鱼 E、刀妹 E
- 二段窗口:盲僧 Q/W/E、卡蜜尔 E
- 形态/强化态:纳尔、凯隐、鳄鱼、潘森
- 标记与被动联动:剑姬要害、诺手血怒、沃利贝尔 W、塞拉斯偷大
- 条件冷却:命中减冷却、击杀刷新、终段才进主冷却
- 复杂目标逻辑:最近目标、命中英雄才刷新、对特定目标开放二段
这类逻辑如果继续用静态配置表达,只会把复杂性转移到隐蔽角落。
因此现在的原则很直接:
- 技能的行为写在代码里
- 技能的状态挂在 ECS 实体上
- 统一施法管线只负责校验和派发
核心原则
1. 技能是实体
每个技能都对应一个独立实体,通过:
SkillOfSkillsPassiveSkillOf
挂到英雄实体上。
技能实体本身承担状态,而不是只做索引占位。
常见状态包括:
- 技能等级
- 冷却
- 重施窗口
- 当前阶段
- 临时标记
- 形态相关信息
2. 施法走统一入口
统一施法链路如下:
- 输入层触发
CommandAction Action::Skill转发为CommandSkillBeforeStart与CommandSkillStarton_skill_cast完成通用校验- 校验通过后触发
EventSkillCast - 具体技能 observer 接管后续逻辑
统一入口负责的只有这些通用职责:
- 查找技能实体
- 校验技能是否已学习
- 校验资源
- 校验冷却
- 记录施法日志
- 按统一规则启动默认冷却
具体技能行为不再放在这个入口里。
3. observer 是唯一技能执行方式
技能施法通过校验后,会触发:
EventSkillCast {
entity,
skill_entity,
index,
point,
}
之后必须由 observer 处理。
observer 可以直接:
- 读取技能槽位
- 查询技能实体状态
- 查询施法者状态
- 决定表现
- 决定判定
- 推进阶段
- 启动或延后冷却
这让复杂技能的逻辑和状态推进保持在一处,可读、可测、可调试。
核心数据结构
Skill
Skill 现在只表达代码驱动技能所需的最小元数据:
spelllevelslotcooldown_mode
字段语义:
spell:数值来源level:技能等级slot:Q/W/E/R/Passive/Customcooldown_mode:默认施法后冷却,或手动冷却
不再包含:
- effect key
- 执行模式切换
- 静态动作定义
SkillCooldownMode
当前有两种冷却方式:
AfterCastManual
AfterCast 适用于:
- 普通单段技能
- 按下即进入冷却的技能
Manual 适用于:
- 分段技能
- 二段技能
- 终段才进入主冷却的技能
SkillRecastWindow
这是当前最基础的通用技能状态组件。
包含:
stagemax_stagetimer
用于表示:
- 当前处于第几段
- 最多可重施到第几段
- 剩余重施时间
任何二段/三段技能都应优先考虑基于这个组件建模。
SkillCastLog
系统会记录每次施法尝试,供测试和调试使用。
日志内容包括:
- 施法者
- 技能实体
- 索引
- 槽位
- 目标点
- 成功或失败原因
当前失败原因覆盖:
- 缺少技能列表
- 非法索引
- 技能实体不存在
- spell object 缺失
- 技能未学习
- 资源组件缺失
- 资源不足
- 冷却中
这保证了技能行为可以在 headless 环境里直接断言,而不是只能看视觉结果。
动作触发方式
虽然不再有 SkillAction,但技能行为仍然是由一组标准化原子动作拼装出来的。
当前常用原子包括:
play_skill_animation(...)spawn_skill_particle(...)despawn_skill_particle(...)skill_dash(...)skill_damage(...)reset_skill_attack(...)
这些函数只是对已有 action/event 的代码封装,不是新的数据层。
它们的作用是:
- 降低 observer 中的重复样板
- 保持技能代码直接可读
- 不重新引入静态 effect 配置层
推荐实现范式
1. 单段技能
适合:
- 一个施法动作
- 一次位移或一次伤害
- 无复杂阶段状态
实现方式:
- 注册
Skill::new(slot, spell_key) - 在
EventSkillCast中按slot匹配 - 直接调用动画、粒子、伤害、位移等原子函数
2. 分段技能
适合:
- 锐雯 Q
- 盲僧二段技能
- 鳄鱼 E
实现方式:
- 使用
SkillCooldownMode::Manual - 在技能实体上挂
SkillRecastWindow - observer 根据
stage决定当前段行为 - 非终段只刷新窗口,不进入主冷却
- 终段结束后手动启动冷却
3. 被动技能
被动技能仍然是技能实体,但通常不走主动施法路径。
它们应通过:
PassiveSkillOf- observer
- 周期系统
- 伤害/攻击/状态事件
与主动技能和角色行为联动。
典型例子:锐雯 Q
锐雯 Q 是当前纯代码驱动技能的样板。
实现结构:
- 技能实体槽位为
Q - 冷却模式为
Manual - observer 监听
EventSkillCast - 从技能实体读取
SkillRecastWindow - 根据
stage分别执行 Q1/Q2/Q3 - Q1/Q2 写回下一段窗口
- Q3 清理窗口并手动启动冷却
这个实现直接对应文档里的真实语义:
- 分段状态不再通过替换 effect key 实现
- 主冷却时机由技能自己决定
- 技能逻辑与技能状态写在一处
面向英雄文档的建模建议
根据 docs/champions,后续技能可以按以下方式建模:
A. 分段/重施技能
优先使用:
SkillRecastWindowManual冷却EventSkillCastobserver
代表:
- Riven Q
- Lee Sin Q/W/E
- Renekton E
- Irelia E
B. 形态/强化态技能
优先使用:
- 英雄实体上的形态状态
- 技能实体上的局部状态
- observer 中的显式分支
代表:
- Gnar 变身
- Kayn 形态
- Renekton 怒气强化
- Pantheon 被动强化
C. 命中刷新/击杀刷新
优先使用:
- 伤害或命中事件 observer
- 直接修改技能实体冷却或窗口
代表:
- Fiora Q 命中减冷却
- Irelia Q 刷新
- Hecarim Q 叠层减冷却
D. 被动标记系统
优先使用:
- 被动技能实体
- 目标身上的标记组件
- 伤害事件联动
代表:
- Fiora Vital
- Darius 血怒
- Volibear W
- Sylas R 偷取大招
当前结论
现在的技能系统是彻底的代码驱动版本:
- 技能行为全部由 observer 实现
- 技能状态全部挂在 ECS 实体上
- 统一施法管线只做通用校验和派发
- 不再依赖任何静态 effect 配置
这套设计才能覆盖 docs/champions 中那些真正复杂的英雄机制,并在 lol_core::skill::tests / lol_champions::<hero>::tests 中保持足够高的可测试性。
