From 557e43ed29e9109f44076bdc5a6f0c93c9e9b7c9 Mon Sep 17 00:00:00 2001 From: walkpan Date: Fri, 2 Jan 2026 23:37:20 +0800 Subject: [PATCH] =?UTF-8?q?refactor(skill):=20=E9=87=8D=E6=9E=84=E6=8A=80?= =?UTF-8?q?=E8=83=BD=E7=B3=BB=E7=BB=9F=E4=BB=A5=E6=94=AF=E6=8C=81=E5=AF=B9?= =?UTF-8?q?=E8=B1=A1=E6=B1=A0=E5=A4=8D=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将技能节点管理改为使用对象池模式,提高性能 添加技能节点复用时的初始化逻辑 统一技能组件获取和重置方式 更新英雄配置中的默认技能 --- assets/script/game/common/config/heroSet.ts | 6 +-- assets/script/game/skill/Skill.ts | 48 +++++++++++++++++++-- assets/script/game/skill/SkillView.ts | 16 +++++-- 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/assets/script/game/common/config/heroSet.ts b/assets/script/game/common/config/heroSet.ts index 793b9fe6..366be10b 100644 --- a/assets/script/game/common/config/heroSet.ts +++ b/assets/script/game/common/config/heroSet.ts @@ -166,11 +166,11 @@ export const HeroInfo: Record = { // 1. 基础近战型 5201:{uuid:5201,name:"兽人战士",path:"mo1", fac:FacSet.MON, kind:1,as:3.0, - type:HType.warrior,lv:1,hp:40,mp:100,def:0,ap:5,dis:60,speed:180,skills:[6201], + type:HType.warrior,lv:1,hp:40,mp:100,def:0,ap:5,dis:60,speed:180,skills:[6005], buff:[],tal:[],info:"标准炮灰:确保英雄能完成3次普攻积累天赋计数"}, // 2. 快速突击型 5301:{uuid:5301,name:"兽人斥候",path:"mo1", fac:FacSet.MON, kind:1,as:1.2, - type:HType.assassin,lv:1,hp:30,mp:100,def:0,ap:12,dis:50,speed:400,skills:[6201], + type:HType.assassin,lv:1,hp:30,mp:100,def:0,ap:12,dis:50,speed:400,skills:[6005], buff:[],tal:[],info:"快速突击:极高移速贴脸,检测护盾(7102)刷新率"}, // 3. 重型坦克型 5401:{uuid:5401,name:"兽人卫士",path:"mo1", fac:FacSet.MON, kind:1,as:5.0, @@ -184,7 +184,7 @@ export const HeroInfo: Record = { // 5. 特殊机制型 5601:{uuid:5601,name:"兽人自爆兵",path:"mo1", fac:FacSet.MON, kind:1,as:3.0, - type:HType.assassin,lv:1,hp:60,mp:100,def:0,ap:250,dis:50,speed:220,skills:[6201], + type:HType.assassin,lv:1,hp:60,mp:100,def:0,ap:250,dis:50,speed:220,skills:[6005], buff:[],tal:[],info:"特殊机制:极端伤害,漏怪即秒杀,检测减伤(7103)"}, // 召唤师:持续召唤小怪(后续可在技能系统中实现 SType.zhaohuan) 5602:{uuid:5602,name:"兽人召唤师",path:"mo1", fac:FacSet.MON, kind:1,as:3.0, diff --git a/assets/script/game/skill/Skill.ts b/assets/script/game/skill/Skill.ts index 6440ba1a..cf21d022 100644 --- a/assets/script/game/skill/Skill.ts +++ b/assets/script/game/skill/Skill.ts @@ -1,4 +1,4 @@ -import { BoxCollider2D, instantiate, Node, Prefab, v3, Vec3 } from "cc"; +import { BoxCollider2D, instantiate, Node, Prefab, v3, Vec3, NodePool } from "cc"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { EType, SkillSet } from "../common/config/SkillSet"; import { oops } from "db://oops-framework/core/Oops"; @@ -13,10 +13,34 @@ import { smc } from "../common/SingletonModuleComp"; /** Skill 模块 */ @ecs.register(`Skill`) export class Skill extends ecs.Entity { + /** 多键对象池:Map */ + static pools: Map = new Map(); + + static getFromPool(path: string): Node | null { + if (this.pools.has(path)) { + const pool = this.pools.get(path)!; + if (pool.size() > 0) { + return pool.get(); + } + } + return null; + } + + static putToPool(path: string, node: Node) { + if (!this.pools.has(path)) { + this.pools.set(path, new NodePool()); + } + this.pools.get(path)!.put(node); + } + /** ---------- 数据层 ---------- */ SDataCom!: SDataCom; SMoveCom!: SMoveDataComp + /** 当前技能的预制体路径(用于对象池回收) */ + private prefabPath: string = ""; + private skillNode: Node | null = null; // 持有节点引用以便销毁时回收 + /** ---------- 业务层 ---------- */ // SkillBll!: SkillBllComp; @@ -73,8 +97,11 @@ export class Skill extends ecs.Entity { node.setPosition(startPos); // 初始化移动组件 - 从SkillView获取移动参数 - - const sMoveCom = this.get(SMoveDataComp); + let sMoveCom = this.get(SMoveDataComp); + if (!sMoveCom) { + sMoveCom = this.add(SMoveDataComp); + } + sMoveCom.reset(); // 复用组件时重置状态 sMoveCom.startPos.set(startPos); sMoveCom.targetPos.set(targetPos); sMoveCom.s_uuid = s_uuid; @@ -87,7 +114,11 @@ export class Skill extends ecs.Entity { let cAttrsComp=caster.ent.get(HeroAttrsComp) // 初始化数据组件 - const sDataCom = this.get(SDataCom); + let sDataCom = this.get(SDataCom); + if (!sDataCom) { + sDataCom = this.add(SDataCom); + } + sDataCom.reset(); sDataCom.group=caster.box_group sDataCom.caster=caster sDataCom.Attrs={...cAttrsComp.Attrs} @@ -101,7 +132,16 @@ export class Skill extends ecs.Entity { // 注: 自定义释放逻辑,视图层实现 ecs.IComp 接口的 ecs 组件需要手动释放 this.remove(SDataCom); this.remove(SMoveDataComp) + + // 移除组件会触发 reset,但我们在 reset 中移除了 destroy this.remove(SkillView) + + // 回收节点到对象池 + if (this.skillNode && this.skillNode.isValid && this.prefabPath) { + Skill.putToPool(this.prefabPath, this.skillNode); + this.skillNode = null; + } + super.destroy(); } diff --git a/assets/script/game/skill/SkillView.ts b/assets/script/game/skill/SkillView.ts index da2095e5..3249c581 100644 --- a/assets/script/game/skill/SkillView.ts +++ b/assets/script/game/skill/SkillView.ts @@ -30,21 +30,31 @@ export class SkillView extends CCComp { private maxAttackFrames: number = 1; // 最大攻击帧数,可配置 // 已命中目标追踪,防止重复伤害 start() { + this.init(); + } + + init() { this.SConf = SkillSet[this.s_uuid] - this.sData=this.ent.get(SDataCom) - this.anim=this.node.getComponent(Animation) + this.sData = this.ent.get(SDataCom) + this.anim = this.node.getComponent(Animation) this.node.active = true; this.collider = this.getComponent(Collider2D); if(this.collider) { this.collider.group = this.group; this.collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this); + this.collider.enabled = true; // 确保复用时开启 } if(this.node.getComponent(Animation)){ let anim = this.node.getComponent(Animation); //console.log("[SkillCom]:has anim",anim) anim.on(Animation.EventType.FINISHED, this.onAnimationFinished, this); + + // 对象池复用时,需要手动播放默认动画(因为 Play On Load 只在首次生效) + if (anim.defaultClip) { + anim.play(anim.defaultClip.name); + } } - + this.attackFrameCount = 0; // 重置攻击帧计数 } onBeginContact (seCol: Collider2D, oCol: Collider2D) { // 安全获取双方信息用于日志