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