Files
pixelheros/docs/superpowers/specs/2026-07-23-timed-buff-system-design.md
pan c4e7f2584b feat(hero): 新增完整计时性Buff/Debuff系统
本次提交实现了游戏内完整的计时性增益/减益系统,包含:
1. 新增Buff配置表与运行时数据组件
2. 实现属性修饰器与最终属性计算逻辑
3. 完成Buff管理、计时结算与周期效果处理
4. 兼容旧有控制状态系统,支持平滑过渡
5. 附带完整的系统设计文档

同时关闭了两个闲置的任务界面节点。
2026-07-23 15:48:59 +08:00

160 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 计时性 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 Systemtick 驱动
└── BuffManager.ts 新增:对外 APIapply/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 驱动
- 永久 buffduration=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 2HeroAttrsComp 新增 getter不改旧字段
- Step 3SkillSet 新增 timed_buff_idSCastSystem 新旧路径并存,消费方逐个改用 getter
- Step 4控制类 buff 迁移(双写),最后删除 HeroBuffSystem 与旧字段
## 9. 风险与兜底
| 风险 | 兜底 |
|---|---|
| getter 未覆盖所有读取点 | grep 全量排查 |
| max_stack=0 无限叠加内存泄漏 | 超阈值打 warning |
| BuffComp 未 reset 残留 | reset() 清空,英雄回收时调用 |
| 双 System 冲突 | 兼容期 BuffSystem 接管HeroBuffSystem 改空或删除 |