diff --git a/assets/script/game/hero/HeroAttrsComp.ts b/assets/script/game/hero/HeroAttrsComp.ts index ad16369d..0783778f 100644 --- a/assets/script/game/hero/HeroAttrsComp.ts +++ b/assets/script/game/hero/HeroAttrsComp.ts @@ -8,6 +8,11 @@ import { HeroViewComp } from "./HeroViewComp"; import { _decorator } from "cc"; +/** + * 可撤销的属性型 Buff/Debuff 实例 + * - 仅用于 Timed 类型 + * - 进入 BUFFS/DEBUFFS 后会在到期时自动反向回滚 + */ interface ActiveBuffState { id: number attr: Attrs @@ -16,6 +21,11 @@ interface ActiveBuffState { BType: BType time: number } +/** + * 间隔触发型效果实例 + * - 不直接进入 BUFFS/DEBUFFS + * - 由 HeroBuffSystem 每帧推进 tick/remain 并触发执行 + */ interface IntervalBuffState { id: number attr: Attrs @@ -174,6 +184,7 @@ export class HeroAttrsComp extends ecs.Comp { addBuff(buffConf: BuffConf) { const normalized = this.normalizeBuffValue(buffConf); const runType = this.resolveRunType(buffConf); + // Interval:按间隔触发,写入 INTERVAL_EFFECTS,由系统统一执行 if (runType === BuffRunType.Interval) { const interval = buffConf.interval && buffConf.interval > 0 ? buffConf.interval : 1; const remain = buffConf.time > 0 ? buffConf.time : interval; @@ -189,10 +200,12 @@ export class HeroAttrsComp extends ecs.Comp { }); return; } + // Permanent:一次性生效,不写入 BUFFS/DEBUFFS,不存在自动撤销 if (runType === BuffRunType.Permanent) { this.applyAttrChange(buffConf.buff, normalized.value, normalized.BType); return; } + // Timed:先应用,再记录,后续 updateList 到期后自动反向移除 const duration = buffConf.time > 0 ? buffConf.time : 1; const targetList = buffConf.isDebuff ? this.DEBUFFS : this.BUFFS; @@ -216,12 +229,23 @@ export class HeroAttrsComp extends ecs.Comp { mLogger.log(this.debugMode, 'HeroAttrs', `添加Buff: ${buffConf.name}, 属性:${buffConf.buff}, 值:${normalized.value}, 时间:${duration}`); } + /** + * runType 解析优先级: + * 1) 显式配置 runType + * 2) 兼容旧配置:存在 interval 视为 Interval + * 3) time>0 视为 Timed,否则 Permanent + */ private resolveRunType(buffConf: BuffConf): BuffRunType { if (buffConf.runType !== undefined) return buffConf.runType; if (buffConf.interval && buffConf.interval > 0) return BuffRunType.Interval; return buffConf.time > 0 ? BuffRunType.Timed : BuffRunType.Permanent; } + /** + * 把配置值统一转换为“可直接写入容器和结算”的数值 + * - RATIO 会在写入前转换为 VALUE + * - BOOLEAN 保持原类型 + */ private normalizeBuffValue(buffConf: BuffConf): { value: number; BType: BType } { if (buffConf.BType === BType.BOOLEAN) { return { value: buffConf.value, BType: BType.BOOLEAN }; @@ -335,6 +359,10 @@ export class HeroAttrsComp extends ecs.Comp { this.updateStatusFlags(); } + /** + * 仅做“采集触发事件”,不做数值执行 + * 实际执行由 HeroBuffSystem.applyIntervalEffect 统一处理 + */ collectIntervalEffectsBySystem(dt: number): IntervalBuffState[] { const triggered: IntervalBuffState[] = []; for (let i = this.INTERVAL_EFFECTS.length - 1; i >= 0; i--) { @@ -364,6 +392,11 @@ export class HeroAttrsComp extends ecs.Comp { this.applyAttrChange(attr, value, type); } + /** + * Timed Buff/Debuff 到期更新 + * - 到期时调用 applyAttrChange(reverse=true) 回滚 + * - 该函数只处理 BUFFS/DEBUFFS,不处理 INTERVAL_EFFECTS + */ private updateList(list: Record, dt: number) { for (const attrKey in list) { const buffs = list[attrKey]; @@ -538,15 +571,23 @@ export class HeroBuffSystem extends ecs.ComblockSystem implements ecs.ISystemUpd if (!smc.mission.play || smc.mission.pause) return; const attrs = e.get(HeroAttrsComp); if (!attrs || attrs.is_dead) return; + // 1) 推进 Timed Buff/Debuff 生命周期 attrs.updateBuffsDebuffs(this.dt); + // 2) 收集本帧到点的 Interval 触发 const triggered = attrs.collectIntervalEffectsBySystem(this.dt); if (triggered.length === 0) return; const view = e.get(HeroViewComp); + // 3) 统一执行数值与表现 for (const effect of triggered) { this.applyIntervalEffect(attrs, view, effect); } } + /** + * 间隔效果统一执行入口 + * - 先做数值结算 + * - 再按实际变化触发表现,避免无效动画 + */ private applyIntervalEffect(attrs: HeroAttrsComp, view: HeroViewComp | null, effect: IntervalBuffState) { if (effect.attr === Attrs.hp) { const oldHp = attrs.hp;