326 lines
13 KiB
TypeScript
326 lines
13 KiB
TypeScript
import { _decorator,Collider2D ,Contact2DType,v3,IPhysics2DContact,Vec3, tween, math, RigidBody2D, Animation, sp, Tween} 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 { smc } from "../common/SingletonModuleComp";
|
||
import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops";
|
||
import { GameEvent } from "../common/config/GameEvent";
|
||
import { AType, DTType, EType, RType, SkillSet, SType, TGroup } from "../common/config/SkillSet";
|
||
import { BoxSet, FacSet } from "../common/config/BoxSet";
|
||
import { HeroViewComp } from "../hero/HeroViewComp";
|
||
import { BezierMove } from "../BezierMove/BezierMove";
|
||
import { FightConComp } from "../map/FightConComp";
|
||
import { MonModelComp } from "../hero/MonModelComp";
|
||
import { FightSet } from "../common/config/Mission";
|
||
import { HeroModelComp } from "../hero/HeroModelComp";
|
||
|
||
|
||
const { ccclass, property } = _decorator;
|
||
|
||
/** 视图层对象 */
|
||
@ccclass('SkillCom')
|
||
@ecs.register('SkillCom')
|
||
export class SkillCom extends CCComp {
|
||
s_uuid:number = 0;
|
||
s_name:string = "";
|
||
hero:number = 0;
|
||
speed:number = 200;
|
||
scale:number = 1;
|
||
angle:number = 0;
|
||
atk_count:number = 0;
|
||
is_destroy:boolean = false;
|
||
enemys:any = [];
|
||
AType: number = 0; // 运动类型
|
||
startPos: Vec3 = v3(); // 起始位置
|
||
targetPos: Vec3 = v3(); // 目标位置
|
||
duration: number = 0; // 技能持续时间
|
||
prefabName: string = ""; // 预制体名称
|
||
animName: string = "";
|
||
group:number = 0; //阵营
|
||
fac:number=0; //阵营
|
||
caster:any=null;
|
||
distance_x:number=0;
|
||
distance_y:number=0;
|
||
ap:number=0;
|
||
heal:number=0;
|
||
shield:number=0;
|
||
burn_count:number=0;
|
||
burn_value:number=0;
|
||
stun_time:number=0;
|
||
stun_ratto:number=0;
|
||
frost_ratto:number=0;
|
||
frost_time:number=0;
|
||
FIGHTCON:FightConComp=null;
|
||
run_time:number=0;
|
||
hited_time:number=0;
|
||
hit_count:number=0;
|
||
spine:sp.Skeleton=null;
|
||
anim:Animation=null;
|
||
tweenInstance:Tween<any> = null;
|
||
t_end_x:number=0;
|
||
caster_crit:number=0;
|
||
caster_crit_d:number=0;
|
||
puncture:number=0;
|
||
puncture_damage:number=0;
|
||
EType:any=null
|
||
private moveDirection: Vec3 | null = null; // 添加一个属性来存储移动方向
|
||
|
||
protected onLoad(): void {
|
||
this.FIGHTCON=this.node.parent.getComponent(FightConComp)
|
||
|
||
}
|
||
|
||
start() {
|
||
this.EType=SkillSet[this.s_uuid].EType
|
||
this.node.setPosition(this.startPos.x,this.startPos.y,0)
|
||
if(this.node.getChildByName('anm')){
|
||
this.spine=this.node.getChildByName('anm').getComponent('sp.Skeleton') as sp.Skeleton;
|
||
}else{
|
||
this.anim=this.node.getComponent(Animation)
|
||
}
|
||
oops.message.on(GameEvent.MissionEnd, this.doDestroy, this);
|
||
this.node.active = true;
|
||
// console.log("[SkillCom]:caster",this.caster)
|
||
|
||
|
||
let collider = this.getComponent(Collider2D);
|
||
if(collider) {
|
||
collider.group = this.group;
|
||
collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
||
}
|
||
// console.log(this.group +"技能 collider ",collider);
|
||
switch(SkillSet[this.s_uuid].AType){
|
||
case AType.parabolic:
|
||
this.node.angle +=10
|
||
let bm=this.node.getComponent(BezierMove)
|
||
// bm.speed=700
|
||
if(this.group==BoxSet.MONSTER) bm.controlPointSide=-1
|
||
bm.moveTo(this.targetPos)
|
||
break;
|
||
case AType.StartEnd:
|
||
// 2段位移:先升高,然后移到目的地
|
||
this.executeTwoStageMovement();
|
||
break;
|
||
case AType.fixedEnd:
|
||
this.node.setPosition(this.targetPos.x,this.targetPos.y,0)
|
||
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);
|
||
}
|
||
if(this.node.getChildByName('anm')){
|
||
if(this.node.getChildByName('anm').getComponent('sp.Skeleton')){
|
||
// console.log("[SkillCom]:has spine",this.spine)
|
||
this.spine.setCompleteListener((trackEntry) => {
|
||
this.onAnimationFinished()
|
||
// console.log("[SkillCom]:[track %s][animation %s] complete: %s", trackEntry.trackIndex);
|
||
});
|
||
}
|
||
}
|
||
break;
|
||
case AType.fixedStart:
|
||
this.node.setPosition(this.startPos.x,this.startPos.y,0)
|
||
this.scheduleOnce(()=>{
|
||
this.do_buff()
|
||
console.log("[SkillCom]:fixedStart",SkillSet[this.s_uuid].in-0.2)
|
||
},SkillSet[this.s_uuid].in-0.2)
|
||
break;
|
||
}
|
||
|
||
|
||
}
|
||
|
||
onAnimationFinished(){
|
||
if(SkillSet[this.s_uuid].EType==EType.timeEnd) return
|
||
this.is_destroy=true
|
||
}
|
||
//范围伤害
|
||
range_damage(){
|
||
let enemys=ecs.query(ecs.allOf(MonModelComp))
|
||
if(this.fac==FacSet.MON) enemys=ecs.query(ecs.allOf(HeroModelComp))
|
||
enemys.forEach(entity => {
|
||
let view=entity.get(HeroViewComp)
|
||
if(view){
|
||
let dis =Math.abs(this.node.position.x-view.node.position.x)
|
||
if(dis > SkillSet[this.s_uuid].with) return
|
||
this.single_damage(view,true)
|
||
}
|
||
});
|
||
}
|
||
//单体伤害
|
||
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;
|
||
target.do_atked(this.ap,this.caster_crit,this.caster_crit_d,
|
||
this.burn_count,this.burn_value,
|
||
this.stun_time,this.stun_ratto,
|
||
this.frost_time,this.frost_ratto) // ap 及暴击 属性已经在skill.ts 处理
|
||
console.log("[SkillCom]:single_damage",this.ap,this.caster_crit,this.caster_crit_d,this.hit_count)
|
||
if(SkillSet[this.s_uuid].debuff>0){
|
||
let deUP =this.get_debuff() // 因为不是每个技能都需要,debuff的增益在这里处理, ap 及暴击 属性已经在skill.ts 处理
|
||
let debuff=SkillSet[this.s_uuid]
|
||
let dev=debuff.deV*(100+deUP.deV)/100
|
||
let deR=debuff.deR+deUP.deR
|
||
dev=Math.round(dev*100)/100
|
||
let deC=debuff.deC+deUP.deC //dec只作为次数叠加
|
||
// console.log("[SkillCom]:debuff",SkillSet[this.s_uuid].name,debuff.debuff,deUP.deV,deUP.deC)
|
||
target.add_debuff(debuff.debuff,dev,deC,deR)
|
||
}
|
||
this.hit_count++
|
||
if(this.hit_count>=(SkillSet[this.s_uuid].hit+this.puncture)&&(SkillSet[this.s_uuid].DTType!=DTType.range)) this.is_destroy=true // 技能命中次数
|
||
}
|
||
|
||
onBeginContact (seCol: Collider2D, oCol: Collider2D) {
|
||
// console.log(this.scale+"碰撞开始 ",seCol,oCol);
|
||
let target = oCol.getComponent(HeroViewComp)
|
||
if(oCol.group!=this.group){
|
||
if(target == null) return;
|
||
this.single_damage(target)
|
||
// this.ent.destroy()
|
||
}
|
||
}
|
||
get_debuff(){ //debuff 加成
|
||
let debuff = {deV:0,deC:0,deR:0}
|
||
let buff=null
|
||
if(this.caster.is_master) buff = this.FIGHTCON.hero_buff
|
||
if(this.caster.is_friend) buff = this.FIGHTCON.friend_buff
|
||
if(this.caster.is_boss||this.caster.is_kalami) buff = this.FIGHTCON.enemy_buff
|
||
if(buff==null) return debuff
|
||
debuff.deV=buff.DEBUFF_VALUE
|
||
debuff.deC=buff.DEBUFF_COUNT
|
||
debuff.deR=buff.DEBUFF_UP
|
||
return debuff
|
||
}
|
||
|
||
/**
|
||
* 执行2段位移:先升高,然后移到目的地
|
||
*/
|
||
private executeTwoStageMovement() {
|
||
const totalDuration = SkillSet[this.s_uuid].in-0.1
|
||
const firstStageDuration = totalDuration * 0.4; // 第一段占40%时间
|
||
const secondStageDuration = totalDuration * 0.6; // 第二段占60%时间
|
||
|
||
// 第一段:升高
|
||
const riseHeight = 100; // 升高高度
|
||
const midPosition = v3(this.node.position.x, this.node.position.y + riseHeight, 0);
|
||
|
||
// 第二段:移动到目标位置
|
||
const finalPosition = v3(this.targetPos.x, this.targetPos.y, 0);
|
||
|
||
// 创建缓动序列
|
||
tween(this.node)
|
||
// 第一段:升高
|
||
.to(firstStageDuration, { position: midPosition }, {
|
||
easing: 'quadOut' // 使用二次缓出效果,让上升更自然
|
||
})
|
||
// 第二段:移动到目标位置
|
||
.to(secondStageDuration, { position: finalPosition }, {
|
||
easing: 'quadInOut' // 使用二次缓入缓出效果
|
||
}).call(()=>{
|
||
this.do_buff()
|
||
})
|
||
.start();
|
||
}
|
||
private do_buff(){
|
||
console.log("[SkillCom]:do_buff")
|
||
let teams=ecs.query(ecs.allOf(HeroModelComp))
|
||
if(this.fac==FacSet.MON) teams=ecs.query(ecs.allOf(MonModelComp))
|
||
if(SkillSet[this.s_uuid].TGroup==TGroup.Team||SkillSet[this.s_uuid].TGroup==TGroup.Self) {
|
||
teams.forEach(entity => {
|
||
let view=entity.get(HeroViewComp)
|
||
if(view.node.position.x==this.targetPos.x){
|
||
if(SkillSet[this.s_uuid].SType==SType.heal){
|
||
view.add_hp(this.heal,false)
|
||
}
|
||
if(SkillSet[this.s_uuid].SType==SType.shield){
|
||
view.add_shield(this.shield)
|
||
}
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
private startLinearMove(dt: number) {
|
||
if (!this.speed || this.is_destroy) return;
|
||
if(this.s_uuid == 6005){
|
||
// console.log("[SkillCom]:startLinearMove",this.node.position.x)
|
||
}
|
||
// 使用角度方向移动
|
||
const newX = this.node.position.x + this.speed * dt*this.scale;
|
||
const newY = this.node.position.y;
|
||
this.node.setPosition(newX, this.node.position.y, this.node.position.z);
|
||
|
||
// 检查是否超出边界
|
||
if (newX < -400 || newX > 400) {
|
||
this.is_destroy = true;
|
||
}
|
||
}
|
||
|
||
|
||
update(deltaTime: number) {
|
||
let config=SkillSet[this.s_uuid]
|
||
if(smc.mission.pause) {
|
||
if(this.spine) this.spine.paused=true
|
||
if(this.anim) this.anim.pause()
|
||
return;
|
||
}
|
||
if(this.anim) this.anim.resume()
|
||
if(this.spine) this.spine.paused=false
|
||
if (!this.node || !this.node.isValid) return;
|
||
if(config.EType==EType.timeEnd){
|
||
this.run_time+=deltaTime
|
||
if(this.run_time>config.in){
|
||
// console.log("[SkillCom]: timeEnd destroy",this.s_uuid,this.run_time)
|
||
this.is_destroy=true
|
||
}
|
||
}
|
||
//范围伤害
|
||
this.hited_time+=deltaTime
|
||
if(this.hited_time>config.hited&&(SkillSet[this.s_uuid].DTType==DTType.range)){
|
||
this.hited_time=0
|
||
this.range_damage()
|
||
}
|
||
//直线移动
|
||
if(this.AType == AType.linear) this.startLinearMove(deltaTime);
|
||
this.toDestroy();
|
||
}
|
||
|
||
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
|
||
}
|
||
to_console(value:any,value2:any=null,value3:any=null){
|
||
console.log("[SkillCom]:["+this.s_name+this.s_uuid+"]:",value,value2,value3)
|
||
}
|
||
|
||
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
|
||
reset() {
|
||
this.is_destroy = false;
|
||
this.AType = 0;
|
||
this.speed = 0;
|
||
this.startPos.set();
|
||
this.targetPos.set();
|
||
this.moveDirection = null; // 重置移动方向
|
||
// 先移除所有碰撞回调
|
||
const collider = this.getComponent(Collider2D);
|
||
if (collider) {
|
||
collider.off(Contact2DType.BEGIN_CONTACT);
|
||
}
|
||
this.scheduleOnce(() => {
|
||
this.node.destroy();
|
||
}, 0);
|
||
}
|
||
|
||
} |