Files
heros/assets/script/game/skill/AtkConCom.ts
walkpan 11f1f08c1d refactor(属性系统): 重构英雄属性系统,将属性定义移至HeroAttrs模块
- 将Attrs和DBuff相关定义从SkillSet迁移至HeroAttrs
- 新增NeAttrs枚举用于管理负面状态
- 重构HeroViewComp中的buff/debuff处理逻辑
- 优化属性分类和分组,增加新属性类型
- 移除旧的DBuff相关代码,改用统一的负面状态管理
2025-10-25 15:04:11 +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 > 360?300: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();
}
}