From 6170f47ca6b74df5c621bb329c91938b0cb78df6 Mon Sep 17 00:00:00 2001 From: panw Date: Fri, 13 Mar 2026 09:52:16 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E6=8A=80?= =?UTF-8?q?=E8=83=BD=E7=B3=BB=E7=BB=9F=E5=B9=B6=E7=A7=BB=E9=99=A4=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E6=96=BD=E6=B3=95=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除 SACastSystem 及其 meta 文件,移除自动施法逻辑 - 重构 HeroAttrsComp 中的 Buff 处理逻辑,修复百分比计算问题 - 将治疗和护盾 Buff 的 BType 从 VALUE 改为 RATIO - 添加 resolveBuffValue 方法正确计算基于最大生命值的百分比值 - 修复 applyAttrChange 中 RATIO 类型的叠加逻辑 - 添加 HeroBuffSystem 系统,将 Buff 更新逻辑从 HeroAttrsComp 中分离 - 优化 SkillView 的销毁逻辑,避免直接调用 destroy 方法 - 禁用碰撞体并设置节点为 inactive 状态 --- assets/script/game/common/config/SkillSet.ts | 4 +- assets/script/game/hero/HeroAttrsComp.ts | 92 ++- assets/script/game/hero/SACastSystem.ts | 621 ------------------- assets/script/game/hero/SACastSystem.ts.meta | 9 - assets/script/game/skill/SkillView.ts | 7 +- 5 files changed, 47 insertions(+), 686 deletions(-) delete mode 100644 assets/script/game/hero/SACastSystem.ts delete mode 100644 assets/script/game/hero/SACastSystem.ts.meta diff --git a/assets/script/game/common/config/SkillSet.ts b/assets/script/game/common/config/SkillSet.ts index 23109a28..23f4d831 100644 --- a/assets/script/game/common/config/SkillSet.ts +++ b/assets/script/game/common/config/SkillSet.ts @@ -314,9 +314,9 @@ export const BuffsList: Record = { // ========== 治疗与护盾 (转换自原 SType) ========== 10300 - 10399 // 治疗 (基于攻击力百分比) - 10301: { uuid: 10301, name: "治疗", icon: "1292", buff: Attrs.hp, BType: BType.VALUE, value: 30, time: 0, chance: 1, info: "回复30%生命值" }, + 10301: { uuid: 10301, name: "治疗", icon: "1292", buff: Attrs.hp, BType: BType.RATIO, value: 30, time: 0, chance: 1, info: "回复30%最大生命值" }, // 护盾 (基于攻击力百分比) - 10302: { uuid: 10302, name: "护盾", icon: "1255", buff: Attrs.shield, BType: BType.VALUE, value: 30, time: 0, chance: 1, info: "获得30%护盾" }, + 10302: { uuid: 10302, name: "护盾", icon: "1255", buff: Attrs.shield, BType: BType.RATIO, value: 30, time: 0, chance: 1, info: "获得30%最大生命值护盾" }, // ========== 减益类 Buff (属性降低) ========== 10200 - 10299 // 减速 (移动速度降低) diff --git a/assets/script/game/hero/HeroAttrsComp.ts b/assets/script/game/hero/HeroAttrsComp.ts index b74a79cd..bfcd3f0e 100644 --- a/assets/script/game/hero/HeroAttrsComp.ts +++ b/assets/script/game/hero/HeroAttrsComp.ts @@ -5,6 +5,7 @@ import { Attrs, BType } from "../common/config/HeroAttrs"; import { BuffConf, SkillDisVal, SkillRange } from "../common/config/SkillSet"; import { HeroInfo, HType } from "../common/config/heroSet"; import { mLogger } from "../common/Logger"; +import { smc } from "../common/SingletonModuleComp"; import { _decorator } from "cc"; const { property } = _decorator; @@ -152,39 +153,45 @@ export class HeroAttrsComp extends ecs.Comp { * @param buffConf buff 配置 */ addBuff(buffConf: BuffConf) { - // 1. 如果是永久性增益(time=0),直接修改基础属性 + const applyType = buffConf.BType === BType.BOOLEAN ? BType.BOOLEAN : BType.VALUE; + const resolvedValue = applyType === BType.BOOLEAN + ? buffConf.value + : this.resolveBuffValue(buffConf.buff, buffConf.value, buffConf.BType); if (buffConf.time <= 0) { - this.applyAttrChange(buffConf.buff, buffConf.value, buffConf.BType); + this.applyAttrChange(buffConf.buff, resolvedValue, applyType); return; } - // 2. 临时性 Buff/Debuff 处理 - // 区分存储列表 const targetList = buffConf.isDebuff ? this.DEBUFFS : this.BUFFS; - - // 确保列表初始化 - // 注意:这里我们用 buffConf.buff (属性名) 作为 key,而不是 buffConf.uuid - // 这样同一种属性的 buff 可以叠加或覆盖 const attrKey = buffConf.buff as unknown as number; // 强制转换 key 类型以适配 Record if (!targetList[attrKey]) { targetList[attrKey] = []; } const currentBuffs = targetList[attrKey]; - - // 查找是否已有同源的 buff (这里假设 uuid 相同为同源,或者简单点直接追加) - // 策略:直接追加,update 时统一计算 - // 记录添加时的数值,方便后续移除(虽然 update 是重新计算总值的) currentBuffs.push({ - value: buffConf.value, - BType: buffConf.BType, + value: resolvedValue, + BType: applyType, time: buffConf.time }); - // 立即应用一次属性变更(增量) - this.applyAttrChange(buffConf.buff, buffConf.value, buffConf.BType); + this.applyAttrChange(buffConf.buff, resolvedValue, applyType); - mLogger.log(this.debugMode, 'HeroAttrs', `添加Buff: ${buffConf.name}, 属性:${buffConf.buff}, 值:${buffConf.value}, 时间:${buffConf.time}`); + mLogger.log(this.debugMode, 'HeroAttrs', `添加Buff: ${buffConf.name}, 属性:${buffConf.buff}, 值:${resolvedValue}, 时间:${buffConf.time}`); + } + + 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; } /** @@ -212,43 +219,10 @@ export class HeroAttrsComp extends ecs.Comp { return; } - // 处理百分比 - // 注意:百分比通常是基于基础值计算,这里简化为直接修改当前值 - // 如果需要严格的基础值+百分比,需要维护 baseAttrs 和 bonusAttrs - // 当前架构直接修改属性,百分比暂时按 (当前值 * 百分比) 或 (基础值 * 百分比) 处理 - // 鉴于属性系统中 hp/hp_max 等已经是数值,这里百分比暂定为:属性 = 属性 + (属性 * 百分比) - // 但对于 addBuff 这种临时增益,百分比通常是基于"基础值"的。 - // 由于没有显式的 base_ap,这里简化处理: - // VALUE: 直接加减 - // RATIO: 简单处理为 value 就是最终加成值(需要配置表里填好的数值),或者基于当前值 - // 通常配置表填 10 表示 10%,即 0.1。 - // 但这里的 value 已经是 number。假设配置 10 就是 10 点,或者 10%。 - - // 修正:根据 BType 处理 if (type === BType.RATIO) { - // 假设 value 是百分比整数,如 10 代表 10% - // 必须基于某个基数。这里暂时基于当前值(不严谨,但在没有 base 属性的情况下只能这样,或者基于 100?) - // 更合理的做法:如果是 RATIO,value 应该在配置时就转为实际数值,或者这里基于当前属性计算 - // 考虑到 Attrs 定义里有很多非数值属性(如状态),需要特殊处理 - - // 针对状态类属性(IN_FROST 等),通常是 BOOLEAN,不走 RATIO - // 针对数值类(ap, hp),RATIO 应该是 value% * current - - // 简化:目前只支持 VALUE 型直接加减。RATIO 型需要更复杂的属性系统支持(Base + Add + Mul)。 - // 这里的实现先按 VALUE 处理,如果以后需要 RATIO,建议在 addBuff 前计算好 value - // 或者:约定 RATIO 时,value 是基于当前值的百分比增量 - const ratio = finalValue / 100; - // 注意:这里直接修改 this[attr] 会导致多次叠加问题。 - // 临时 Buff 的正确做法是:Update 中每一帧重置属性 -> 应用所有 Buff。 - // 但当前架构似乎是“增量修改”式的。 - // “增量修改”式在移除时很麻烦(尤其是百分比)。 - // 妥协方案:只支持 VALUE 加减。配置表里的 RATIO 需要在逻辑层转为 VALUE。 - // 但为了兼容 BType.RATIO,这里暂时按 (当前值 * ratio) 计算增量 - // 这会导致 recursive 问题,所以严谨的项目里属性必须分层。 - // 鉴于“少可用原则”,这里仅处理 VALUE 和 BOOLEAN + finalValue = this.resolveBuffValue(attr, finalValue, BType.RATIO); if (typeof this[attr] === 'number') { - // 警告:直接改写数值可能不准确 - this[attr] = (this[attr] as number) * (1 + ratio); + this[attr] = (this[attr] as number) + finalValue; } } else if (type === BType.BOOLEAN) { // 布尔型/状态型:value > 0 为 true/计数+1,移除时 -1 @@ -475,5 +449,19 @@ export class HeroAttrsComp extends ecs.Comp { } +@ecs.register('HeroBuffSystem') +export class HeroBuffSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate { + filter(): ecs.IMatcher { + return ecs.allOf(HeroAttrsComp); + } + + update(e: ecs.Entity): void { + if (!smc.mission.play || smc.mission.pause) return; + const attrs = e.get(HeroAttrsComp); + if (!attrs || attrs.is_dead) return; + attrs.updateBuffsDebuffs(this.dt); + } +} + diff --git a/assets/script/game/hero/SACastSystem.ts b/assets/script/game/hero/SACastSystem.ts deleted file mode 100644 index 75e6cd6b..00000000 --- a/assets/script/game/hero/SACastSystem.ts +++ /dev/null @@ -1,621 +0,0 @@ -// 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 { HSSet, SkillSet, SType, TGroup, SkillConfig } from "../common/config/SkillSet"; -// import { HeroSkillsComp, SkillSlot } from "./HeroSkills"; -// import { Skill } from "../skill/Skill"; -// import { smc } from "../common/SingletonModuleComp"; -// import { TalComp } from "./TalComp"; -// import { TalEffet, TriType } from "../common/config/TalSet"; -// import { BoxSet, FacSet } from "../common/config/GameSet"; -// import { GameConst } from "../common/config/GameConst"; -// import { Attrs } from "../common/config/HeroAttrs"; -// import { mLogger } from "../common/Logger"; - -// /** -// * ==================== 自动施法系统 ==================== -// * -// * 职责: -// * 1. 检测可施放的技能 -// * 2. 根据策略自动施法(AI) -// * 3. 选择目标 -// * 4. 添加施法请求标记 -// * -// * 设计理念: -// * - 负责"何时施法"的决策 -// * - 通过添加 CSRequestComp 触发施法 -// * - 可被玩家输入系统或AI系统复用 -// * - 支持多种AI策略 -// */ -// @ecs.register('SACastSystem') -// export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate { -// debugMode: boolean = false; // 是否启用调试模式 - -// filter(): ecs.IMatcher { -// return ecs.allOf(HeroSkillsComp, HeroAttrsComp, HeroViewComp); -// } - -// update(e: ecs.Entity): void { -// if(!smc.mission.play ) return; -// if(smc.mission.pause) return -// const skills = e.get(HeroSkillsComp); -// if (!skills) return; - -// // AI 降频:每0.2秒执行一次 -// skills.ai_timer += this.dt; -// if (skills.ai_timer < GameConst.Battle.AI_CHECK_INTERVAL) return; -// skills.ai_timer = 0; - -// const heroAttrs = e.get(HeroAttrsComp); -// const heroView = e.get(HeroViewComp); -// if (!heroAttrs || !heroView) return; - -// // 检查基本条件 -// if (heroAttrs.is_dead || heroAttrs.is_reviving || heroAttrs.isStun() || heroAttrs.isFrost()) return; - -// // 移除 is_atking 检查,实现只要距离和CD满足即施法 -// // if (!heroAttrs.is_atking) return; - -// const readySkills = skills.getReadySkills(); -// if (readySkills.length === 0) return; - -// // 选择第一个可施放的技能(支持伤害/治疗/护盾) -// for (const s_uuid of readySkills) { -// const skill = skills.getSkill(s_uuid); -// if (!skill) continue; -// if (skill.hset === HSSet.max && !skills.max_auto) continue; - -// const config = SkillSet[skill.s_uuid]; -// if (!config) continue; - -// // 根据技能类型检查目标 -// if (config.SType === SType.damage) { -// if (!this.hasEnemyInSkillRange(heroView, heroAttrs, skill.dis)) continue; -// } else if (config.SType === SType.heal || config.SType === SType.shield) { -// if (!this.hasTeamInSkillRange(heroView, heroAttrs, skill.dis)) continue; -// } else if (config.SType === SType.buff) { -// if (!this.hasBuffTarget(heroView, heroAttrs, skill.dis, config.TGroup)) continue; -// } - -// // ✅ 开始执行施法 -// this.startCast(e, skill, skill.hset); - -// // 一次只施放一个技能 -// break; -// } -// } -// private startCast(e: ecs.Entity,skill:SkillSlot,hset:HSSet): boolean { -// if (!skill||!e) return false -// const skills = e.get(HeroSkillsComp); -// const heroAttrs = e.get(HeroAttrsComp); -// const heroView = e.get(HeroViewComp); -// // 3. 检查施法条件 -// if (!this.checkCastConditions(skills, heroAttrs, skill.s_uuid)) return false - -// // 4. 执行施法 -// const castSucess = this.executeCast(e, skill.s_uuid, heroView,hset); -// // 5. 扣除资源和重置CD -// if (castSucess) { -// // 🔥 怪物不消耗蓝 -// if (heroAttrs.fac !== FacSet.MON) { -// // 手动更新技能距离缓存 -// heroAttrs.updateSkillDistanceCache(skills); -// } -// skills.resetCD(skill.s_uuid); -// } -// return castSucess; -// } -// public manualCast(e: ecs.Entity, s_uuid: number): boolean { -// if (!e) return false -// const skills = e.get(HeroSkillsComp) -// const heroAttrs = e.get(HeroAttrsComp) -// const heroView = e.get(HeroViewComp) -// if (!skills || !heroAttrs || !heroView) return false -// const slot = skills.getSkill(s_uuid) -// if (!slot) return false -// return this.startCast(e, slot, slot.hset) -// } -// public manualCastMax(e: ecs.Entity): boolean { -// const skills = e.get(HeroSkillsComp) -// if (!skills) return false -// for (const key in skills.skills) { -// const s_uuid = Number(key) -// const slot = skills.getSkill(s_uuid) -// if (slot && slot.hset === HSSet.max) { -// return this.manualCast(e, s_uuid) -// } -// } -// return false -// } -// /** -// * 检查施法条件 -// */ -// private checkCastConditions(skills: HeroSkillsComp, heroAttrs: HeroAttrsComp, s_uuid: number): boolean { -// // 检查角色状态 -// if (heroAttrs.is_dead) { -// return false; -// } - -// // 检查控制状态(眩晕、冰冻) -// if (heroAttrs.isStun() || heroAttrs.isFrost()) { -// return false; -// } - -// // 检查CD -// if (!skills.canCast(s_uuid)) { -// return false; -// } - -// return true; -// } - -// /** -// * 执行施法 -// */ -// private executeCast(casterEntity: ecs.Entity, s_uuid: number, heroView: HeroViewComp,hset:HSSet): boolean { -// const heroAttrs=casterEntity.get(HeroAttrsComp) -// const config = SkillSet[s_uuid]; -// if (!config) { -// mLogger.error(this.debugMode, 'SACastSystem', "[SACastSystem] 技能配置不存在:", s_uuid); -// return false; -// } - -// // 1. 播放施法动画 -// heroView.playSkillEffect(s_uuid); -// /**********************天赋处理*************************************************************************/ -// // 2. 更新攻击类型的天赋触发值,技能和必杀级 -// if(casterEntity.has(TalComp)){ -// const talComp = casterEntity.get(TalComp); -// if (hset === HSSet.atk) talComp.updateCur(TriType.ATK); -// if (hset === HSSet.skill) talComp.updateCur(TriType.SKILL); -// } -// /**********************天赋处理*************************************************************************/ -// // 根据技能类型执行不同逻辑 -// if (config.SType === SType.heal) { -// return this.executeHealSkill(casterEntity, s_uuid, heroView, hset); -// } else if (config.SType === SType.shield) { -// return this.executeShieldSkill(casterEntity, s_uuid, heroView, hset); -// } else if (config.SType === SType.buff) { -// return this.executeBuffSkill(casterEntity, s_uuid, heroView, hset); -// } - -// // 获取目标位置(伤害技能) -// let targets = this.sTargets(heroView, s_uuid); -// if (targets.length === 0) { -// mLogger.warn(this.debugMode, 'SACastSystem', "[SACastSystem] 没有找到有效目标"); -// return false; -// } -// // 2.1 普通攻击逻辑 -// if (hset === HSSet.atk){ -// let delay = GameConst.Battle.SKILL_CAST_DELAY -// let ext_dmg = heroAttrs.useCountValTal(TalEffet.ATK_DMG); -// heroView.scheduleOnce(() => { -// this.createSkill(s_uuid, heroView,targets,ext_dmg); -// }, delay); -// //风怒wfuny 只针对 普通攻击起效 -// if (heroAttrs.useCountTal(TalEffet.WFUNY)){ -// let ext2_dmg = heroAttrs.useCountValTal(TalEffet.ATK_DMG); -// let delay = GameConst.Battle.SKILL_CAST_DELAY -// heroView.playSkillEffect(s_uuid); -// //需要再添加 风怒动画 -// heroView.scheduleOnce(() => { -// this.createSkill(s_uuid, heroView,targets,ext2_dmg); -// },delay); -// } -// } -// // 2.2 技能攻击逻辑 -// if(hset === HSSet.skill){ -// let delay = GameConst.Battle.SKILL_CAST_DELAY -// let ext_dmg = heroAttrs.useCountValTal(TalEffet.SKILL_DMG); -// heroView.scheduleOnce(() => { -// this.createSkill(s_uuid, heroView,targets,ext_dmg); -// }, delay); -// // 双技能 只针对 技能起效 -// if(heroAttrs.useCountTal(TalEffet.D_SKILL)){ -// let ext2_dmg = heroAttrs.useCountValTal(TalEffet.SKILL_DMG); -// let delay = GameConst.Battle.SKILL_CAST_DELAY -// heroView.playSkillEffect(s_uuid); -// //需要再添加 双技能动画 -// heroView.scheduleOnce(() => { -// this.createSkill(s_uuid, heroView,targets,ext2_dmg); -// },delay); -// } -// } -// // 2.3 必杀技能逻辑 -// if(hset === HSSet.max){ -// let delay = GameConst.Battle.SKILL_CAST_DELAY -// heroView.playSkillEffect(s_uuid); -// //需要再添加 最大伤害动画 -// heroView.scheduleOnce(() => { -// this.createSkill(s_uuid, heroView,targets); -// },delay); -// } - - - -// return true; -// } - - -// /** -// * 创建技能实体 -// */ -// private createSkill(s_uuid: number, caster: HeroViewComp,targets:Vec3[]=[],ext_dmg:number=0) { -// // 检查节点有效性 -// if (!caster.node || !caster.node.isValid) { -// mLogger.warn(this.debugMode, 'SACastSystem', "[SACastSystem] 施法者节点无效"); -// return; -// } - -// // 获取场景节点 -// const parent = caster.node.parent; -// if (!parent) { -// mLogger.warn(this.debugMode, 'SACastSystem', "[SACastSystem] 场景节点无效"); -// return; -// } - - - -// // 创建技能实体 -// const skill = ecs.getEntity(Skill); - -// // 获取施法者位置作为起始位置 -// const startPos = caster.node.position.clone(); - -// const targetPos = targets[0]; // 使用第一个目标位置 -// // mLogger.log(this.debugMode, 'SACastSystem', `[SACastSystem]: ${s_uuid}, 起始位置: ${startPos}, 目标位置: ${targetPos}`); -// // 加载技能实体(包括预制体、组件初始化等) -// skill.load(startPos, parent, s_uuid, targetPos, caster,ext_dmg); - -// } -// /** -// * 选择目标位置 -// */ -// private sTargets(caster: HeroViewComp, s_uuid: number): Vec3[] { -// const heroAttrs = caster.ent.get(HeroAttrsComp); -// if (!heroAttrs) return []; -// const config = SkillSet[s_uuid]; -// if (!config) return this.sDefaultTargets(caster, heroAttrs.fac); -// const maxTargets = Math.max(GameConst.Skill.MIN_TARGET_COUNT, config.t_num ?? 1); -// const targets = this.sDamageTargets(caster, config, maxTargets); -// if (targets.length === 0) { -// targets.push(...this.sDefaultTargets(caster, heroAttrs.fac)); -// } -// return targets; -// } - -// /** -// * 选择伤害技能目标 -// */ -// private sDamageTargets(caster: HeroViewComp, config: SkillConfig, maxTargets: number): Vec3[] { -// const targets: Vec3[] = []; -// const heroAttrs = caster.ent.get(HeroAttrsComp); -// if (!heroAttrs) return targets; - -// const range = Number(config.dis ?? GameConst.Battle.DEFAULT_SEARCH_RANGE); -// const enemyPositions = this.findNearbyEnemies(caster, heroAttrs.fac, range); - -// // 选择最多maxTargets个目标 -// for (let i = 0; i < Math.min(maxTargets, enemyPositions.length); i++) { -// targets.push(enemyPositions[i]); -// } - -// // 如果没有找到敌人,使用默认位置 -// if (targets.length === 0) { -// targets.push(...this.sDefaultTargets(caster, heroAttrs.fac)); -// } - -// return targets; -// } - - - - -// /** -// * 选择默认目标 -// */ -// private sDefaultTargets(caster: HeroViewComp, fac: number): Vec3[] { -// const targets: Vec3[] = []; -// const defaultX = fac === 0 ? GameConst.Battle.DEFAULT_TARGET_X_RIGHT : GameConst.Battle.DEFAULT_TARGET_X_LEFT; -// targets.push(v3(defaultX, BoxSet.GAME_LINE, GameConst.Battle.DEFAULT_TARGET_Z)); -// return targets; -// } - -// /** -// * 查找附近的敌人 -// */ -// private findNearbyEnemies(caster: HeroViewComp, fac: number, range: number): Vec3[] { -// const enemies: Vec3[] = []; -// if (!caster || !caster.node) return enemies; -// const currentPos = caster.node.position; -// const results: { pos: Vec3; dist: number; laneBias: number }[] = []; -// ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => { -// const model = e.get(HeroAttrsComp); -// const view = e.get(HeroViewComp); -// if (!model || !view || !view.node) return false; -// if (model.is_dead) return false; -// if (model.fac === fac) return false; -// const pos = view.node.position.clone(); -// pos.y += GameConst.Battle.SEARCH_Y_OFFSET; -// const dist = Math.abs(currentPos.x - pos.x); -// if (dist <= range) { -// const laneBias = Math.abs(currentPos.y - pos.y); -// results.push({ pos: pos, dist, laneBias }); -// } -// return false; -// }); -// results.sort((a, b) => { -// if (a.laneBias !== b.laneBias) return a.laneBias - b.laneBias; -// return a.dist - b.dist; -// }); -// for (const r of results) enemies.push(r.pos); -// return enemies; -// } - - -// /** -// * 检查技能攻击范围内是否有敌人 -// */ -// private hasEnemyInSkillRange(heroView: HeroViewComp, heroAttrs: HeroAttrsComp, skillDistance: number): boolean { -// if (!heroView || !heroView.node) return false; - -// const currentPos = heroView.node.position; -// const team = heroAttrs.fac; - -// let found = false; -// ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => { -// const model = e.get(HeroAttrsComp); -// const view = e.get(HeroViewComp); -// if (!view || !view.node) return false; -// const distance = Math.abs(currentPos.x - view.node.position.x); -// if (model.fac !== team && !model.is_dead) { -// if (distance <= skillDistance) { -// found = true; -// return true; -// } -// } -// }); -// return found; -// } - -// /** -// * 检查技能范围内是否有友军 -// */ -// private hasTeamInSkillRange(heroView: HeroViewComp, heroAttrs: HeroAttrsComp, skillDistance: number): boolean { -// if (!heroView || !heroView.node) return false; - -// const currentPos = heroView.node.position; -// const team = heroAttrs.fac; - -// let found = false; -// ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => { -// const model = e.get(HeroAttrsComp); -// const view = e.get(HeroViewComp); -// if (!view || !view.node) return false; -// const distance = Math.abs(currentPos.x - view.node.position.x); -// if (model.fac === team && !model.is_dead) { -// if (distance <= skillDistance) { -// found = true; -// return true; -// } -// } -// }); -// return found; -// } - -// /** -// * 检查Buff技能是否有目标 -// */ -// private hasBuffTarget(heroView: HeroViewComp, heroAttrs: HeroAttrsComp, skillDistance: number, tGroup: TGroup): boolean { -// if (tGroup === TGroup.Self) return true; // 自身Buff总是可以释放 - -// // 如果是团队Buff,检查范围内是否有队友 -// if (tGroup === TGroup.Team || tGroup === TGroup.Ally) { -// return this.hasTeamInSkillRange(heroView, heroAttrs, skillDistance); -// } - -// return false; -// } - -// /** -// * 执行Buff技能 -// */ -// private executeBuffSkill(casterEntity: ecs.Entity, s_uuid: number, heroView: HeroViewComp, hset: HSSet): boolean { -// const hAttrsCom = casterEntity.get(HeroAttrsComp); -// const config = SkillSet[s_uuid]; -// if (!config || !config.buffs || config.buffs.length === 0) return false; - -// const targets = this.sBuffTargets(casterEntity, heroView, hAttrsCom, config); -// if (targets.length === 0) return false; - -// const delay = GameConst.Battle.SKILL_CAST_DELAY; - -// heroView.scheduleOnce(() => { -// for (const targetEntity of targets) { -// const targetAttrs = targetEntity.get(HeroAttrsComp); -// if (!targetAttrs) continue; - -// // 应用所有配置的Buff -// for (const buffConf of config.buffs) { -// // 检查概率 -// if (buffConf.chance >= 1 || Math.random() < buffConf.chance) { -// targetAttrs.addBuff(buffConf); -// mLogger.log(this.debugMode, 'SACastSystem', `[SACastSystem] Buff生效: 施法者=${casterEntity.get(HeroAttrsComp)?.hero_name}, 技能=${config.name}, 目标=${targetAttrs.hero_name}, Buff类型=${buffConf.buff}, 值=${buffConf.value}`); -// } -// } -// } -// }, delay); - -// return true; -// } - -// /** -// * 选择Buff目标 -// */ -// private sBuffTargets(casterEntity: ecs.Entity, casterView: HeroViewComp, heroAttrs: HeroAttrsComp, config: SkillConfig): ecs.Entity[] { -// const targets: ecs.Entity[] = []; -// const tGroup = config.TGroup; - -// // 1. 自身 -// if (tGroup === TGroup.Self) { -// targets.push(casterEntity); -// return targets; -// } - -// // 2. 团队/友军 -// if (tGroup === TGroup.Team || tGroup === TGroup.Ally) { -// const maxTargets = Math.max(GameConst.Skill.MIN_TARGET_COUNT, Number(config.t_num ?? 1)); -// const range = Number(config.dis ?? GameConst.Battle.DEFAULT_SEARCH_RANGE); - -// ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).forEach(e => { -// const model = e.get(HeroAttrsComp); -// const view = e.get(HeroViewComp); -// if (!model || !view || !view.node) return; -// if (model.fac !== heroAttrs.fac) return; // 必须是同阵营 -// if (model.is_dead) return; - -// const distance = Math.abs(casterView.node.position.x - view.node.position.x); -// if (distance <= range) { -// targets.push(e); -// } -// }); - -// return targets.slice(0, maxTargets); -// } - -// return targets; -// } - -// /** -// * 执行治疗技能 -// */ -// private executeHealSkill(casterEntity: ecs.Entity, s_uuid: number, heroView: HeroViewComp, hset: HSSet): boolean { -// const hAttrsCom = casterEntity.get(HeroAttrsComp); -// const config = SkillSet[s_uuid]; -// if (!config) return false; - -// const targets = this.sHealTargets(heroView, hAttrsCom, config); -// if (targets.length === 0) return false; - -// const healAmount = config.ap * hAttrsCom.Attrs[Attrs.HP_MAX]/100; -// const delay = GameConst.Battle.SKILL_CAST_DELAY; - -// heroView.scheduleOnce(() => { -// for (const targetEntity of targets) { -// const targetAttrs = targetEntity.get(HeroAttrsComp); -// const targetView = targetEntity.get(HeroViewComp); -// if (!targetAttrs || !targetView) continue; - -// targetAttrs.add_hp(healAmount, true); -// targetView.health(healAmount); -// mLogger.log(this.debugMode, 'SACastSystem', `[SACastSystem] 治疗生效: 施法者=${casterEntity.get(HeroAttrsComp)?.hero_name}, 技能=${config.name}, 目标=${targetAttrs.hero_name}, 治疗量=${healAmount}`); -// } -// }, delay); - -// return true; -// } - -// /** -// * 执行护盾技能 -// */ -// private executeShieldSkill(casterEntity: ecs.Entity, s_uuid: number, heroView: HeroViewComp, hset: HSSet): boolean { -// const hAttrsCom = casterEntity.get(HeroAttrsComp); -// const config = SkillSet[s_uuid]; -// if (!config) return false; - -// const targets = this.sShieldTargets(heroView, hAttrsCom, config); -// if (targets.length === 0) return false; - -// const shieldAmount = config.ap * hAttrsCom.Attrs[Attrs.HP_MAX]/100; -// const delay = GameConst.Battle.SKILL_CAST_DELAY; - -// heroView.scheduleOnce(() => { -// for (const targetEntity of targets) { -// const targetAttrs = targetEntity.get(HeroAttrsComp); -// const targetView = targetEntity.get(HeroViewComp); -// if (!targetAttrs || !targetView) continue; - -// targetAttrs.add_shield(shieldAmount, true); -// targetView.add_shield(shieldAmount); -// mLogger.log(this.debugMode, 'SACastSystem', `[SACastSystem] 护盾生效: 施法者=${casterEntity.get(HeroAttrsComp)?.hero_name}, 技能=${config.name}, 目标=${targetAttrs.hero_name}, 护盾量=${shieldAmount}`); -// } -// }, delay); - -// return true; -// } - -// /** -// * 选择治疗目标 -// */ -// private sHealTargets(caster: HeroViewComp, heroAttrs: HeroAttrsComp, config: SkillConfig): ecs.Entity[] { -// const targets: ecs.Entity[] = []; -// const maxTargets = Math.max(GameConst.Skill.MIN_TARGET_COUNT, Number(config.t_num ?? 1)); -// const range = Number(config.dis ?? GameConst.Battle.DEFAULT_SEARCH_RANGE); - -// ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).forEach(e => { -// const model = e.get(HeroAttrsComp); -// const view = e.get(HeroViewComp); -// if (!model || !view || !view.node) return; -// if (model.fac !== heroAttrs.fac) return; -// if (model.is_dead) return; - -// const distance = Math.abs(caster.node.position.x - view.node.position.x); -// if (distance <= range) { -// targets.push(e); -// } -// }); - -// targets.sort((a, b) => { -// const attrsA = a.get(HeroAttrsComp); -// const attrsB = b.get(HeroAttrsComp); -// if (!attrsA || !attrsB) return 0; -// return attrsA.hp - attrsB.hp; -// }); - -// return targets.slice(0, maxTargets); -// } - -// /** -// * 选择护盾目标 -// */ -// private sShieldTargets(caster: HeroViewComp, heroAttrs: HeroAttrsComp, config: SkillConfig): ecs.Entity[] { -// const targets: ecs.Entity[] = []; -// const maxTargets = Math.max(GameConst.Skill.MIN_TARGET_COUNT, Number(config.t_num ?? 1)); -// const range = Number(config.dis ?? GameConst.Battle.DEFAULT_SEARCH_RANGE); - -// ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).forEach(e => { -// const model = e.get(HeroAttrsComp); -// const view = e.get(HeroViewComp); -// if (!model || !view || !view.node) return; -// if (model.fac !== heroAttrs.fac) return; -// if (model.is_dead) return; - -// const distance = Math.abs(caster.node.position.x - view.node.position.x); -// if (distance <= range) { -// targets.push(e); -// } -// }); - -// return targets.slice(0, maxTargets); -// } - -// /** -// * 根据位置查找实体 -// */ -// private findEntityAtPosition(pos: Vec3): ecs.Entity | null { -// let foundEntity: ecs.Entity | null = null; -// ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => { -// const view = e.get(HeroViewComp); -// if (!view || !view.node) return false; -// const distance = Vec3.distance(pos, view.node.position); -// if (distance < 50) { -// foundEntity = e; -// return true; -// } -// return false; -// }); -// return foundEntity; -// } - -// } \ No newline at end of file diff --git a/assets/script/game/hero/SACastSystem.ts.meta b/assets/script/game/hero/SACastSystem.ts.meta deleted file mode 100644 index 9fd88241..00000000 --- a/assets/script/game/hero/SACastSystem.ts.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "4.0.24", - "importer": "typescript", - "imported": true, - "uuid": "e76866cc-7379-436f-91ff-e71e790580a9", - "files": [], - "subMetas": {}, - "userData": {} -} diff --git a/assets/script/game/skill/SkillView.ts b/assets/script/game/skill/SkillView.ts index 5cec9bda..9416bf9a 100644 --- a/assets/script/game/skill/SkillView.ts +++ b/assets/script/game/skill/SkillView.ts @@ -166,9 +166,12 @@ export class SkillView extends CCComp { // 清理碰撞体事件监听 if (this.collider) { this.collider.off(Contact2DType.BEGIN_CONTACT); + this.collider.enabled = false; } // 取消所有定时器 this.unscheduleAllCallbacks(); - this.node.destroy(); + if (this.node && this.node.isValid) { + this.node.active = false; + } } -} \ No newline at end of file +}