182 lines
6.1 KiB
TypeScript
182 lines
6.1 KiB
TypeScript
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);
|
||
}
|
||
}
|
||
|
||
|