refactor(hero): 移除SkillConComp并添加ECS系统注册装饰器
- 删除废弃的SkillConComp组件及其meta文件 - 为HeroAtkSystem、HeroAttrSystem等系统添加@ecs.register装饰器 - 在生命周期系统中添加空安全检查 - 移除SkillConComp相关引用及调试日志 - 在移动系统中添加节点有效性检查
This commit is contained in:
@@ -52,7 +52,6 @@ export class SkillCastSystem extends ecs.ComblockSystem implements ecs.IEntityEn
|
||||
* 过滤器:拥有技能数据 + 施法请求的实体
|
||||
*/
|
||||
filter(): ecs.IMatcher {
|
||||
console.log("[SkillCastSystem] filter");
|
||||
return ecs.allOf(HeroSkillsComp, HeroAttrsComp, CastSkillRequestComp);
|
||||
}
|
||||
|
||||
@@ -187,7 +186,6 @@ export class SkillCastSystem extends ecs.ComblockSystem implements ecs.IEntityEn
|
||||
export class SkillCDSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
|
||||
|
||||
filter(): ecs.IMatcher {
|
||||
console.log("[SkillCDSystem] filter");
|
||||
return ecs.allOf(HeroSkillsComp);
|
||||
}
|
||||
|
||||
@@ -218,7 +216,6 @@ export class SkillCDSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
|
||||
export class SkillAutocastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
|
||||
|
||||
filter(): ecs.IMatcher {
|
||||
console.log("[SkillAutocastSystem] filter");
|
||||
return ecs.allOf(HeroSkillsComp, HeroAttrsComp, HeroViewComp);
|
||||
}
|
||||
|
||||
@@ -226,7 +223,6 @@ export class SkillAutocastSystem extends ecs.ComblockSystem implements ecs.ISyst
|
||||
const skillsData = e.get(HeroSkillsComp);
|
||||
const heroModel = e.get(HeroAttrsComp);
|
||||
const heroView = e.get(HeroViewComp);
|
||||
console.log("[SkillAutocastSystem] update");
|
||||
if (!skillsData || !heroModel || !heroView) return;
|
||||
|
||||
// 检查基本条件
|
||||
|
||||
@@ -114,6 +114,7 @@ export class Hero extends ecs.Entity {
|
||||
|
||||
}
|
||||
|
||||
@ecs.register('HeroLifecycleSystem')
|
||||
export class HeroLifecycleSystem extends ecs.ComblockSystem
|
||||
implements ecs.IEntityEnterSystem, ecs.IEntityRemoveSystem {
|
||||
|
||||
@@ -123,11 +124,21 @@ export class HeroLifecycleSystem extends ecs.ComblockSystem
|
||||
|
||||
entityEnter(e: ecs.Entity): void {
|
||||
// 英雄实体创建时的特殊处理
|
||||
console.log(`英雄进入世界: ${e.get(HeroAttrsComp).hero_name}`);
|
||||
const heroAttrs = e.get(HeroAttrsComp);
|
||||
if (heroAttrs) {
|
||||
console.log(`英雄进入世界: ${heroAttrs.hero_name}`);
|
||||
} else {
|
||||
console.log(`英雄进入世界: 实体ID ${e.eid}`);
|
||||
}
|
||||
}
|
||||
|
||||
entityRemove(e: ecs.Entity): void {
|
||||
// 英雄实体销毁时的清理工作
|
||||
console.log(`英雄离开世界: ${e.get(HeroAttrsComp).hero_name}`);
|
||||
const heroAttrs = e.get(HeroAttrsComp);
|
||||
if (heroAttrs) {
|
||||
console.log(`英雄离开世界: ${heroAttrs.hero_name}`);
|
||||
} else {
|
||||
console.log(`英雄离开世界: 实体ID ${e.eid}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ export class HeroAtkComp extends ecs.Comp {
|
||||
}
|
||||
|
||||
/** 业务层业务逻辑处理对象 */
|
||||
@ecs.register('HeroAtkSystem')
|
||||
export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate, ecs.IEntityEnterSystem {
|
||||
|
||||
private debugMode: boolean = false; // 是否启用调试模式
|
||||
|
||||
@@ -392,9 +392,11 @@ export class HeroAttrsComp extends ecs.Comp {
|
||||
* 2. 每帧更新 HP/MP 自然回复
|
||||
* 3. 限制属性值在合理范围内
|
||||
*
|
||||
/**
|
||||
* 使用方式:
|
||||
* 在 RootSystem 中注册此系统,它会自动每帧更新所有拥有 HeroAttrsComp 的实体
|
||||
*/
|
||||
@ecs.register('HeroAttrSystem')
|
||||
export class HeroAttrSystem extends ecs.ComblockSystem
|
||||
implements ecs.ISystemUpdate, ecs.IEntityEnterSystem, ecs.ISystemFirstUpdate {
|
||||
|
||||
|
||||
@@ -159,7 +159,10 @@ export class HeroMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
|
||||
/** 找到最近的敌人 */
|
||||
private findNearestEnemy(entity: ecs.Entity): HeroViewComp | null {
|
||||
const currentPos = entity.get(HeroViewComp).node.position;
|
||||
const currentView = entity.get(HeroViewComp);
|
||||
if (!currentView || !currentView.node) return null;
|
||||
|
||||
const currentPos = currentView.node.position;
|
||||
const team = entity.get(HeroAttrsComp).fac;
|
||||
let nearestEnemyView: HeroViewComp | null = null;
|
||||
let minDistance = Infinity;
|
||||
@@ -167,7 +170,7 @@ export class HeroMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).forEach(e => {
|
||||
const model = e.get(HeroAttrsComp);
|
||||
const view = e.get(HeroViewComp);
|
||||
if (model.fac !== team && !model.is_dead) {
|
||||
if (model.fac !== team && !model.is_dead && view && view.node) {
|
||||
const distance = Math.abs(currentPos.x - view.node.position.x);
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance;
|
||||
@@ -181,12 +184,16 @@ export class HeroMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
|
||||
/** 检测攻击范围内敌人 */
|
||||
private checkEnemiesInRange(entity: ecs.Entity, range: number): boolean {
|
||||
const currentPos = entity.get(HeroViewComp).node.position;
|
||||
const currentView = entity.get(HeroViewComp);
|
||||
if (!currentView || !currentView.node) return false;
|
||||
|
||||
const currentPos = currentView.node.position;
|
||||
const team = entity.get(HeroAttrsComp).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 <= range) {
|
||||
@@ -200,12 +207,16 @@ export class HeroMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
|
||||
/** 检测面前是否有敌人 */
|
||||
private checkEnemiesInFace(entity: ecs.Entity): boolean {
|
||||
const currentPos = entity.get(HeroViewComp).node.position;
|
||||
const currentView = entity.get(HeroViewComp);
|
||||
if (!currentView || !currentView.node) return false;
|
||||
|
||||
const currentPos = currentView.node.position;
|
||||
const team = entity.get(HeroAttrsComp).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 <= 75) {
|
||||
@@ -232,8 +243,11 @@ export class HeroMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
|
||||
// 按x坐标排序:x坐标越大(越前面)的显示在上层
|
||||
const sortedUnits = allUnits.sort((a, b) => {
|
||||
const posA = a.get(HeroViewComp).node.position.x;
|
||||
const posB = b.get(HeroViewComp).node.position.x;
|
||||
const viewA = a.get(HeroViewComp);
|
||||
const viewB = b.get(HeroViewComp);
|
||||
if (!viewA || !viewA.node || !viewB || !viewB.node) return 0;
|
||||
const posA = viewA.node.position.x;
|
||||
const posB = viewB.node.position.x;
|
||||
return posA - posB; // x坐标从小到大排序
|
||||
});
|
||||
|
||||
|
||||
@@ -101,6 +101,7 @@ export class Monster extends ecs.Entity {
|
||||
}
|
||||
|
||||
}
|
||||
@ecs.register('MonLifecycleSystem')
|
||||
export class MonLifecycleSystem extends ecs.ComblockSystem
|
||||
implements ecs.IEntityEnterSystem, ecs.IEntityRemoveSystem {
|
||||
|
||||
@@ -110,11 +111,21 @@ export class MonLifecycleSystem extends ecs.ComblockSystem
|
||||
|
||||
entityEnter(e: ecs.Entity): void {
|
||||
// 怪物实体创建时的特殊处理
|
||||
console.log(`怪物进入世界: ${e.get(HeroAttrsComp).hero_name}`);
|
||||
const heroAttrs = e.get(HeroAttrsComp);
|
||||
if (heroAttrs) {
|
||||
console.log(`怪物进入世界: ${heroAttrs.hero_name}`);
|
||||
} else {
|
||||
console.log(`怪物进入世界: 实体ID ${e.eid}`);
|
||||
}
|
||||
}
|
||||
|
||||
entityRemove(e: ecs.Entity): void {
|
||||
// 怪物实体销毁时的清理工作
|
||||
console.log(`怪物离开世界: ${e.get(HeroAttrsComp).hero_name}`);
|
||||
const heroAttrs = e.get(HeroAttrsComp);
|
||||
if (heroAttrs) {
|
||||
console.log(`怪物离开世界: ${heroAttrs.hero_name}`);
|
||||
} else {
|
||||
console.log(`怪物离开世界: 实体ID ${e.eid}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,12 +88,16 @@ export class MonMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
|
||||
|
||||
/** 检测攻击范围内敌人 */
|
||||
private checkEnemiesInRange(entity: ecs.Entity, range: number): boolean {
|
||||
const currentPos = entity.get(HeroViewComp).node.position;
|
||||
const currentView = entity.get(HeroViewComp);
|
||||
if (!currentView || !currentView.node) return false;
|
||||
|
||||
const currentPos = currentView.node.position;
|
||||
const team = entity.get(HeroAttrsComp).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 <= range) {
|
||||
@@ -107,12 +111,16 @@ export class MonMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
|
||||
|
||||
/** 检测面前是否有敌人 */
|
||||
private checkEnemiesInFace(entity: ecs.Entity): boolean {
|
||||
const currentPos = entity.get(HeroViewComp).node.position;
|
||||
const currentView = entity.get(HeroViewComp);
|
||||
if (!currentView || !currentView.node) return false;
|
||||
|
||||
const currentPos = currentView.node.position;
|
||||
const team = entity.get(HeroAttrsComp).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 <= 75) {
|
||||
@@ -139,8 +147,11 @@ export class MonMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
|
||||
|
||||
// 按x坐标排序:x坐标越大(越前面)的显示在上层
|
||||
const sortedUnits = allUnits.sort((a, b) => {
|
||||
const posA = a.get(HeroViewComp).node.position.x;
|
||||
const posB = b.get(HeroViewComp).node.position.x;
|
||||
const viewA = a.get(HeroViewComp);
|
||||
const viewB = b.get(HeroViewComp);
|
||||
if (!viewA || !viewA.node || !viewB || !viewB.node) return 0;
|
||||
const posA = viewA.node.position.x;
|
||||
const posB = viewB.node.position.x;
|
||||
return posA - posB; // x坐标从小到大排序
|
||||
});
|
||||
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
import { _decorator, Component, Node, ProgressBar, v3, Vec3 } from 'cc';
|
||||
import { HeroViewComp } from './HeroViewComp';
|
||||
import { SkillSet, SType, TGroup, } from '../common/config/SkillSet';
|
||||
import { ecs } from 'db://oops-framework/libs/ecs/ECS';
|
||||
import { GameEvent } from '../common/config/GameEvent';
|
||||
import { FacSet } from '../common/config/BoxSet';
|
||||
import { smc } from '../common/SingletonModuleComp';
|
||||
import { CCComp } from 'db://oops-framework/module/common/CCComp';
|
||||
import { HeroAttrsComp } from './HeroAttrsComp';
|
||||
import { HeroSkillsComp } from './HeroSkills';
|
||||
import { CastSkillRequestComp } from './HSkillSystem';
|
||||
import { SkillEnt } from '../skill/SkillEnt';
|
||||
import { Attrs } from '../common/config/HeroAttrs';
|
||||
import { TalComp } from './TalComp';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass('SkillCon')
|
||||
@ecs.register('SkillCon')
|
||||
export class SkillConComp extends CCComp {
|
||||
HeroView:any=null;
|
||||
HeroEntity:any=null;
|
||||
skill_cd=0
|
||||
private _timers: { [key: string]: any } = {};
|
||||
init(): void {
|
||||
this.on(GameEvent.FightEnd, this.clear_timer, this);
|
||||
}
|
||||
onLoad(){
|
||||
this.HeroView=this.node.getComponent(HeroViewComp)
|
||||
}
|
||||
start() {
|
||||
this.HeroEntity=this.HeroView.ent
|
||||
}
|
||||
|
||||
/**
|
||||
* ⚠️ 注意:此方法已废弃
|
||||
* 技能CD更新和施法逻辑已迁移到 HSkillSystem(SkillCDSystem + SkillAutocastSystem)
|
||||
* 保留此方法仅用于手动触发技能(如玩家点击技能按钮)
|
||||
*/
|
||||
update(dt: number) {
|
||||
// 已由 SkillCDSystem 和 SkillAutocastSystem 处理
|
||||
// 此方法可以删除或改为手动施法的入口
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动施放技能(玩家点击技能按钮)
|
||||
* @param skillIndex 技能索引
|
||||
*/
|
||||
manualCastSkill(skillIndex: number) {
|
||||
if (!this.HeroEntity) return;
|
||||
|
||||
// 选择目标
|
||||
const targets = this.selectTargets(1);
|
||||
|
||||
// ✅ 通过添加标记组件请求施法
|
||||
const request = this.HeroEntity.add(CastSkillRequestComp) as CastSkillRequestComp;
|
||||
request.skillIndex = skillIndex;
|
||||
request.targetPositions = targets;
|
||||
}
|
||||
|
||||
|
||||
/** 施放技能 */
|
||||
castSkill(config: typeof SkillSet[keyof typeof SkillSet]) {
|
||||
let wfuny=this.check_wfuny()
|
||||
let dmg=0
|
||||
this.doSkill(config,wfuny,dmg);
|
||||
}
|
||||
|
||||
|
||||
private doSkill(config: typeof SkillSet[keyof typeof SkillSet],is_wfuny:boolean=false,dmg:number=0) {
|
||||
// 添加节点有效性检查
|
||||
if (!this.node || !this.node.isValid || !this.HeroView || !this.HeroView.node || !this.HeroView.node.isValid) {
|
||||
return;
|
||||
}
|
||||
let targets:any=null
|
||||
if(config.TGroup==TGroup.Self){
|
||||
targets = [this.node.position]
|
||||
}
|
||||
if(config.TGroup==TGroup.Enemy){
|
||||
targets = this.selectTargets(config.t_num)
|
||||
}
|
||||
this.HeroView.playSkillEffect(config.uuid)
|
||||
const sEnt = ecs.getEntity<SkillEnt>(SkillEnt);
|
||||
const timerId = setTimeout(() => {
|
||||
// 再次检查节点有效性
|
||||
if (!this.node || !this.node.isValid || !this.HeroView || !this.HeroView.node || !this.HeroView.node.isValid) {
|
||||
return;
|
||||
}
|
||||
console.log("技能开始",sEnt)
|
||||
sEnt.load(
|
||||
this.node.position,
|
||||
this.node.parent,
|
||||
config.uuid,
|
||||
targets,
|
||||
this.HeroView,
|
||||
dmg
|
||||
);
|
||||
}, 300);
|
||||
if(is_wfuny){
|
||||
this.scheduleOnce(()=>{
|
||||
this.doSkill(config,false,dmg)
|
||||
},0.1)
|
||||
}
|
||||
// 保存定时器ID
|
||||
this._timers[`skill_${config.uuid}`] = timerId;
|
||||
}
|
||||
|
||||
check_wfuny(){
|
||||
let random = Math.random()*100
|
||||
if(random < this.HeroView.Attrs[Attrs.WFUNY]){
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
check_target(){
|
||||
if(this.HeroView.fac==FacSet.HERO){
|
||||
return ecs.query(ecs.allOf(HeroAttrsComp))
|
||||
}else{
|
||||
return ecs.query(ecs.allOf(HeroAttrsComp))
|
||||
}
|
||||
}
|
||||
get_front(entities:any){
|
||||
let keyPos = this.HeroView.fac==FacSet.HERO ?
|
||||
Math.min(...entities.map(e => e.get(HeroViewComp).node.position.x)) :
|
||||
Math.max(...entities.map(e => e.get(HeroViewComp).node.position.x));
|
||||
let keyEntity = entities.find(e => e.get(HeroViewComp).node.position.x === keyPos);
|
||||
return keyEntity.get(HeroViewComp).node.position;
|
||||
}
|
||||
/**
|
||||
* 选择目标(整合版)
|
||||
* @param t_num 目标数量,第一个是最近的前排,后续随机(可重复)
|
||||
* @returns 目标坐标数组
|
||||
*/
|
||||
private selectTargets(t_num: number): Vec3[] {
|
||||
const targets: Vec3[] = [];
|
||||
const entities = this.check_target();
|
||||
|
||||
// 如果没有目标实体
|
||||
if (entities.length === 0) {
|
||||
const defaultPos = this.HeroView.fac === FacSet.HERO ? v3(400, 0, 0) : v3(-400, 0, 0);
|
||||
// 返回t_num个相同的默认位置
|
||||
for (let i = 0; i < t_num; i++) {
|
||||
targets.push(defaultPos.clone());
|
||||
}
|
||||
return targets;
|
||||
}
|
||||
|
||||
// 第一个目标:最前排(离施法者最近的)
|
||||
const frontPos = this.get_front(entities);
|
||||
targets.push(v3(frontPos.x, frontPos.y, 0));
|
||||
|
||||
// 后续目标:随机选择(可以重复)
|
||||
for (let i = 1; i < t_num; i++) {
|
||||
const randomEntity = entities[Math.floor(Math.random() * entities.length)];
|
||||
const randomPos = randomEntity.get(HeroViewComp).node.position;
|
||||
targets.push(v3(randomPos.x, randomPos.y, 0));
|
||||
}
|
||||
|
||||
return targets;
|
||||
}
|
||||
|
||||
public clear_timer() {
|
||||
// console.log("[SkillConComp]:clear_timer",this.HeroView);
|
||||
|
||||
Object.values(this._timers).forEach(clearTimeout);
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.clear_timer();
|
||||
}
|
||||
onDestroy() {
|
||||
// 清理所有定时器
|
||||
// console.log("[SkillConComp]:onDestroy:",this.node.name)
|
||||
Object.values(this._timers).forEach(clearTimeout);
|
||||
this._timers = {};
|
||||
// 移除事件监听
|
||||
this.off(GameEvent.CastHeroSkill);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "6f882a1f-6f5a-4ef5-9ea0-21a0192c2785",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import { ItalConf, TalType, TalEType, talConf } from "../common/config/TalSet";
|
||||
import { BuffConf, SkillSet } from "../common/config/SkillSet";
|
||||
import { HeroInfo } from "../common/config/heroSet";
|
||||
import { HeroViewComp } from "./HeroViewComp";
|
||||
import { SkillConComp } from "./SkillConComp";
|
||||
|
||||
const { ccclass } = _decorator;
|
||||
|
||||
@@ -60,7 +59,6 @@ export class TalComp extends ecs.Comp {
|
||||
start() {
|
||||
// 运行时获取组件,避免编译时循环引用
|
||||
this.heroView = this.ent.get(HeroViewComp);
|
||||
this.skillCon = this.ent.get(SkillConComp);
|
||||
if (this.heroView) {
|
||||
this.heroUuid = this.heroView.hero_uuid;
|
||||
this.initializeTalents();
|
||||
|
||||
Reference in New Issue
Block a user