refactor(skill): 重构技能系统以支持对象池复用

将技能节点管理改为使用对象池模式,提高性能
添加技能节点复用时的初始化逻辑
统一技能组件获取和重置方式
更新英雄配置中的默认技能
This commit is contained in:
walkpan
2026-01-02 23:37:20 +08:00
parent 81f55a796d
commit 557e43ed29
3 changed files with 60 additions and 10 deletions

View File

@@ -166,11 +166,11 @@ export const HeroInfo: Record<number, heroInfo> = {
// 1. 基础近战型 // 1. 基础近战型
5201:{uuid:5201,name:"兽人战士",path:"mo1", fac:FacSet.MON, kind:1,as:3.0, 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次普攻积累天赋计数"}, buff:[],tal:[],info:"标准炮灰确保英雄能完成3次普攻积累天赋计数"},
// 2. 快速突击型 // 2. 快速突击型
5301:{uuid:5301,name:"兽人斥候",path:"mo1", fac:FacSet.MON, kind:1,as:1.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)刷新率"}, buff:[],tal:[],info:"快速突击:极高移速贴脸,检测护盾(7102)刷新率"},
// 3. 重型坦克型 // 3. 重型坦克型
5401:{uuid:5401,name:"兽人卫士",path:"mo1", fac:FacSet.MON, kind:1,as:5.0, 5401:{uuid:5401,name:"兽人卫士",path:"mo1", fac:FacSet.MON, kind:1,as:5.0,
@@ -184,7 +184,7 @@ export const HeroInfo: Record<number, heroInfo> = {
// 5. 特殊机制型 // 5. 特殊机制型
5601:{uuid:5601,name:"兽人自爆兵",path:"mo1", fac:FacSet.MON, kind:1,as:3.0, 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)"}, buff:[],tal:[],info:"特殊机制:极端伤害,漏怪即秒杀,检测减伤(7103)"},
// 召唤师:持续召唤小怪(后续可在技能系统中实现 SType.zhaohuan // 召唤师:持续召唤小怪(后续可在技能系统中实现 SType.zhaohuan
5602:{uuid:5602,name:"兽人召唤师",path:"mo1", fac:FacSet.MON, kind:1,as:3.0, 5602:{uuid:5602,name:"兽人召唤师",path:"mo1", fac:FacSet.MON, kind:1,as:3.0,

View File

@@ -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 { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { EType, SkillSet } from "../common/config/SkillSet"; import { EType, SkillSet } from "../common/config/SkillSet";
import { oops } from "db://oops-framework/core/Oops"; import { oops } from "db://oops-framework/core/Oops";
@@ -13,10 +13,34 @@ import { smc } from "../common/SingletonModuleComp";
/** Skill 模块 */ /** Skill 模块 */
@ecs.register(`Skill`) @ecs.register(`Skill`)
export class Skill extends ecs.Entity { export class Skill extends ecs.Entity {
/** 多键对象池Map<prefabPath, NodePool> */
static pools: Map<string, NodePool> = 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; SDataCom!: SDataCom;
SMoveCom!: SMoveDataComp SMoveCom!: SMoveDataComp
/** 当前技能的预制体路径(用于对象池回收) */
private prefabPath: string = "";
private skillNode: Node | null = null; // 持有节点引用以便销毁时回收
/** ---------- 业务层 ---------- */ /** ---------- 业务层 ---------- */
// SkillBll!: SkillBllComp; // SkillBll!: SkillBllComp;
@@ -73,8 +97,11 @@ export class Skill extends ecs.Entity {
node.setPosition(startPos); node.setPosition(startPos);
// 初始化移动组件 - 从SkillView获取移动参数 // 初始化移动组件 - 从SkillView获取移动参数
let sMoveCom = this.get(SMoveDataComp);
const sMoveCom = this.get(SMoveDataComp); if (!sMoveCom) {
sMoveCom = this.add(SMoveDataComp);
}
sMoveCom.reset(); // 复用组件时重置状态
sMoveCom.startPos.set(startPos); sMoveCom.startPos.set(startPos);
sMoveCom.targetPos.set(targetPos); sMoveCom.targetPos.set(targetPos);
sMoveCom.s_uuid = s_uuid; sMoveCom.s_uuid = s_uuid;
@@ -87,7 +114,11 @@ export class Skill extends ecs.Entity {
let cAttrsComp=caster.ent.get(HeroAttrsComp) 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.group=caster.box_group
sDataCom.caster=caster sDataCom.caster=caster
sDataCom.Attrs={...cAttrsComp.Attrs} sDataCom.Attrs={...cAttrsComp.Attrs}
@@ -101,7 +132,16 @@ export class Skill extends ecs.Entity {
// 注: 自定义释放逻辑,视图层实现 ecs.IComp 接口的 ecs 组件需要手动释放 // 注: 自定义释放逻辑,视图层实现 ecs.IComp 接口的 ecs 组件需要手动释放
this.remove(SDataCom); this.remove(SDataCom);
this.remove(SMoveDataComp) this.remove(SMoveDataComp)
// 移除组件会触发 reset但我们在 reset 中移除了 destroy
this.remove(SkillView) this.remove(SkillView)
// 回收节点到对象池
if (this.skillNode && this.skillNode.isValid && this.prefabPath) {
Skill.putToPool(this.prefabPath, this.skillNode);
this.skillNode = null;
}
super.destroy(); super.destroy();
} }

View File

@@ -30,21 +30,31 @@ export class SkillView extends CCComp {
private maxAttackFrames: number = 1; // 最大攻击帧数,可配置 private maxAttackFrames: number = 1; // 最大攻击帧数,可配置
// 已命中目标追踪,防止重复伤害 // 已命中目标追踪,防止重复伤害
start() { start() {
this.init();
}
init() {
this.SConf = SkillSet[this.s_uuid] this.SConf = SkillSet[this.s_uuid]
this.sData=this.ent.get(SDataCom) this.sData = this.ent.get(SDataCom)
this.anim=this.node.getComponent(Animation) this.anim = this.node.getComponent(Animation)
this.node.active = true; this.node.active = true;
this.collider = this.getComponent(Collider2D); this.collider = this.getComponent(Collider2D);
if(this.collider) { if(this.collider) {
this.collider.group = this.group; this.collider.group = this.group;
this.collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this); this.collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
this.collider.enabled = true; // 确保复用时开启
} }
if(this.node.getComponent(Animation)){ if(this.node.getComponent(Animation)){
let anim = this.node.getComponent(Animation); let anim = this.node.getComponent(Animation);
//console.log("[SkillCom]:has anim",anim) //console.log("[SkillCom]:has anim",anim)
anim.on(Animation.EventType.FINISHED, this.onAnimationFinished, this); 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) { onBeginContact (seCol: Collider2D, oCol: Collider2D) {
// 安全获取双方信息用于日志 // 安全获取双方信息用于日志