import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { Vec3, v3 } from "cc"; import { HeroAttrsComp } from "./HeroAttrsComp"; import { HeroViewComp } from "./HeroViewComp"; import { SkillSet, SType } from "../common/config/SkillSet"; import { HeroSkillsComp } from "./HeroSkills"; import { Skill } from "../skill/Skill"; import { CSRequestComp } from "../skill/STagComps"; import { smc } from "../common/SingletonModuleComp"; /** * ==================== 技能施法系统 手动施法==================== * * 职责: * 1. 监听 CSRequestComp 标记组件 * 2. 检查施法条件(CD、MP、状态) * 3. 扣除资源(MP) * 4. 创建技能实体 * 5. 触发施法动画 * 6. 移除请求标记 * * 设计理念: * - 使用标记组件驱动,符合 ECS 理念 * - 施法检查与执行分离 * - 自动处理资源消耗和CD重置 */ // @ecs.register('SCastSystem') export class SCastSystem extends ecs.ComblockSystem implements ecs.IEntityEnterSystem { /** * 过滤器:拥有技能数据 + 施法请求的实体 */ filter(): ecs.IMatcher { return ecs.allOf(HeroSkillsComp, HeroAttrsComp, CSRequestComp); } /** * 实体进入时触发(即请求施法时) */ entityEnter(e: ecs.Entity): void { if(!smc.mission.play || smc.mission.pause) return; const skillsComp = e.get(HeroSkillsComp); const heroAttrs = e.get(HeroAttrsComp); const request = e.get(CSRequestComp); const heroView = e.get(HeroViewComp); // 1. 验证数据完整性 if (!skillsComp || !heroAttrs || !request || !heroView) { console.warn("[SCastSystem] 数据不完整,取消施法"); e.remove(CSRequestComp); return; } // 2. 获取技能数据 const skill = skillsComp.getSkill(request.s_uuid); if (!skill) { console.warn(`[SCastSystem] 技能索引无效: ${request.s_uuid }`); e.remove(CSRequestComp); return; } // 3. 检查施法条件 if (!this.checkCastConditions(skillsComp, heroAttrs, request.s_uuid)) { e.remove(CSRequestComp); return; } // 4. 执行施法 this.executeCast(e, skill, request.targets, heroView); // 5. 扣除资源和重置CD heroAttrs.mp -= skill.cost; skillsComp.resetCD(request.s_uuid); // 6. 移除请求标记 e.remove(CSRequestComp); } /** * 检查施法条件 */ private checkCastConditions(skillsComp: HeroSkillsComp, heroAttrs: HeroAttrsComp, skillIndex: number): boolean { // 检查角色状态 if (heroAttrs.is_dead) { return false; } // 检查控制状态(眩晕、冰冻) if (heroAttrs.isStun() || heroAttrs.isFrost()) { return false; } // 检查CD和MP if (!skillsComp.canCast(skillIndex, heroAttrs.mp)) { return false; } return true; } /** * 执行施法 */ private executeCast(casterEntity: ecs.Entity, skill: any, targets: Vec3[], heroView: HeroViewComp) { const config = SkillSet[skill.uuid]; if (!config) { console.error("[SCastSystem] 技能配置不存在:", skill.uuid); return; } // 1. 播放施法动画 heroView.playSkillEffect(skill.uuid); // 2. 延迟创建技能实体(等待动画) const delay = config.with ?? 0.3; // 施法前摇时间 heroView.scheduleOnce(() => { this.createSkill(skill.uuid, heroView, targets); }, delay); const heroAttrs = casterEntity.get(HeroAttrsComp); console.log(`[SCastSystem] ${heroAttrs?.hero_name ?? '未知'} 施放技能: ${config.name}`); } /** * 创建技能实体 */ private createSkill(skillId: number, caster: HeroViewComp, targets: Vec3[]) { // 检查节点有效性 if (!caster.node || !caster.node.isValid) { console.warn("[SCastSystem] 施法者节点无效"); return; } // 获取场景节点 const parent = caster.node.parent; if (!parent) { console.warn("[SCastSystem] 场景节点无效"); return; } // ✅ 使用现有的 SkillEnt 创建技能 // const skill = ecs.getEntity(Skill); } }