refactor(hero): 移除复杂的buff系统并简化属性管理

- 删除Buff/Debuff状态管理相关的接口和数据结构
- 简化addBuff方法,直接应用属性变化而不处理buff生命周期
- 移除Interval、Timed、Permanent等buff类型的处理逻辑
- 简化属性应用逻辑,仅支持AP、HP_MAX、SHIELD_MAX三种属性
- 删除HeroBuffSystem中的buff更新逻辑,系统现在为空实现
- 移除状态检查的复杂逻辑,isStun和isFrost直接返回false
This commit is contained in:
panw
2026-03-19 17:10:37 +08:00
parent e2cac41753
commit a58dc818ee

View File

@@ -1,41 +1,8 @@
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { Attrs, BType } from "../common/config/HeroAttrs";
import { BuffConf, BuffRunType } from "../common/config/SkillSet";
import { HeroDisVal, HeroInfo, HType } from "../common/config/heroSet";
import { BuffConf } from "../common/config/SkillSet";
import { HeroDisVal, HType } from "../common/config/heroSet";
import { mLogger } from "../common/Logger";
import { smc } from "../common/SingletonModuleComp";
import { HeroViewComp } from "./HeroViewComp";
import { _decorator } from "cc";
/**
* 可撤销的属性型 Buff/Debuff 实例
* - 仅用于 Timed 类型
* - 进入 BUFFS/DEBUFFS 后会在到期时自动反向回滚
*/
interface ActiveBuffState {
id: number
attr: Attrs
sourceUuid: number
value: number
BType: BType
time: number
}
/**
* 间隔触发型效果实例
* - 不直接进入 BUFFS/DEBUFFS
* - 由 HeroBuffSystem 每帧推进 tick/remain 并触发执行
*/
interface IntervalBuffState {
id: number
attr: Attrs
sourceUuid: number
value: number
BType: BType
interval: number
remain: number
tick: number
}
@ecs.register('HeroAttrs')
export class HeroAttrsComp extends ecs.Comp {
public debugMode: boolean = false;
@@ -96,13 +63,6 @@ export class HeroAttrsComp extends ecs.Comp {
maxSkillDistance: number = 0; // 最远技能攻击距离缓存受MP影响
minSkillDistance: number = 0; // 最近技能攻击距离缓存不受MP影响用于停止位置判断
// ==================== Buff/Debuff 系统 ====================
/** 持久型buff数组 - 不会自动过期 */
BUFFS: Record<number, ActiveBuffState[]> = {};
DEBUFFS: Record<number, ActiveBuffState[]> = {};
INTERVAL_EFFECTS: IntervalBuffState[] = [];
private buffInstanceId = 0;
// ==================== 标记状态 ====================
is_dead: boolean = false;
is_count_dead: boolean = false;
@@ -132,16 +92,8 @@ export class HeroAttrsComp extends ecs.Comp {
* 从 HeroInfo 读取初始配置,建立属性系统
*/
initAttrs() {
// 清空现有 buff/debuff
this.BUFFS = {};
this.DEBUFFS = {};
this.INTERVAL_EFFECTS = [];
this.buffInstanceId = 0;
// 获取英雄配置
const heroInfo = HeroInfo[this.hero_uuid];
if (!heroInfo) return;
this.in_stun = false;
this.in_frost = false;
}
/*******************基础属性管理********************/
@@ -188,95 +140,24 @@ 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;
this.INTERVAL_EFFECTS.push({
id: ++this.buffInstanceId,
attr: buffConf.buff,
sourceUuid: buffConf.uuid,
value: normalized.value,
BType: normalized.BType,
interval,
remain,
tick: interval
});
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;
const attrKey = buffConf.buff as unknown as number; // 强制转换 key 类型以适配 Record
if (!targetList[attrKey]) {
targetList[attrKey] = [];
}
const currentBuffs = targetList[attrKey];
currentBuffs.push({
id: ++this.buffInstanceId,
attr: buffConf.buff,
sourceUuid: buffConf.uuid,
value: normalized.value,
BType: normalized.BType,
time: duration
});
this.applyAttrChange(buffConf.buff, normalized.value, normalized.BType);
if (this.debugMode) {
mLogger.log(this.debugMode, 'HeroAttrs', `添加Buff: ${buffConf.name}, 属性:${buffConf.buff}, 值:${normalized.value}, 时间:${duration}`);
mLogger.log(this.debugMode, 'HeroAttrs', `添加属性: ${buffConf.name}, 属性:${buffConf.buff}, 值:${normalized.value}`);
}
}
/**
* 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 };
}
return {
value: this.resolveBuffValue(buffConf.buff, buffConf.value, buffConf.BType),
value: buffConf.value,
BType: BType.VALUE
};
}
private resolveBuffValue(attr: Attrs, value: number, type: BType): number {
if (type !== BType.RATIO) return value;
if (attr === Attrs.hp || attr === Attrs.shield) {
return this.hp_max * value / 100;
}
if (attr === Attrs.hp_max || attr === Attrs.shield_max) {
return this[attr] * value / 100;
}
if (typeof this[attr] === "number") {
return (this[attr] as number) * value / 100;
}
return value;
}
/**
* 通用属性修改应用
* @param attr 属性名
@@ -285,48 +166,25 @@ export class HeroAttrsComp extends ecs.Comp {
* @param reverse 是否反向应用 (用于移除 buff)
*/
private applyAttrChange(attr: Attrs, value: number, type: BType, reverse: boolean = false) {
const mappedAttr = attr === Attrs.hp ? Attrs.hp_max : (attr === Attrs.shield ? Attrs.shield_max : attr);
if (mappedAttr !== Attrs.ap && mappedAttr !== Attrs.hp_max && mappedAttr !== Attrs.shield_max) return;
void type;
let finalValue = value;
// 如果是移除 buff取反
if (reverse) {
finalValue = -value;
}
if (reverse) finalValue = -finalValue;
// 护盾特殊处理:同时修改当前值和最大值
if (attr === Attrs.shield && type === BType.VALUE) {
this.shield += finalValue;
this.shield_max += finalValue;
this.shield = Math.max(0, this.shield);
this.shield_max = Math.max(0, this.shield_max);
this.dirty_shield = true;
if (mappedAttr === Attrs.ap) {
this.ap = Math.max(0, this.ap + finalValue);
return;
}
if (type === BType.RATIO) {
finalValue = this.resolveBuffValue(attr, finalValue, BType.RATIO);
if (typeof this[attr] === 'number') {
this[attr] = (this[attr] as number) + finalValue;
}
} else if (type === BType.BOOLEAN) {
// 布尔型/状态型value > 0 为 true/计数+1移除时 -1
// 这里使用计数器方式来支持多个同类状态叠加
// 例如 IN_FROST 是一个状态,不是属性。
// 需要在 HeroAttrsComp 中定义对应的状态计数器,或者利用 DEBUFFS 列表的存在性判断状态
// 暂时直接修改属性(如果属性是 boolean
if (typeof this[attr] === 'boolean') {
this[attr] = !reverse; // 添加设为 true, 移除设为 false (不仅确,多个冰冻会出问题)
// 正确做法updateBuffsDebuffs 中根据列表是否为空来设置状态
}
} else {
// VALUE 固定值
if (typeof this[attr] === 'number') {
this[attr] = (this[attr] as number) + finalValue;
}
if (mappedAttr === Attrs.hp_max) {
this.hp_max = Math.max(1, this.hp_max + finalValue);
if (this.hp > this.hp_max) this.hp = this.hp_max;
this.dirty_hp = true;
return;
}
// 标记脏数据(如果有对应的 dirty 标记)
if (attr === Attrs.hp) this.dirty_hp = true;
if (attr === Attrs.shield) this.dirty_shield = true;
this.shield_max = Math.max(0, this.shield_max + finalValue);
this.shield = Math.max(0, Math.min(this.shield + finalValue, this.shield_max));
this.dirty_shield = true;
}
//======更新cd========//
updateCD(dt: number){
@@ -340,10 +198,10 @@ export class HeroAttrsComp extends ecs.Comp {
}
}
isStun(): boolean {
return this.in_stun;
return false;
}
isFrost(): boolean {
return this.in_frost;
return false;
}
triggerAtkCD() {
this.a_cd = 0;
@@ -353,103 +211,8 @@ export class HeroAttrsComp extends ecs.Comp {
this.s_cd = 0;
this.can_skill = false;
}
// ==================== 临时 BUFF/DEBUFF 更新 ====================
/**
* 更新临时 buff/debuff 的剩余时间
* @param dt 时间增量
*/
updateBuffsDebuffs(dt: number) {
this.updateList(this.BUFFS, dt);
this.updateList(this.DEBUFFS, dt);
// 更新状态标记 (根据 DEBUFFS 列表是否存在有效项)
this.updateStatusFlags();
}
/**
* 仅做“采集触发事件”,不做数值执行
* 实际执行由 HeroBuffSystem.applyIntervalEffect 统一处理
*/
collectIntervalEffectsBySystem(dt: number): IntervalBuffState[] {
const triggered: IntervalBuffState[] = [];
for (let i = this.INTERVAL_EFFECTS.length - 1; i >= 0; i--) {
const state = this.INTERVAL_EFFECTS[i];
state.remain -= dt;
state.tick -= dt;
while (state.tick <= 0 && state.remain > 0) {
triggered.push({
id: state.id,
attr: state.attr,
sourceUuid: state.sourceUuid,
value: state.value,
BType: state.BType,
interval: state.interval,
remain: state.remain,
tick: state.tick
});
state.tick += state.interval;
}
if (state.remain <= 0) {
this.INTERVAL_EFFECTS.splice(i, 1);
}
}
return triggered;
}
applyStoredEffect(attr: Attrs, value: number, type: BType) {
this.applyAttrChange(attr, value, type);
}
/**
* Timed Buff/Debuff 到期更新
* - 到期时调用 applyAttrChange(reverse=true) 回滚
* - 该函数只处理 BUFFS/DEBUFFS不处理 INTERVAL_EFFECTS
*/
private updateList(list: Record<number, ActiveBuffState[]>, dt: number) {
for (const attrKey in list) {
const buffs = list[attrKey];
if (!buffs || buffs.length === 0) continue;
// 倒序遍历以便移除
for (let i = buffs.length - 1; i >= 0; i--) {
const buff = buffs[i];
buff.time -= dt;
if (buff.time <= 0) {
this.applyAttrChange(buff.attr, buff.value, buff.BType, true);
buffs.splice(i, 1);
if (this.debugMode) {
mLogger.log(this.debugMode, 'HeroAttrs', `Buff过期: 属性:${buff.attr}, 恢复值:${buff.value}`);
}
}
}
// 如果该属性的 buff 列表空了,可以清理 key (可选)
if (buffs.length === 0) {
delete list[attrKey];
}
}
}
private updateStatusFlags() {
// 检查特定状态的 Debuff 列表是否为空,来更新 boolean 标志
this.checkStatus(Attrs.IN_FROST, 'in_frost');
this.checkStatus(Attrs.IN_STUN, 'in_stun');
}
private checkStatus(attr: Attrs, flagName: string) {
const key = attr as unknown as number;
const hasBuff = this.DEBUFFS[key] && this.DEBUFFS[key].length > 0;
// 只有当状态改变时才赋值,避免每帧赋值
if (this[flagName] !== hasBuff) {
this[flagName] = hasBuff;
// 状态变化日志
if (this.debugMode) {
mLogger.log(this.debugMode, 'HeroAttrs', `状态变更: ${this.hero_name}, ${flagName} = ${hasBuff}`);
}
}
}
// ==================== 技能距离缓存管理 ====================
@@ -525,10 +288,6 @@ export class HeroAttrsComp extends ecs.Comp {
this.in_frost = false;
this.in_stun = false;
this.BUFFS = {};
this.DEBUFFS = {};
this.INTERVAL_EFFECTS = [];
this.buffInstanceId = 0;
// 重置技能距离缓存
this.maxSkillDistance = 0;
this.minSkillDistance = 0;
@@ -568,49 +327,7 @@ export class HeroBuffSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
}
update(e: ecs.Entity): void {
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;
attrs.add_hp(effect.value, true);
const delta = attrs.hp - oldHp;
if (view && delta !== 0) {
view.playIntervalEffect(effect.attr, delta, effect.sourceUuid);
}
return;
}
if (effect.attr === Attrs.shield) {
const oldShield = attrs.shield;
attrs.add_shield(effect.value, true);
const delta = attrs.shield - oldShield;
if (view && delta !== 0) {
view.playIntervalEffect(effect.attr, delta, effect.sourceUuid);
}
return;
}
attrs.applyStoredEffect(effect.attr, effect.value, effect.BType);
if (view) {
view.playIntervalEffect(effect.attr, effect.value, effect.sourceUuid);
}
void e;
}
}