import { Vec2 } from "cc"; import GBaseMode from "../GBaseMode"; import { GRoleUtil } from "../entity/GRole"; import { GTactical } from "../entity/GTactical"; import GRoleDefault from "../base/role/GRoleDefault"; import { Prefab } from "cc"; import { _decorator } from "cc"; import { instantiate } from "cc"; import { GPVPModePlayerEnum } from "./GPVPMode"; import { JNFrameInfo } from "../../../../extensions/ngame/assets/ngame/sync/frame/JNSyncFrame"; import { GMapLoop } from "../base/common/map/GMapLoop"; import { Node } from "cc"; import JNFrameTime from "../../../../extensions/ngame/assets/ngame/sync/frame/game/time/JNFrameTime"; import { TD, app } from "../../App"; import { v3 } from "cc"; import { v2 } from "cc"; import GFSMOnHookMode from "./OnHook/GFSMOnHookMode"; import { TB, TbGEntity } from "../../config/data/schema"; import PlayerTacticalData, { PlayerTacticalEvent } from "../../data/PlayerTacticalData"; import GRoleOnHookPlayerExpand from "../base/role/expand/OnHook/GRoleOnHookPlayerExpand"; import PlayerPetData from "../../data/PlayerPetData"; import { GUI } from "../../ui/UIConfig"; import { GOnHookPet, GOnHookPets } from "../../../../extensions/ngame/assets/ngame/message/proto"; import GOnHookManager, { GOnHookManagerEvent } from "../../manager/battle/mode/GOnHookManager"; import GRoleOnHookCreepsExpand from "../base/role/expand/OnHook/GRoleOnHookCreepsExpand"; import GPetAttribute from "../base/values/attribute/role/GPetAttribute"; import GDefaultMode from "./default/GDefaultMode"; import GOnHookData from "../../data/GOnHookData"; import { GModeEvent, GModeHitInfo } from "./GMode"; const { ccclass, property } = _decorator; //挂机模式状态 export enum GOnHookModeState{ GoTarget,//前往目标 Attack, //攻击 AttackEnd, //攻击结束 } //角色 export enum GOnHookModePlayerEnum{ PLAYER, //玩家 ENEMY, //怪物 } //玩家信息 export interface GOnHookInfo{ //阵法 tactical: GTactical; } /** * 挂机模式 无限出现小怪 (不是联机模式 该模式支持使用本地数据 和 API) */ @ccclass('GOnHookMode') export default class GOnHookMode extends GDefaultMode<{},{}>{ @property(Prefab) rolePrefab: Prefab = null; @property(Node) objects: Node = null; get scene():Node{ return this.objects; } //玩家信息 playerInfo:GOnHookInfo; //宠物信息 enemyInfo:GOnHookInfo; //玩家宠物位置 playerPos: Vec2 = new Vec2(-400,0); //怪物位置 enemyPos: Vec2 = new Vec2(400,0); //玩家宠物 playerRoles: GRoleDefault[] = []; //敌方宠物 enemyRoles: GRoleDefault[] = []; //每一波怪的距离 everyX:number = 600; //下一波怪的对战位置X _nextFightX:number = 0; get nextFightX(){return this._nextFightX} set nextFightX(value:number){ //修改玩家阵法位置 this.playerInfo.tactical.setOffset(this.playerPos.clone().add(v2(value,0))) this.enemyInfo.tactical.setOffset(this.enemyPos.clone().add(v2(value,0))) this._nextFightX = value; } fsm:GFSMOnHookMode; //是否允许攻击 isAllowAttack:boolean = false; //添加监听事件 addEvent(){ app.event.on(PlayerTacticalEvent.UPDATE_TACTICAL,this.onUpdatePlayerPet,this); // app.event.on(GOnHookManagerEvent.UPDATE_MAP,this.onUpdateWorld,this); } //移除监听事件 onDestroy(){ super.onDestroy(); app.event.off(PlayerTacticalEvent.UPDATE_TACTICAL,this.onUpdatePlayerPet,this); // app.event.off(GOnHookManagerEvent.UPDATE_MAP,this.onUpdateWorld,this); } onSyncInitSuccess():void{ //初始化战斗 console.log("GOnHookMode 模式初始化"); //调整相机 this.camera.enabled = true; let camreaPos = this.camera.node.worldPosition; this.camera.node.worldPosition = v3(0,750,camreaPos.z) //初始化状态机 this.fsm = new GFSMOnHookMode(this); //更新场景 this.onUpdateWorld(); this.playerInfo = { tactical: GTactical.getTactical().setOffset(this.playerPos) }; this.enemyInfo = { tactical: GTactical.getTactical(true).setOffset(this.enemyPos) }; this.onUpdatePlayerPet(); //添加监听 this.addEvent(); // //模拟请求生成宠物 // app.socket.SendBack(GAction.MODE_ON_HOOK_SPAWN_PET,{ // type:GActionType.GOnHookPets, // fun:(info:GOnHookPets) => { // console.log("接受到野怪列表",info) // } // }) //生成玩家 // this.playerInfo.roles.forEach((info,index) => this.onGenRole(GOnHookModePlayerEnum.PLAYER,index + 1,info)) // //生成敌人 // this.onResetGenerateEnemy(); } //更新地图 onUpdateWorld(){ let info = TD.TbGOnHookMaps.get(GOnHookData.getIns().info.onHookMap); this.setWorldMap(info.mapId); } //更新页面 onUpdateView(){ } //更新玩家宠物 onUpdatePlayerPet(){ //获取玩家阵容 let infos = PlayerTacticalData.getIns().getTacticalInfo(); //移除不再阵容中的宠物 let roles = [...this.getOnesRoleAlive(GOnHookModePlayerEnum.PLAYER)] roles.forEach(role => { let expand = role.getComponent(GRoleOnHookPlayerExpand); //如果宠物不再阵容中 则 移除宠物 if(infos.indexOf(expand.petId) < 0){ //移除宠物 this.playerRoles.splice(this.playerRoles.indexOf(role),1); role.isDie = true; } }) infos.forEach((petId,index) => { if(petId){ this.onGenPlayerPet(index+1,petId); } }) } //更新帧 onSyncUpdate(dt: number,frame:JNFrameInfo, input?: {}){ super.onSyncUpdate(dt,frame,input); this.onUpdateMap(dt); this.onUpdateCamera(dt); this.fsm.onUpdate(dt,frame); } //更新相机逻辑 onUpdateCamera(dt:number){ //如果没有敌人相机永远锁定最前面的宠物 if(this.isAllowAttack && this.isHaveEnemy()){ //如果有敌人则移动到战斗位置 let cameraWorld = this.camera.node.worldPosition.clone(); this.camera.node.worldPosition = cameraWorld.lerp(v3(this.nextFightX,cameraWorld.y,cameraWorld.z),(dt / 1000)); }else{ //获取冲到最前面的宠物 let roles = this.getOnesRoleAlive(GOnHookModePlayerEnum.PLAYER); let frontRole = roles.sort((role1,role2) => role2.v2World.x - role1.v2World.x)[0]; if(!frontRole) return; //设置相机 位置 let cameraWorld = this.camera.node.worldPosition.clone(); this.camera.node.worldPosition = cameraWorld.lerp(v3(frontRole.v2World.x,cameraWorld.y,cameraWorld.z),(dt / 1000)); } } //生成玩家宠物 onGenPlayerPet(index:number,petId:number){ //如果场上有这个宠物则更新阵法位置 let passRole:GRoleDefault; this.playerRoles.forEach(role => { if(role.getComponent(GRoleOnHookPlayerExpand).petId == petId) passRole = role; }) if(passRole){ //更新宠物阵法位置 passRole.tacticalIndex = index; return; } //获取要生成的宠物 let info = PlayerPetData.getIns().petIdQueryPetInfo(petId); if(!info){ app.layer.Open(GUI.Tips,{text:"未拥有当前上阵的宠物"}); return; } let role = this.onGenRole(GOnHookModePlayerEnum.PLAYER,index,TD.TbGRole.get(info.petTbId)); //向宠物添加 OnHook 扩展 let expand = role.node.addComponent(GRoleOnHookPlayerExpand); expand.petId = petId; //添加宠物属性 role.onEffectiveValue(new GPetAttribute(info)); } //生成野怪 onGenCreeps(index:number,creeps:GOnHookPet){ let role = this.onGenRole(GOnHookModePlayerEnum.ENEMY,index,TD.TbGRole.get(creeps.petTbId)); //向野怪添加扩展 let expand = role.node.addComponent(GRoleOnHookCreepsExpand); expand.creeps = creeps; //添加野怪属性 role.onEffectiveValue(new GPetAttribute({ petId:0, petPlayerId:0, petTbId:creeps.petTbId, petLevel:creeps.petLevel, petStar:0, petStarExp:0, })); } //生成宠物 onGenRole(type: GOnHookModePlayerEnum,index:number,info:TB.TbGRole):GRoleDefault { let tactical = this.getInfo(type).tactical; let pos:Vec2 = this.getInfo(type).tactical.getPosition(index); if(!pos) return; let role = instantiate(this.rolePrefab); let entity = role.getComponent(GRoleDefault); //初始化 entity.onInit(type,info,tactical,index); //绑定寻敌 entity.onQueryEunmy = () => { return this.getEnumy(entity,type); } //绑定死亡回调 entity.addKillBackEvent(this.onRoleKillBack.bind(this)) //绑定受击回调 entity.addHitCallback(this.onHitBack.bind(this)); this.addGObject(entity,tactical.getPosition(index)); this.getOnesRole(type).push(entity); return entity; } //获取配置 getInfo(type: GOnHookModePlayerEnum): GOnHookInfo { if(type == GOnHookModePlayerEnum.PLAYER) return this.playerInfo; if(type == GOnHookModePlayerEnum.ENEMY) return this.enemyInfo; } //获取阵营宠物 getOnesRole(type: GOnHookModePlayerEnum):GRoleDefault[]{ if(type == GOnHookModePlayerEnum.PLAYER) return this.playerRoles; if(type == GOnHookModePlayerEnum.ENEMY) return this.enemyRoles; } //获取存活的宠物 getOnesRoleAlive(type: GOnHookModePlayerEnum):GRoleDefault[]{ if(type == GOnHookModePlayerEnum.PLAYER) return this.playerRoles.filter(role => !!role.get()); if(type == GOnHookModePlayerEnum.ENEMY) return this.enemyRoles.filter(role => !!role.get()); } //获取敌人 getEnumy(player:GRoleDefault,type:GOnHookModePlayerEnum):GRoleDefault{ if(!this.isAllowAttack) return null; let enumyOnes = GOnHookModePlayerEnum.ENEMY //如果是ENEMY 则 它的敌人是 PLAYER if(type == GOnHookModePlayerEnum.ENEMY) enumyOnes = GOnHookModePlayerEnum.PLAYER //获取敌人 let roles = this.getOnesRoleAlive(enumyOnes); //通过距离获取最近的敌人 if(roles[0]){ let len = Math.abs(Vec2.distance(player.v2World,roles[0].v2World)); let enumy = roles[0]; for (let index = 0; index < roles.length; index++) { const role = roles[index]; let tLen; if(tLen = Math.abs(Vec2.distance(player.v2World,role.v2World)) < len){ enumy = role; len = tLen; } } return enumy; }else{ return null; } } //生成敌人 onResetGenerateEnemy(){ this.enemyRoles = []; let sign = TD.TbGOnHookMaps.get(GOnHookData.getIns().info.onHookMap).sign; let table:{data:TbGEntity.TOnHookLevel} = TD[sign].get(GOnHookData.getIns().info.levelId); for (let index = 0; index < table.data.petSize; index++) { //获取敌人 let creeps = GOnHookManager.getIns().getNextCreeps(); if(!creeps) return; //没有获取到野怪则返回 this.onGenCreeps(index + 1,creeps); } // this.enemyInfo.roles.forEach((info,index) => this.onGenRole(GOnHookModePlayerEnum.ENEMY,index + 1,info)); } //角色死亡回调 onRoleKillBack(role:GRoleDefault){ //死亡销毁 JNFrameTime.getInstance().setTimeout(() => { if(role.isValid) role.node.destroy() },3000) //如果死亡的是野怪则通知野怪死亡 if(role.getComponent(GRoleOnHookCreepsExpand)){ GOnHookManager.getIns().onKillSreeps(role.getComponent(GRoleOnHookCreepsExpand).creeps); } //清理 this.onClearCache(); } //角色受击回调 onHitBack(role:GRoleDefault,hit:number){ if(!role.get()) return; //添加受击显示 app.event.emit(GModeEvent.HIT,{ mode:this, role:role, hit:hit, world:role.v2World, camera:this.camera, }); } //清理缓存 onClearCache(){ //清理宠物 let roles = [...this.playerRoles]; roles.forEach(role => { if(!role.get()){ this.playerRoles.splice(this.playerRoles.indexOf(role),1); } }) roles = [...this.enemyRoles]; roles.forEach(role => { if(!role.get()){ this.enemyRoles.splice(this.enemyRoles.indexOf(role),1); } }) } //是否有怪物 isHaveEnemy(){ if(!this.isAllowAttack) return []; return this.getOnesRoleAlive(GOnHookModePlayerEnum.ENEMY).filter(role => !!role.get()).length > 0; } //前往下一个目标 onNextTarget(){ //下一个目标点 this.nextFightX = this.nextFightX + this.everyX; } }