feat(hero): 新增完整计时性Buff/Debuff系统
本次提交实现了游戏内完整的计时性增益/减益系统,包含: 1. 新增Buff配置表与运行时数据组件 2. 实现属性修饰器与最终属性计算逻辑 3. 完成Buff管理、计时结算与周期效果处理 4. 兼容旧有控制状态系统,支持平滑过渡 5. 附带完整的系统设计文档 同时关闭了两个闲置的任务界面节点。
This commit is contained in:
159
docs/superpowers/specs/2026-07-23-timed-buff-system-design.md
Normal file
159
docs/superpowers/specs/2026-07-23-timed-buff-system-design.md
Normal file
@@ -0,0 +1,159 @@
|
||||
# 计时性 Buff/Debuff 系统设计
|
||||
|
||||
> 日期:2026-07-23
|
||||
> 状态:已批准,待实现
|
||||
|
||||
## 1. 目标与范围
|
||||
|
||||
为英雄/怪物添加通用的计时性 buff/debuff 机制,覆盖四类需求:
|
||||
- 限时的属性加成/削弱(如"10秒内攻击+30%")
|
||||
- 周期性跳伤害/治疗 DoT/HoT(如中毒、灼烧、再生)
|
||||
- 统一现有冰冻/击晕的计时框架,便于扩展更多控制效果
|
||||
- 数据层完整记录 buff 状态(UI 展示本期不做,预留脏标记)
|
||||
|
||||
## 2. 核心架构决策
|
||||
|
||||
| 维度 | 决策 |
|
||||
|---|---|
|
||||
| 属性计算模型 | 修饰器模型(读取时重算,无残留风险) |
|
||||
| 叠加规则 | 可叠层,每层独立计时 |
|
||||
| 配置组织 | 独立 `BuffSet.ts` 配置表 |
|
||||
| 架构方案 | 方案 A:原字段=base + 修饰器表 |
|
||||
|
||||
## 3. 模块划分
|
||||
|
||||
```
|
||||
assets/script/game/
|
||||
├── common/config/
|
||||
│ ├── BuffSet.ts 新增:buff 静态配置表(id → 定义)
|
||||
│ └── HeroAttrs.ts 复用现有 Attrs 枚举
|
||||
└── hero/
|
||||
├── HeroAttrsComp.ts 改造:新增 getFinalXxx() getter
|
||||
├── BuffComp.ts 新增:ECS Comp,持有 buffs 运行时实例
|
||||
├── BuffSystem.ts 新增:ECS System,tick 驱动
|
||||
└── BuffManager.ts 新增:对外 API(apply/dispel/查询)
|
||||
```
|
||||
|
||||
职责边界:
|
||||
- `BuffSet.ts`:纯静态配置,无运行时状态
|
||||
- `BuffComp.ts`:挂实体上的运行时数据,不写逻辑
|
||||
- `BuffSystem.ts`:固定 tick 推进 buff(倒计时/DoT/到期)
|
||||
- `BuffManager.ts`:对外门面,屏蔽 ECS 细节
|
||||
|
||||
## 4. 数据模型
|
||||
|
||||
### BuffSet.ts — 静态配置
|
||||
|
||||
```ts
|
||||
export enum BuffCategory {
|
||||
Buff = 0, // 正面增益
|
||||
Debuff = 1, // 负面减益
|
||||
Control = 2, // 控制(冰冻/击晕/减速)
|
||||
}
|
||||
|
||||
export enum ModOp {
|
||||
Flat = 0, // 固定值
|
||||
PercentAdd = 1, // 百分比(加算)
|
||||
PercentMul = 2, // 百分比(乘算,预留)
|
||||
}
|
||||
|
||||
export interface BuffModifier {
|
||||
attr: Attrs;
|
||||
op: ModOp;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export interface BuffTickEffect {
|
||||
interval: number; // 触发间隔(秒)
|
||||
damage_or_heal: number; // 正=治疗,负=伤害
|
||||
scale_by_ap_pct: number; // 按施法者 ap 缩放百分比,0=不吃加成
|
||||
}
|
||||
|
||||
export interface BuffConfig {
|
||||
id: number;
|
||||
name: string;
|
||||
icon: string;
|
||||
category: BuffCategory;
|
||||
duration: number; // 单层持续时间(秒),0=永久
|
||||
max_stack: number; // 默认 0=无限叠加;1=不可叠层;N=最多N层
|
||||
modifiers?: BuffModifier[];
|
||||
tick?: BuffTickEffect;
|
||||
is_control?: boolean;
|
||||
control_kind?: 'frost' | 'stun' | 'none';
|
||||
info: string;
|
||||
}
|
||||
|
||||
export const BuffList: Record<number, BuffConfig> = { /* 配置项 */ };
|
||||
```
|
||||
|
||||
### BuffComp.ts — 运行时实例
|
||||
|
||||
```ts
|
||||
export class ActiveBuff {
|
||||
config_id: number;
|
||||
remaining: number;
|
||||
source_uuid: number;
|
||||
source_ap_snapshot: number; // 施法时锁定
|
||||
tick_acc: number = 0;
|
||||
}
|
||||
|
||||
@ecs.register('Buff')
|
||||
export class BuffComp extends ecs.Comp {
|
||||
buffs: Map<number, ActiveBuff[]> = new Map();
|
||||
dirty_buffs: boolean = false; // 预留 UI 消费
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 修饰器模型与最终值计算
|
||||
|
||||
HeroAttrsComp 原字段(ap/hp_max/critical 等)保持原语义(基础值 + 永久加成),新增 getter:
|
||||
|
||||
```
|
||||
final = (base + Σ_flat_timed) × (1 + Σ_pctAdd_timed / 100)
|
||||
```
|
||||
|
||||
- flat 优先于 pct:先加固定值,再乘百分比
|
||||
- 驻场加成并入 getter,避免"忘记乘驻场"
|
||||
- `add_ap`/`add_hp_max`/`add_special_attr` 语义不变,继续改 base
|
||||
- getter 不缓存,避免脏数据;实测有热点再加 dirty
|
||||
|
||||
## 6. BuffSystem 驱动逻辑
|
||||
|
||||
- 固定步长 0.1s(与现有 HeroBuffSystem 一致),用 Timer(0.1)
|
||||
- 每层独立倒计时,到期 splice 移除
|
||||
- DoT/HoT:每层独立 tick_acc,到 interval 跳一次,`tick_acc -= interval` 保留余数
|
||||
- DoT 数值按施法时 ap 快照缩放,不在结算时重读施法者
|
||||
- 控制类 buff 双写兼容:施加时同时调用现有 toFrost/toStun;现有字段继续由 BuffSystem.tickLegacyControl 驱动
|
||||
- 永久 buff(duration=0)不递减 remaining,只能被 dispel 清除
|
||||
|
||||
## 7. BuffManager API
|
||||
|
||||
```ts
|
||||
applyBuff(target, buffId, sourceUuid?, sourceAp?, overrides?): void
|
||||
dispel(target, category?, excludeIds?): number
|
||||
getStack(target, buffId): number
|
||||
hasControl(target, kind): boolean
|
||||
```
|
||||
|
||||
叠层规则(max_stack 默认 0=无限叠加):
|
||||
- max_stack=0:每次施加都新增层
|
||||
- 未满:新增层
|
||||
- 已满(≥1):替换最老层(刷新)
|
||||
|
||||
驱散后控制类需 recomputeControlState:同 kind 还有任意层则保持,否则清除。
|
||||
|
||||
## 8. 迁移策略
|
||||
|
||||
- Step 1:新增 buff 基础设施(纯加法,零风险)
|
||||
- Step 2:HeroAttrsComp 新增 getter,不改旧字段
|
||||
- Step 3:SkillSet 新增 timed_buff_id,SCastSystem 新旧路径并存,消费方逐个改用 getter
|
||||
- Step 4:控制类 buff 迁移(双写),最后删除 HeroBuffSystem 与旧字段
|
||||
|
||||
## 9. 风险与兜底
|
||||
|
||||
| 风险 | 兜底 |
|
||||
|---|---|
|
||||
| getter 未覆盖所有读取点 | grep 全量排查 |
|
||||
| max_stack=0 无限叠加内存泄漏 | 超阈值打 warning |
|
||||
| BuffComp 未 reset 残留 | reset() 清空,英雄回收时调用 |
|
||||
| 双 System 冲突 | 兼容期 BuffSystem 接管,HeroBuffSystem 改空或删除 |
|
||||
Reference in New Issue
Block a user