Files
heros/assets/script/game/skill/AtkConCom.ts
panw 028a175df4 refactor(skill): 优化技能系统实现和配置
- 删除未使用的ECS元文件和组件
- 修复技能视图和移动逻辑,添加调试日志
- 调整技能预制体配置和动画参数
- 简化技能加载和方向处理逻辑
- 新增技能6002并更新英雄配置
- 统一受击特效路径命名
2025-10-31 16:42:57 +08:00

236 lines
9.2 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, Animation, CCBoolean, Collider2D, Contact2DType, Tween, UITransform, v3, Vec3 } from "cc";
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
import { BezierMove } from "../BezierMove/BezierMove";
import { DTType, EType, SkillSet, SType } from "../common/config/SkillSet";
import { BoxSet, FacSet } from "../common/config/BoxSet";
import { HeroViewComp } from "../hero/HeroViewComp";
import { GameEvent } from "../common/config/GameEvent";
import { smc } from "../common/SingletonModuleComp";
import { Attrs } from "../common/config/HeroAttrs";
const { ccclass, property } = _decorator;
/** 视图层对象 */
@ccclass('AtkConCom')
@ecs.register('AtkCon', false)
export class AtkConCom extends CCComp {
@property
public anmEnd: boolean = false;
@property
public cbox: boolean = false;
// 核心标识和配置
s_uuid:number = 0;
// 运行时状态(必须缓存的)
is_destroy:boolean = false;
startPos: Vec3 = v3(); // 起始位置
targetPos: Vec3 = v3(); // 目标位置
group:number = 0; //阵营
fac:number=0; //阵营
run_time:number = 0;
// 战斗相关运行时数据
Attrs:any=null
hit_count:number = 0;
// 组件引用
anim:Animation=null;
tweenInstance:Tween<any> = null;
private moveDirection: Vec3 | null = null; // 添加一个属性来存储移动方向
// 缓存的配置对象(避免重复查找)
public Config: any = null;
private isInitialized: boolean = false;
private initializeConfig() {
if (this.isInitialized) return;
// 缓存技能配置,避免重复查找
this.Config = SkillSet[this.s_uuid];
if (!this.Config) {
// console.error("[SkillCom] 技能配置不存在:", this.s_uuid);
return;
}
this.isInitialized = true;
// console.log("[SkillCom] 技能配置初始化完成:", this.s_uuid, this.Config.name);
}
start() {
this.initializeConfig();
// var entity = this.ent as ecs.Entity; // ecs.Entity 可转为当前模块的具体实体对象
// this.on(ModuleEvent.Cmd, this.onHandler, this);
this.anim=this.node.getComponent(Animation)
this.on(GameEvent.MissionEnd, this.doDestroy, this);
this.node.active = true;
let collider = this.getComponent(Collider2D);
if(collider) {
collider.group = this.group;
collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
}
}
do_anim(){
if(this.node.getComponent(Animation)){
let anim = this.node.getComponent(Animation);
//console.log("[SkillCom]:has anim",anim)
anim.on(Animation.EventType.FINISHED, this.onAnimationFinished, this);
}
}
do_parabolic(){
let bm=this.node.getComponent(BezierMove)
this.node.angle +=10
// bm.speed=700
if(this.group==BoxSet.MONSTER) {bm.controlPointSide=-1 }
bm.rotationSmoothness=0.6
bm.moveTo(this.targetPos)
}
do_line(){
let bm=this.node.getComponent(BezierMove)
let s_x=this.startPos.x
let s_y=this.startPos.y
let t_x=this.targetPos.x
let t_y=this.targetPos.y
// 设定目标x
this.targetPos.x = 400;
if(this.group == BoxSet.MONSTER) {
bm.controlPointSide = -1;
this.targetPos.x = -400;
}
// 计算斜率
const k = (t_y - s_y) / (t_x - s_x);
// 按直线公式计算新的y
this.targetPos.y = k * (this.targetPos.x - s_x) + s_y;
bm.controlPointOffset=0
bm.rotationSmoothness=0.6
bm.moveTo(this.targetPos);
}
do_fixedEnd(){
this.node.setPosition(this.targetPos.x > 360?300:this.targetPos.x,this.node.position.y,0)
this.do_anim()
}
do_fixedStart(){
this.node.setPosition(this.startPos.x,this.node.position.y,0)
this.do_anim()
}
onAnimationFinished(){
// console.log("[SkillCom]:onAnimationFinished",this.s_uuid)
if (!this.Config) return;
if(this.Config.EType==EType.timeEnd) return
if(this.Config.SType!=SType.damage){
}
this.is_destroy=true
}
onBeginContact (seCol: Collider2D, oCol: Collider2D) {
// console.log(this.scale+"碰撞开始 ",seCol,oCol);
if(seCol.node.position.x-oCol.node.position.x > 100 ) return
let target = oCol.getComponent(HeroViewComp)
if(oCol.group!=this.group){
if(target == null) return;
if (!this.Config) return;
// console.log("[SkillCom]:onBeginContact oCol||seCol",oCol.node.position,seCol.node.position)
this.single_damage(target,this.Config.DTType==DTType.range?true:false)
// this.ent.destroy()
}
}
//单体伤害
single_damage(target:HeroViewComp,is_range:boolean=false){
// //console.log("[SkillCom]:onBeginContact hit_count:",this.hit_count,SkillSet[this.s_uuid].hit)
// if(this.hit_count > 0&&!is_range) this.ap=this.ap*(50+this.puncture_damage)/100 // 穿刺后 伤害减半,过滤范围伤害
if(target == null) return;
if (!this.Config) return;
let damage=Math.floor(this.Attrs[Attrs.AP]*(SkillSet[this.s_uuid].ap/100))
if(this.hit_count > 0 &&!is_range ){
let Percentage=Math.pow((50+this.Attrs[Attrs.PUNCTURE_DMG])/100, this.hit_count)
damage=damage*Percentage
}
target.do_atked(damage,this.Attrs,this.s_uuid) // ap 及暴击 属性已经在skill.ts 处理
// console.log("[SkillCom]:single_damage t:tp:rtp",this.node.position,this.targetPos,target.node.position)
this.hit_count++
// console.log("[SkillCom]:碰撞次数:技能次数:穿刺次数",this.hit_count,this.Config.hit,this.puncture)
if(this.hit_count>=(this.Config.hit+this.Attrs[Attrs.PUNCTURE])&&(this.Config.DTType!=DTType.range)&&(this.Config.EType!=EType.animationEnd)&&(this.Config.EType!=EType.timeEnd)) this.is_destroy=true // 技能命中次数
}
update(deltaTime: number) {
// 确保配置已初始化(处理 update 可能先于 start 执行的情况)
if (!this.isInitialized) {
this.initializeConfig();
if (!this.Config) return;
}
if(smc.mission.pause) {
if(this.anim) this.anim.pause()
return;
}
if(this.anim) this.anim.resume()
if (!this.node || !this.node.isValid) return;
if(this.Config.EType==EType.timeEnd){
this.run_time+=deltaTime
if(this.run_time>this.Config.in){
// //console.log("[SkillCom]: timeEnd destroy",this.s_uuid,this.run_time)
this.is_destroy=true
}
}
this.toDestroy();
}
public atk(args:any){
let dis=this.node.getComponent(UITransform).width/2
let targetsInRange: HeroViewComp[] = []
// 收集范围内所有敌方目标
ecs.query(ecs.allOf(HeroViewComp)).some(e => {
const view = e.get(HeroViewComp);
if(view.fac!=this.fac) {
const distance = Math.abs(this.node.position.x - view.node.position.x);
if(distance <= dis) {
targetsInRange.push(view);
}
}
});
// 根据配置的hit_num决定攻击模式
const hitNum = SkillSet[this.s_uuid].hit_num || 0;
if(hitNum > 0) {
// 限制目标数量按距离排序选择最近的N个目标
if(targetsInRange.length > 0) {
// 按距离排序(从近到远)
targetsInRange.sort((a, b) => {
const distanceA = Math.abs(this.node.position.x - a.node.position.x);
const distanceB = Math.abs(this.node.position.x - b.node.position.x);
return distanceA - distanceB;
});
// 限制目标数量
const maxTargets = Math.min(hitNum, targetsInRange.length);
const selectedTargets = targetsInRange.slice(0, maxTargets);
selectedTargets.forEach(target => {
this.single_damage(target, false);
});
}
} else {
// 范围伤害:对所有范围内目标造成伤害
if(targetsInRange.length > 0) {
targetsInRange.forEach(target => {
this.single_damage(target, false);
});
}
}
}
toDestroy() {
if(this.is_destroy){
if (this.ent) {
this.ent.destroy();
} else {
// 如果ent不存在直接销毁节点
if (this.node && this.node.isValid) {
this.node.destroy();
}
}
}
}
doDestroy(){
// //console.log("[SkillCom]:doDestroy")
this.is_destroy=true
}
reset() {
this.node.destroy();
}
}