Files
heros/assets/script/game/hero/SkillConComp.ts
2025-06-20 10:26:28 +08:00

220 lines
8.0 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 { _decorator, Component, Node, Vec3 } from 'cc';
import { HeroViewComp } from './HeroViewComp';
import { SkillSet, TargetGroup, TargetType } from '../common/config/SkillSet';
import { Skill } from '../skills/Skill';
import { ecs } from 'db://oops-framework/libs/ecs/ECS';
import { oops } from 'db://oops-framework/core/Oops';
import { GameEvent } from '../common/config/GameEvent';
import { BoxSet, FacSet } from '../common/config/BoxSet';
import { smc } from '../common/SingletonModuleComp';
import { CCComp } from 'db://oops-framework/module/common/CCComp';
import { FightConComp } from '../map/FightConComp';
import { MonModelComp } from './MonModelComp';
import { HeroModelComp } from './HeroModelComp';
const { ccclass, property } = _decorator;
@ccclass('SkillCon')
@ecs.register('SkillCon')
export class SkillConComp extends CCComp {
FIGHTCON:FightConComp=null!
HeroView:any=null;
HeroEntity:any=null;
private _timers: { [key: string]: number } = {};
private _damageQueue: Array<{ timer: number; callback: () => void }> = [];
init(): void {
oops.message.on(GameEvent.FightEnd, this.clear_timer, this);
}
onLoad(){
this.HeroView=this.node.getComponent(HeroViewComp)
this.FIGHTCON=this.node.parent.getComponent(FightConComp)
// console.log(this.HeroView.uuid+"=>"+this.HeroView.hero_name+"=> SkillConComp onLoad")
this.on(GameEvent.CastHeroSkill,this.cast_master_skill,this)
}
start() {
// console.log(this.HeroView.uuid+"=>"+this.HeroView.hero_name+"=> SkillConComp start")
this.HeroEntity=this.HeroView.ent
}
update(dt: number) {
if(!smc.mission.play||smc.mission.pause) return
this.HeroView.at += dt;
let cd = this.get_cd(this.HeroView.cd,this.HeroView)
let count=this.get_count(1,this.HeroView)
if(count<1) count=1
// console.log(this.HeroView.hero_name+(this.HeroView.is_master?"[主]":"[从] 准备释放")+SkillSet[this.HeroView.atk_skill].name+"=>"+"=>cd:"+cd+"=> count:"+count)
if (this.HeroView.is_atking &&(this.HeroView.at > cd)) {
if(this.HeroView.is_dead) return
const config = SkillSet[this.HeroView.atk_skill];
if (!config) return;
// console.log(this.HeroView.hero_name+(this.HeroView.is_master?"[主]":"[从] 释放")+"=>"+config.name+"=>"+count)
this.castSkill(config,count);
this.HeroView.master_count_atk_count()
this.HeroView.friend_count_atk_count()
this.HeroView.at = 0;
}
}
get_cd(cd:number,view:HeroViewComp){
if(view.fac==FacSet.HERO){
if(view.is_master){
return cd*(100-this.FIGHTCON.hero_buff.ATK_CD+this.FIGHTCON.hero_debuff.DECD)/100
}else{
return cd*(100-this.FIGHTCON.friend_buff.ATK_CD+this.FIGHTCON.friend_debuff.DECD)/100
}
}else{
return cd*(100-this.FIGHTCON.enemy_buff.ATK_CD+this.FIGHTCON.enemy_debuff.DECD)/100
}
}
get_count(count:number,view:HeroViewComp){
if(view.fac==FacSet.HERO){
if(view.is_master){
return count+(this.FIGHTCON.hero_buff.ATK_COUNT-this.FIGHTCON.hero_debuff.DECOUNT)
}else{
return count+(this.FIGHTCON.friend_buff.ATK_COUNT-this.FIGHTCON.friend_debuff.DECOUNT)
}
}else{
return count+(this.FIGHTCON.enemy_buff.ATK_COUNT-this.FIGHTCON.enemy_debuff.DECOUNT)
}
}
cast_master_skill(e:string,uuid:any){
if(!this.HeroView) return
if(!this.HeroView.is_master) return
console.log("hart cast_skill",uuid ,e)
const config = SkillSet[uuid];
this.castSkill(config,1,this.FIGHTCON.hero_buff.SKILL_DMG)
}
/** 施放技能 */
castSkill(config: typeof SkillSet[keyof typeof SkillSet],count:number=1,dmg:number=0) {
// console.log(view.uuid+"=>"+view.hero_name+"施放技能:"+config.uuid);
this.doSkill(config,count,dmg);
}
private doSkill(config: typeof SkillSet[keyof typeof SkillSet],count:number=1,angle:number=0,dmg:number=0) {
// 添加节点有效性检查
if (!this.node || !this.node.isValid || !this.HeroView || !this.HeroView.node || !this.HeroView.node.isValid) {
return;
}
let targets:any=null
switch(config.TargetGroup){
case TargetGroup.Enemy: //单个敌人
targets = this.filterFrontRow();
break
case TargetGroup.Ally: //所有敌人
targets = this.selectAllyTargets();
break
case TargetGroup.Self: //自身
targets = this.HeroView.ent
break
case TargetGroup.Team: //所有友方
break
case TargetGroup.All: //所有单位
break
}
const skillEntity = ecs.getEntity<Skill>(Skill);
if (targets.length === 0) return;
const timerId = setTimeout(() => {
// 再次检查节点有效性
if (!this.node || !this.node.isValid || !this.HeroView || !this.HeroView.node || !this.HeroView.node.isValid) {
return;
}
// 检查目标有效性
if (targets.length <= 0 || !targets[0]) return;
const targetView = targets[0].get(HeroViewComp);
if (!targetView || !targetView.node || !targetView.node.isValid) return;
skillEntity.load(
new Vec3(this.HeroView.node.position.x + BoxSet.ATK_X * this.HeroView.scale,
this.HeroView.node.position.y + BoxSet.ATK_Y, 0),
this.node.parent,
config.uuid,
new Vec3(targetView.node.position.x, targetView.node.position.y, 0),
this.HeroView,
angle,
dmg
);
}, 300);
count-=1
if(count>0){
let angle=10*count
this.scheduleOnce(()=>{
this.doSkill(config,count,angle)
},0.1)
}
// 保存定时器ID
this._timers[`skill_${config.uuid}`] = timerId;
}
/** 筛选最前排单位 */
private filterFrontRow(): ecs.Entity[] {
// 敌方最前排是x坐标最大的我方最前排是x坐标最小的
let entities:any=null
if(this.HeroView.fac==FacSet.HERO){
entities = ecs.query(ecs.allOf(MonModelComp))
}else{
entities = ecs.query(ecs.allOf(HeroModelComp))
}
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));
return entities.filter(e =>
Math.abs(e.get(HeroViewComp).node.position.x - keyPos) < 10
)
}
private selectAllyTargets( ): ecs.Entity[] {
if(this.HeroView.fac==FacSet.HERO){
return ecs.query(ecs.allOf(MonModelComp))
}else{
return ecs.query(ecs.allOf(MonModelComp))
}
}
/** 随机选择目标 */
private pickRandomTarget(count: number): ecs.Entity[] {
let entities:any=null
if(this.HeroView.fac==FacSet.HERO){
entities = ecs.query(ecs.allOf(MonModelComp))
}else{
entities = ecs.query(ecs.allOf(HeroModelComp))
}
const shuffled = [...entities].sort(() => 0.5 - Math.random());
return shuffled.slice(0, count);
}
public clear_timer() {
// console.log("clear_timer");
Object.values(this._timers).forEach(clearTimeout);
}
reset() {
this.clear_timer();
}
onDestroy() {
// 清理所有定时器
Object.values(this._timers).forEach(clearTimeout);
this._timers = {};
// 移除事件监听
this.off(GameEvent.CastHeroSkill);
}
}