import { Timer } from "db://oops-framework/core/common/timer/Timer"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { smc } from "../common/SingletonModuleComp"; import { Attrs } from "../common/config/HeroAttrs"; import { HeroUpSet } from "../common/config/heroSet"; import { HeroSkillsComp } from "./HeroSkills"; import { HeroAttrsComp } from "./HeroAttrsComp"; /** * ==================== 英雄属性更新系统 ==================== * * 按照 ECS 设计理念: * - Component(HeroAttrsComp):存储数据 * - System(HeroAttrSystem):处理业务逻辑 * * 系统职责: * 1. 每帧更新临时 Buff(时间递减,过期移除) * 2. 每帧更新 HP/MP 自然回复 * 3. 限制属性值在合理范围内 * /** * 使用方式: * 在 RootSystem 中注册此系统,它会自动每帧更新所有拥有 HeroAttrsComp 的实体 */ @ecs.register('HeroAttrSystem') export class HeroAttrSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate, ecs.IEntityEnterSystem, ecs.ISystemFirstUpdate { // ==================== 调试统计(可选)==================== private entityCount: number = 0; // 本帧处理的实体数 private frameCount: number = 0; // 总帧数 private debugMode: boolean = false; // 是否启用调试模式 private timer:Timer=new Timer(1) /** * 过滤器:只处理拥有 HeroAttrsComp 的实体 */ filter(): ecs.IMatcher { return ecs.allOf(HeroAttrsComp); } /** * 实体首次进入系统时调用(每个实体只调用一次) */ entityEnter(e: ecs.Entity): void { if(!smc.mission.play || smc.mission.pause) return; const model = e.get(HeroAttrsComp); if (!model) return; console.log(`[HeroAttrSystem] 英雄进入系统: ${model.hero_name} (uuid: ${model.hero_uuid})`); } /** * 系统首次更新前调用(整个系统只调用一次) */ firstUpdate(): void { console.log("[HeroAttrSystem] 系统首次更新"); } /** * 每帧更新(为每个英雄调用一次) * * ⭐ 关键理解: * - 如果有 3 个英雄,这个方法每帧会被调用 3 次 * - 每次调用处理不同的实体 e * - 这是正确的设计,不是 bug */ update(e: ecs.Entity): void { if(!smc.mission.play || smc.mission.pause) return; const model = e.get(HeroAttrsComp); if (!model || model.is_dead) return; // 统计:记录本帧处理的实体数 this.entityCount++; // 调试日志(可选,调试时启用) if (this.debugMode) { console.log(` [${this.entityCount}] 更新英雄: ${model.hero_name}, HP: ${model.hp.toFixed(2)}`); } // 1. 更新临时 Buff/Debuff(时间递减,过期自动移除) model.updateTemporaryBuffsDebuffs(this.dt); // 记录MP变化前的值 const oldMp = model.mp; if(this.timer.update(this.dt)){ // 2. HP/MP 自然回复(业务规则) model.mp += HeroUpSet.MP model.hp += HeroUpSet.HP } // 3. 限制属性值在合理范围内 if (model.mp > model.Attrs[Attrs.MP_MAX]) { model.mp = model.Attrs[Attrs.MP_MAX]; } if (model.hp > model.Attrs[Attrs.HP_MAX]) { model.hp = model.Attrs[Attrs.HP_MAX]; } // 4. 如果MP发生变化,更新最大技能距离缓存(最小距离不受MP影响) if (model.mp !== oldMp) { const skillsComp = e.get(HeroSkillsComp); if (skillsComp) { model.updateSkillDistanceCache(skillsComp); } } // 每 60 帧输出一次统计 this.frameCount++; if (this.frameCount % 60 === 0 && this.entityCount === 1) { console.log(`[HeroAttrSystem] 第 ${this.frameCount} 帧,处理 ${this.entityCount} 个英雄`); } // 注意:显示更新由 HeroViewComp 负责,这里只处理数据 } /** * 启用调试模式(调试时使用) */ enableDebug() { this.debugMode = true; } /** * 禁用调试模式(正式运行) */ disableDebug() { this.debugMode = false; } }