Files
pixelheros/assets/script/game/skill/Skill.ts
walkpan 31321a1a45 feat(技能系统): 添加施法者实体ID字段用于安全校验
在SDataCom组件中添加casterEid字段,并在Skill和SkillView中使用该字段替代原有的链式访问,提高代码安全性和可读性
2026-01-06 14:20:45 +08:00

152 lines
5.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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";
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
import { SkillView } from "./SkillView";
import { SDataCom } from "./SDataCom";
import { SMoveDataComp } from "../skill/SMoveComp";
import { HeroViewComp } from "../hero/HeroViewComp";
import { smc } from "../common/SingletonModuleComp";
/** Skill 模块 */
@ecs.register(`Skill`)
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;
SMoveCom!: SMoveDataComp
/** 当前技能的预制体路径(用于对象池回收) */
private prefabPath: string = "";
private skillNode: Node | null = null; // 持有节点引用以便销毁时回收
/** ---------- 业务层 ---------- */
// SkillBll!: SkillBllComp;
/** ---------- 视图层 ---------- */
SView!: SkillView;
/** 实始添加的数据层组件 */
protected init() {
this.addComponents<SDataCom>(SDataCom);
this.addComponents<SMoveDataComp>(SMoveDataComp);
}
load(startPos: Vec3, parent: Node, s_uuid: number, targetPos: Vec3,
caster:HeroViewComp,ext_dmg:number=0) {
const config = SkillSet[s_uuid];
if (!config) {
console.error("[Skill] 技能配置不存在:", s_uuid);
return;
}
// 加载预制体
const path = `game/skill/atk/${config.sp_name}`;
const prefab:Prefab = oops.res.get(path, Prefab);
if (!prefab) {
console.error("[Skill] 预制体加载失败:", path);
return;
}
// console.log("load skill startPos",startPos)
const node: Node = instantiate(prefab);
// console.log("load skill node",node)
var scene = smc.map.MapView.scene;
node.parent = scene.entityLayer!.node!.getChildByName("SKILL")!;
// 设置节点属性
let face=caster.node.scale.x < 0 ? -1 : 1
node.setScale(v3(node.scale.x*face,node.scale.y,1))
// 初始视图
const SView = node.getComponent(SkillView);
if(config.EType!=EType.collision){
const collider=node.getComponent(BoxCollider2D);
if(collider){
collider.enabled=false
}
}
// 只设置必要的运行时属性,配置信息通过 SkillSet[uuid] 访问
// 核心标识
SView.s_uuid= s_uuid
SView.group= caster.box_group
this.add(SView);
startPos.x=startPos.x+SView.atk_x*face
startPos.y=startPos.y+SView.atk_y
node.setPosition(startPos);
// 初始化移动组件 - 从SkillView获取移动参数
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;
sMoveCom.scale = caster.node.scale.x < 0 ? -1 : 1;
sMoveCom.runType = config.RType;
sMoveCom.endType = config.EType;
// 从SkillView获取移动参数位置初始化由SMoveSystem统一处理
sMoveCom.atk_x = SView.atk_x;
sMoveCom.atk_y = SView.atk_y;
let cAttrsComp=caster.ent.get(HeroAttrsComp)
// 初始化数据组件
let sDataCom = this.get(SDataCom);
if (!sDataCom) {
sDataCom = this.add(SDataCom);
}
sDataCom.reset();
sDataCom.group=caster.box_group
sDataCom.caster=caster
sDataCom.casterEid=caster.ent.eid
sDataCom.Attrs={...cAttrsComp.Attrs}
sDataCom.s_uuid=s_uuid
sDataCom.fac=cAttrsComp.fac
sDataCom.ext_dmg=ext_dmg
}
/** 模块资源释放 */
destroy() {
// 注: 自定义释放逻辑,视图层实现 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();
}
}