import { _decorator, sp } from "cc"; import GObject, { GTowards } from "../GObject"; import { JNFrameInfo } from "../../../../../extensions/ngame/assets/ngame/sync/frame/JNSyncFrame"; import GFSMBattle from "../fsm/base/GFSMBattle/GFSMBattle"; import { GFSMBattleAmin, GFSMBattleAminEnum } from "../fsm/base/GFSMBattle/GFSMBattleAmin"; import { Vec2 } from "cc"; import { v3 } from "cc"; import { GTactical } from "../../entity/GTactical"; import { JEasing, JTween } from "../../../../../extensions/ngame/assets/ngame/sync/frame/game/tween/JNFrameTween"; import { v2 } from "cc"; import { app } from "../../../App"; import { TableGRoleAttack } from "../../../../resources/config/ts/TableGRoleAttack"; import { GAttack, GAttackBase } from "../attack/GAttack"; import { TableGRole } from "../../../../resources/config/ts/TableGRole"; import { TableGRoleSkill } from "../../../../resources/config/ts/TableGRoleSkill"; import { GSkill, GSkillBase, GSkillState } from "../../skill/GSkill"; import JNSkeleton from "../../../../../extensions/ngame/assets/ngame/sync/frame/game/spine/JNFrameSkeleton"; const { ccclass, property } = _decorator; export enum GRoleAnimEvent{ Attack = "attack", //普通攻击 } //角色基类 export default abstract class GRoleBase extends GObject{ @property(JNSkeleton) spine:JNSkeleton; //角色 role:TableGRole //角色技能 skills:GSkillBase[] = []; //角色类型 type:number; //状态机 fsm:GFSMBattle; //动画状态机 fsmAnim:GFSMBattleAmin; //玩家攻击范围 range:number = 100; //移动速度 moveSpeed:number = 80; //在阵容中的下标 tacticalIndex:number; //阵容 _tactical:GTactical; get tactical(){return this._tactical}; set tactical(value:GTactical){ this.setTowards(value.towards); this._tactical = value; } //阵容位置 _tacticalPos:Vec2; get tacticalPos(){ return this._tacticalPos} set tacticalPos(value:Vec2){ this._tacticalPos = value} //血量 blood:number = 100; fullBlood:number = 100; //是否死亡 _isDie:boolean = false; get isDie(){ return this._isDie} set isDie(value:boolean){ this._isDie = value; //设置死亡状态 this.fsmAnim.isDie = value; } //受击回调 hitCallbacks:Function[] = []; //添加受击回调 addHitCallback(fun:Function){this.hitCallbacks.push(fun)}; //攻击回调 attackCallbacks:Function[] = []; //添加受击回调 addAttackCallback(fun:Function){this.attackCallbacks.push(fun)}; get():GRoleBase{ if(this.isDie) return null; return this; } onSyncLoad(){ if(!this.spine) this.spine = this.node.getComponent(JNSkeleton); //如果没有生成则直接销毁 if(!this.spine) { this.node.destroy(); return; } // this.spine.debugBones = true; this.bind(this.role); //创建角色状态机 this.fsm = this.fsmCreate(); //创建角色动画状态机 this.fsmAnim = this.fsmAnimCreate(); //监听攻击 this.fsmAnim.addEventListener(GRoleAnimEvent.Attack,this.onAttack.bind(this)); //监听死亡击飞 this.fsmAnim.addStartListener(GFSMBattleAminEnum.Fly,this.onFly.bind(this)); } //设置角色 bind(role:TableGRole){ if(this.spine) this.spine.skeletonData = app.role.skData[role.id]; this.range = role.roleAttackRange; //设置攻击范围 this.role = role; //设置角色 // 设置技能 this.skills = role.roleSkillIds.map(skillId => { let info = TableGRoleSkill.getConfig(skillId); return (new GSkill[info.skillController]()).bind(this,info); }) } //创建一个状态机 protected abstract fsmCreate():GFSMBattle; //创建一个动画状态机 protected abstract fsmAnimCreate():GFSMBattleAmin; onSyncUpdate(dt: number,frame:JNFrameInfo, input?: T){ //更新状态机 this.fsm && this.fsm.onUpdate(dt / 1000); this.fsmAnim && this.fsmAnim.onUpdate(dt / 1000); //更新技能 this.skills.forEach(skill => skill.onUpdate(dt)); } //向目标点移动 onMoveTarget(target:Vec2,dt:number){ //获取两个坐标差值向量 let mins = this.v2World.subtract(target); let normal = this.v2World.subtract(target).normalize(); //设置朝向 if(normal.x != 0){ if(normal.x < 0){ this.setTowards(GTowards.RIGHT) }else{ this.setTowards(GTowards.LEFT) } } if(Vec2.len(normal) >= Vec2.len(mins)){ this.node.setWorldPosition(Object.assign(v3(),target.clone())); return true; }else{ //移动 this.node.worldPosition = this.node.worldPosition.subtract(v3(normal.x*dt*this.moveSpeed,normal.y*dt*this.moveSpeed,0)) return false; } } //朝向目标 onTowardsTarget(role:GRoleBase<{}>){ //获取两个坐标差值向量 let normal = this.v2World.subtract(role.v2World).normalize(); //设置朝向 if(normal.x != 0){ if(normal.x < 0){ this.setTowards(GTowards.RIGHT) }else{ this.setTowards(GTowards.LEFT) } } } //攻击 onAttack(){ if(!this.fsm.enemy) return; //敌人扣血 let info = TableGRoleAttack.getConfig(this.role.id); (new GAttack[info.attackWay]()).attack(this,info); this.attackCallbacks.forEach(fun => fun()); } //释放技能 每一次只能释放一次 onSkill():boolean{ for (const item of this.skills) { if(item.isRelease()){ //如果可以释放则释放 item.release(); return true; } } return false; } //受击 onHit(){ // return; this.blood -= 10; this.hitCallbacks.forEach(fun => fun()); //检测是否死亡 if(this.blood <= 0){ //关闭状态机 this.fsm.close(); //设置死亡 this.isDie = true; } } onDebugHit(){ this.blood -= 10; //检测是否死亡 if(this.blood <= 0){ //关闭状态机 this.fsm.close(); //设置死亡 this.isDie = true; } } //击飞 onFly(){ if(this.nId == 1) console.log("onFly"); let vWorld = this.node.worldPosition; let vEndWorld = this.getWorldBackLen(v2(1000,500)); this.JTween(vWorld) .to({x:vEndWorld.x},800) .onUpdate(pos => this.node.worldPosition = pos) .start(); this.JTween(vWorld) .to({y:vEndWorld.y},800) .easing(JEasing.Circular.Out) .onUpdate(pos => this.node.worldPosition = vWorld) .start(); } //恢复阵容朝向 onRecoverTacticalTowards(){ this.setTowards(this.tactical.towards); } //过滤敌人 filterEnemy(roles:GRoleBase<{}>[] = []){ return roles.filter(role => role.type != this.type); } //判断是否可以释放技能 isReleaseSkill():boolean{ for (const skill of this.skills) { if(skill.isRelease()){ return true; } } return false; } //释放技能 onReleaseSkill():boolean{ for (const skill of this.skills) { if(skill.isRelease()){ skill.release(); return true; } } return false; } //是否正在释放技能 isReleasingSkill():boolean { for (const skill of this.skills) { if(skill.state() == GSkillState.Releasing){ return true; } } return false; } }