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 { HeroSkillsComp } from "./HeroSkills"; /** * ==================== 自动施法系统 ==================== * * 职责: * 1. 检测可施放的技能 * 2. 根据策略自动施法(AI) * 3. 选择目标 * 4. 添加施法请求标记 * * 设计理念: * - 负责"何时施法"的决策 * - 通过添加 CastSkillRequestComp 触发施法 * - 可被玩家输入系统或AI系统复用 * - 支持多种AI策略 */ @ecs.register('SkillAutocastSystem') export class SkillAutocastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate { filter(): ecs.IMatcher { return ecs.allOf(HeroSkillsComp, HeroAttrsComp, HeroViewComp); } update(e: ecs.Entity): void { const skills = e.get(HeroSkillsComp); const heroModel = e.get(HeroAttrsComp); const heroView = e.get(HeroViewComp); if (!skills || !heroModel || !heroView) return; // 检查基本条件 if (heroModel.is_dead || heroModel.isStun() || heroModel.isFrost()) return; // 检查是否正在攻击(只有攻击时才释放技能) if (!heroModel.is_atking) return; // 获取所有可施放的技能 const readySkills = skills.getReadySkills(heroModel.mp); if (readySkills.length === 0) return; // 选择第一个可施放的伤害技能 for (const skillIndex of readySkills) { const skill = skills.getSkill(skillIndex); if (!skill) continue; const config = SkillSet[skill.uuid]; if (!config || config.SType !== SType.damage) continue; // ✅ 添加施法请求标记组件 const request = e.add(CastSkillRequestComp) as CastSkillRequestComp; request.skillIndex = skillIndex; request.targetPositions = this.selectTargets(heroView); // 一次只施放一个技能 break; } } /** * 选择目标位置 */ private selectTargets(caster: HeroViewComp): Vec3[] { // 简化版:选择最前方的敌人 const targets: Vec3[] = []; // 这里可以调用 SkillConComp 的目标选择逻辑 // 暂时返回默认位置 const heroModel = caster.ent.get(HeroAttrsComp); const fac = heroModel?.fac ?? 0; const defaultX = fac === 0 ? 400 : -400; targets.push(v3(defaultX, 0, 0)); return targets; } /** * 选择伤害技能目标 */ private selectDamageTargets(caster: HeroViewComp, config: any, maxTargets: number): Vec3[] { const targets: Vec3[] = []; const heroModel = caster.ent.get(HeroAttrsComp); if (!heroModel) return targets; // 寻找最近的敌人 const enemyPositions = this.findNearbyEnemies(caster, heroModel.fac, config.range || 300); // 选择最多maxTargets个目标 for (let i = 0; i < Math.min(maxTargets, enemyPositions.length); i++) { targets.push(enemyPositions[i]); } // 如果没有找到敌人,使用默认位置 if (targets.length === 0) { targets.push(...this.selectDefaultTargets(caster, heroModel.fac)); } return targets; } /** * 选择治疗技能目标 */ private selectHealTargets(caster: HeroViewComp, config: any, maxTargets: number): Vec3[] { const targets: Vec3[] = []; const heroModel = caster.ent.get(HeroAttrsComp); if (!heroModel) return targets; // 寻找血量最低的友军 const allyPositions = this.findLowHealthAllies(caster, heroModel.fac, config.range || 200); for (let i = 0; i < Math.min(maxTargets, allyPositions.length); i++) { targets.push(allyPositions[i]); } // 如果没有找到友军,治疗自己 if (targets.length === 0 && caster.node) { targets.push(caster.node.position.clone()); } return targets; } /** * 选择BUFF技能目标 */ private selectBuffTargets(caster: HeroViewComp, config: any, maxTargets: number): Vec3[] { // BUFF技能通常施放在自己或友军身上 return this.selectHealTargets(caster, config, maxTargets); } /** * 选择DEBUFF技能目标 */ private selectDebuffTargets(caster: HeroViewComp, config: any, maxTargets: number): Vec3[] { // DEBUFF技能通常施放在敌人身上 return this.selectDamageTargets(caster, config, maxTargets); } /** * 选择默认目标 */ private selectDefaultTargets(caster: HeroViewComp, faction: number): Vec3[] { const targets: Vec3[] = []; const defaultX = faction === 0 ? 400 : -400; targets.push(v3(defaultX, 0, 0)); return targets; } /** * 查找附近的敌人 */ private findNearbyEnemies(caster: HeroViewComp, faction: number, range: number): Vec3[] { // 简化实现,实际应该查询ECS中的敌方实体 const enemies: Vec3[] = []; // 模拟敌人位置 const enemyX = faction === 0 ? 300 : -300; enemies.push(v3(enemyX, 0, 0)); enemies.push(v3(enemyX + 50, 20, 0)); return enemies; } /** * 查找血量低的友军 */ private findLowHealthAllies(caster: HeroViewComp, faction: number, range: number): Vec3[] { // 简化实现,实际应该查询ECS中的友方实体并按血量排序 const allies: Vec3[] = []; // 如果自己血量低,优先治疗自己 return allies; } }