import { _decorator, instantiate, Node, Prefab, Size, Tween, tween, UITransform, Vec2, Vec3 ,Animation, EventTouch, Button, sp, Enum, Label, Toggle, Sprite, SpriteFrame, v3} from 'cc'; import { BaseView } from '../../../framework/layer/BaseView'; import { Framework } from '../../../framework/Framework'; import { FrameworkConf } from '../../../framework/config/FrameworkConf'; import { AudioID } from '../../../framework/config/AudioConf'; import { AsyncQueue, NextFunction } from '../../../framework/queue/AsyncQueue'; import { Hero } from './node/Hero'; import { Enemy } from './node/Enemy'; import { Hurt } from './node/Hurt'; import { BattleNodeBase } from './node/BattleNodeBase'; import { BattleControl } from './control/BattleControl'; import { BattleUtil } from './data/BattleUtil'; import { BattleEventManager } from './base/BattleEventManager'; import { BattleEventData_EnemyBorn, BattleEventData_EnemyBuff, BattleEventData_EnemyDie, BattleEventData_EnemyHurt, BattleEventData_EnemyMove, BattleEventData_HeroAttack, BattleEventData_Over, BattleEventTarget, BattleEventType } from './base/BattleEventUtil'; import { isValid } from 'cc'; import { ZombieBattleControl } from '../zombie/control/ZombieBattleControl'; import { ZombieMapConf } from '../zombie/conf/ZombieMapConf'; import { ZombieHeroData, ZombieHeroDataPool } from '../zombie/data/ZombieHeroData'; //地图比例尺 1:70 let mapScaleX = 72; let mapScaleY = 15; let basePoint = {x:-325,y:-70} let baseOffset = {x:0,y:0} //地图格子转坐标 let MapDataPosToView = (x:number,y:number) => { let XX = (x+baseOffset.x) * mapScaleX + basePoint.x; let YY = (y+baseOffset.y) * mapScaleY + basePoint.y; return new Vec3(XX, YY, 0); //return new Vec3(x * mapScale + basePoint.x, y * mapScale + basePoint.y, 0); } //地图速度转换 let MapDataSpeedToView = (x:number,y:number) => { let XX = x * mapScaleX * BattleUtil.FrameRate; let YY = y * mapScaleY * BattleUtil.FrameRate; return new Vec2(XX, YY,); //return new Vec3(x * mapScale + basePoint.x, y * mapScale + basePoint.y, 0); } const { ccclass, property } = _decorator; export interface PosData { node: Node, hero: Node, bLock: boolean, posID: number, pos: Vec3, posNumber: number } @ccclass('ZombieUI') export class ZombieUI extends BaseView { @property({ type: Sprite, tooltip: "地图" }) mapSprite: Sprite = null; @property({ type: Node, tooltip: "攻击位" }) attackNode: Node = null; @property({ type: Node, tooltip: "背包位" }) bagNode: Node = null; @property({ type: Node, tooltip: "减血数字根节点" }) hurtNode: Node = null; // 攻击位 attackPosList: PosData[] = []; //根据posID获取做的索引 attackPosMap: Map = new Map(); //背包位 bagPosList: PosData[] = []; mapID = 1; @property({ type: [Prefab], tooltip: "英雄" }) heroModelList: Prefab[] = []; heroPool: Map = new Map(); heroList: Node[] = []; @property({type:[Node],tooltip:"升级效果"}) levelUpEffect:Node[] = [] @property({ type: [Prefab], tooltip: "敌人" }) ememyModelList: Prefab[] = []; enemyPool: Node[] = []; enemyMap: Map = new Map(); enemyWaitTime: number = 0; @property({ type: [Prefab], tooltip: "受伤数字" }) hurtModelList: Prefab[] = []; hurtPool: Node[] = []; hurtList: Node[] = []; @property({ type:Node, tooltip: "所有角色根节点" }) roleNode: Node = null; @property({ type:Node, tooltip: "攻击范围" }) radiusNode: Node = null; bStart = false; waitTime = 5; touchStart: Node = null; gameTime = 0; battleControl: ZombieBattleControl = null; //当前动画下标 levelUpEffectIndex = 0; //是否自动合成 isAutoMerge = true; protected onLoad() { super.onLoad(); this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this) this.node.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this); this.node.on(Node.EventType.TOUCH_END, this.onTouchEnd, this); this.node.on(Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this); for (let i = 0; i < this.levelUpEffect.length; i++) { this.levelUpEffect[i].getComponent(sp.Skeleton).setCompleteListener(()=>{ this.levelUpEffect[i].active = false; }) } this.battleControl = ZombieBattleControl.GetInstance() BattleEventManager.instance.addEvent(BattleEventTarget.Update, this.updateDataEvent.bind(this), -1); this.initPool() } protected start(): void { this.battleControl.init(this.mapID) this.init(); } protected onDestroy() { } protected update(dt: number): void { this.updateSiblingIndex() if(this.bStart){ this.gameTime += dt; let nowFrame = Math.floor(this.gameTime/BattleUtil.FrameTime) if(nowFrame > this.battleControl.map.curTurn){ // while(nowFrame > this.battleControl.map.curTurn+1){ //需要移动的对象做瞬时计算 //目前只有敌人,以后会有子弹或者其他会移动的 this.enemyMap.forEach(element => { element.getComponent(Enemy).battleUpdate(BattleUtil.FrameTime) }); this.battleControl.update(); if(this.battleControl.isBattleEnd){ break; } } this.enemyMap.forEach(element => { element.getComponent(Enemy).battleUpdate(BattleUtil.FrameTime) }); this.battleControl.update(); } } else{ if(this.waitTime > 0){ this.waitTime -= dt; } else{ this.bStart = true; } } } private updateDataEvent(event){ if(this.battleControl.isBattleEnd && event.eventType!=BattleEventType.Over){ console.log("结束") return } switch(event.eventType){ case BattleEventType.EnemyBorn:{ let enemyData = event as BattleEventData_EnemyBorn; this.addEnemy(enemyData); break; } case BattleEventType.EnemyMove:{ let enemyData = event as BattleEventData_EnemyMove; // console.log("移动",enemyData.ID,enemyData.speedVector.x,enemyData.speedVector.y) if(this.enemyMap.has(enemyData.ID)){ let enemy = this.enemyMap.get(enemyData.ID); enemy.getComponent(Enemy).speedVector = MapDataSpeedToView(enemyData.speedVector.x, enemyData.speedVector.y); } break; } case BattleEventType.EnemyHurt:{ let enemyData = event as BattleEventData_EnemyHurt; //console.log("移动",enemyData.ID,enemyData.hurt,enemyData.status) if(this.enemyMap.has(enemyData.targetID)){ let enemy = this.enemyMap.get(enemyData.targetID); enemy.getComponent(Enemy).hurt(enemyData.hurt); this.addHurt(enemy.position,enemyData.hurt) } break; } case BattleEventType.EnemyDie:{ // console.log("死亡",event) let enemyData = event as BattleEventData_EnemyDie; if(this.enemyMap.has(enemyData.ID)){ let enemy = this.enemyMap.get(enemyData.ID); enemy.getComponent(Enemy).die(()=>{ this.enemyMap.delete(enemyData.ID); this.enemyPool.push(enemy); } ); } break; } case BattleEventType.EnemyBuff:{ let enemyData = event as BattleEventData_EnemyBuff; if(this.enemyMap.has(enemyData.ID)){ let enemy = this.enemyMap.get(enemyData.ID); //enemy.getComponent(Enemy).addbuff(enemyData.buff); } break; } case BattleEventType.HeroAttack:{ // console.log("攻击",event) let attackData = event as BattleEventData_HeroAttack; if(this.attackPosMap.has(attackData.posID)){ let posData = this.attackPosMap.get(attackData.posID); let enemy = this.enemyMap.get(attackData.targetID); if( posData && posData.hero){ if(enemy){ posData.hero.getComponent(Hero).attack(enemy) enemy.getComponent(Enemy).hurt(attackData.hurt); this.addHurt(enemy.position,attackData.hurt) } else{ posData.hero.getComponent(Hero).stand() } } } break; } case BattleEventType.Over:{ let attackData = event as BattleEventData_Over; this.attackPosMap.forEach((posData, posID) => { if(posData.hero){ posData.hero.getComponent(Hero).stand() } }) this.enemyMap.forEach((enemy, enemyID) => { enemy.getComponent(Enemy).stand() }) let winStr = attackData.bWin ? "胜利" : "失败"; console.log(winStr) tween(this.node).delay(3).call(()=>{ this.enemyMap.forEach((enemy, enemyID) => { enemy.getComponent(Enemy).clearData(); this.enemyMap.delete(enemyID); this.enemyPool.push(enemy); }) // this.mapID = this.mapID %2+1; this.battleControl.reset(this.mapID) this.reset() for(let index = 0; index < this.attackPosList.length; index++){ let hero = this.attackPosList[index].hero; if(hero){ hero.position = this.attackPosList[index].pos; let heroObj = hero.getComponent(Hero) this.battleControl.addHeroInPos(heroObj.typeID,heroObj.level,index) } } }).start(); break; } } } onTouchStart(event: EventTouch) { if (this.touchStart) { this.resetHeroPos(this.touchStart) } // 获取触点对应节点 let posData = this.getItemBaseByPosition(event.getLocation()); if(posData && posData.hero){ let hero = posData.hero.getComponent(Hero); if(hero.isLock){ return; } Framework.audio.playEffect(AudioID.Click); this.touchStart = posData.hero; hero.stand() this.touchStart.setSiblingIndex(30); let index = posData.posID - this.bagPosList.length if(index >= 0){ this.battleControl.removeHeroInPos(index) } } } // 触摸移动 onTouchMove(event: EventTouch) { if (this.touchStart ) { this.touchStart .setPosition(this.roleNode.getComponent(UITransform).convertToNodeSpaceAR(new Vec3(event.getUILocation().x, event.getUILocation().y))) let posData = this.getItemBaseByPosition(event.getLocation()); if(posData&&(posData.posID >= this.bagPosList.length)){ this.radiusNode.position = v3(this.touchStart.position.x,this.touchStart.position.y); this.radiusNode.active = true; this.setRadius(this.touchStart.getComponent(Hero).radius) } else{ this.radiusNode.active = false; } } else{ this.radiusNode.active = false; } } onTouchEnd(event: EventTouch) { this.radiusNode.active = false; if (this.touchStart) { let posData = this.getItemBaseByPosition(event.getLocation()); let touchEnd:Node = null if(posData && posData.hero != this.touchStart){ if(posData.hero){ let hero = posData.hero.getComponent(Hero); if(hero && hero.isLock){ this.resetHeroPos(this.touchStart) this.touchStart = null; return; } } touchEnd = posData.hero; } else{ this.resetHeroPos(this.touchStart) this.touchStart = null; return } if(touchEnd){ let endHero = touchEnd.getComponent(Hero) let startHero = this.touchStart.getComponent(Hero) if(endHero.typeID == startHero.typeID && endHero.level == startHero.level){ this.mergeHero(this.touchStart, touchEnd) } else{ this.changeHeroPos(this.touchStart, touchEnd) } } else{ this.setHeroPos(this.touchStart, posData.posID) } this.touchStart = null; } } onTouchCancel(event: EventTouch) { this.radiusNode.active = false; if (this.touchStart) { this.resetHeroPos(this.touchStart) this.touchStart = null; } } //根据世界坐标获取item 排除手上的 private getItemBaseByPosition(pos: Vec2):PosData { let FindArr = this.bagPosList let bag = FindArr.find(t => { if(t.hero && t.hero != this.touchStart){ return t.hero.getComponent(Hero).hitTest(pos) } return t.node.getComponent(UITransform).hitTest(pos) }); if (bag ) return bag FindArr = this.attackPosList let attack = FindArr.find(t => { if(t.hero && t.hero != this.touchStart){ return t.hero.getComponent(Hero).hitTest(pos) } return t.node.getComponent(UITransform).hitTest(pos) }); return attack; } //炸弹效果播放结束 bombSpineOver() { } //UI开打时会调用,如果有初始化代码应该放到此函数 onOpen(args) { } //UI关闭时会调用,该函数在onDestroy前调用 onClose() { } //框架管理UI层级时会调用,可根据UI情况修改 onShow() { super.onShow(); } //框架管理UI层级时会调用,可根据UI情况修改 onHide() { super.onHide(); } init() { this.bStart = false; this.waitTime = 5; this.gameTime = 0; this.radiusNode.active = false; let posID = 0; let roleTransform = this.roleNode.getComponent(UITransform) let mapConf = ZombieMapConf.data[this.mapID.toString()] if(!mapConf){ console.log("地图配置错误") return } let offset = mapConf.OffsetArray if(offset){ baseOffset.x = offset[0] baseOffset.y = offset[1] } else{ baseOffset.x = 0 baseOffset.y = 0 } let path = "texture/tower/"+mapConf.Background+"/spriteFrame" this.load("package",path, SpriteFrame, (res: SpriteFrame) => { this.mapSprite.spriteFrame = res }) let bagChildren = this.bagNode.children for (let i = 0; i < 10; i++) { let node = bagChildren[i]; let pos = roleTransform.convertToNodeSpaceAR(node.getWorldPosition()) let posData: PosData = { node: node, hero: null, bLock: false, posID: posID, pos: pos, posNumber: -1 } this.bagPosList.push(posData); posID++; } let attackChildren = this.attackNode.children for (let i = 0; i < attackChildren.length; i++) { let node = attackChildren[i]; let posNumber = this.battleControl.getPosIDByIndex(i) if(posNumber != -1){ node.active = true; let mapDataPos = this.battleControl.getPosition(posNumber) let posXX = MapDataPosToView(mapDataPos.x,mapDataPos.y) node.position = posXX let posData: PosData = { node: node, hero: null, bLock: false, posID: posID, pos: new Vec3(posXX.x, posXX.y, 0), posNumber: posNumber } this.attackPosList.push(posData); this.attackPosMap.set(posNumber, posData); posID++; } else { node.active = false; } } } reset(){ let mapConf = ZombieMapConf.data[this.mapID.toString()] if(!mapConf){ console.log("地图配置错误") return } let offset = mapConf.OffsetArray if(offset){ baseOffset.x = offset[0] baseOffset.y = offset[1] } else{ baseOffset.x = 0 baseOffset.y = 0 } let attackChildren = this.attackNode.children for (let i = 0; i < attackChildren.length; i++) { let node = attackChildren[i]; let posNumber = this.battleControl.getPosIDByIndex(i) if(posNumber != -1){ node.active = true; let mapDataPos = this.battleControl.getPosition(posNumber) let posXX = MapDataPosToView(mapDataPos.x,mapDataPos.y) node.position = posXX let posData: PosData = this.attackPosList[i] if(!posData){ posData = { node: node, hero: null, bLock: false, posID: this.bagPosList.length+i, pos: new Vec3(posXX.x, posXX.y, 0), posNumber: posNumber } this.attackPosList.push(posData); } else{ posData.posID = this.bagPosList.length+i; posData.pos = new Vec3(posXX.x, posXX.y, 0); posData.posNumber = posNumber; if(posData.hero){ posData.hero.position = posData.pos; } } this.attackPosMap.set(posNumber, posData); } else { node.active = false; } } let path = "texture/tower/"+mapConf.Background+"/spriteFrame" this.load("package",path, SpriteFrame, (res: SpriteFrame) => { this.mapSprite.spriteFrame = res }) this.bStart = false; this.waitTime = 5; this.gameTime = 0; this.radiusNode.active = false; } private initPool() { //初始化池 let queue = new AsyncQueue(); queue.pushMulti("InitPool", async (next: NextFunction, params: any, args: any) => { Framework.tips.setTipsNode("package", "prefab/ui/tips/tips_flash", "Label", () => { next && next(); }); }); queue.complete = () => { //this._loginEx(); }; queue.play(); //this._loginEx(); } addHero() { let posID = -1; for (let i = 0; i < this.bagPosList.length; i++) { if(this.bagPosList[i].hero == null){ posID = this.bagPosList[i].posID; break; } } if(posID == -1) { console.log("没有空位了"); return; } //添加英雄 let heroID = Math.floor(Math.random() * this.heroModelList.length)%this.heroModelList.length + 1; let heroData = ZombieHeroDataPool.getObject(); heroData.init(heroID,1,posID) let node:Node = null; if(this.heroPool[heroID] == null){ this.heroPool[heroID] = []; } else { if(this.heroPool[heroID].length > 0){ node = this.heroPool[heroID].pop(); } } if(node == null){ node = instantiate(this.heroModelList[heroID-1]); node.parent = this.roleNode; this.heroList.push(node); } let hero = node.getComponent(Hero); hero.resetData(heroData); //用完就还 ZombieHeroDataPool.putObject(heroData); hero.posIndex = posID; let posData = this.bagPosList[posID]; if(!posData){ return; } posData.hero = node; node.position = posData.pos; console.log("添加英雄", node.position); this.checkMerge(node); } checkMerge(node:Node) { let hero = node.getComponent(Hero); if(!hero) { return; } let bFind = false; if(this.isAutoMerge && !hero.isLock && hero.posIndex < this.bagPosList.length){ for (let i = 0; i < this.attackPosList.length; i++) { let dstPosData = this.attackPosList[i]; if(dstPosData.hero != null && dstPosData.hero != node){ let dstHero = dstPosData.hero.getComponent(Hero); if((!dstHero.isLock) && dstHero.typeID == hero.typeID && dstHero.level == hero.level){ if(this.mergeHero(node, dstPosData.hero)){ bFind = true; break; } } } } if(!bFind){ for (let i = 0; i < this.bagPosList.length; i++) { let dstPosData = this.bagPosList[i]; if(dstPosData.hero != null && dstPosData.hero != node){ let dstHero = dstPosData.hero.getComponent(Hero); if((!dstHero.isLock) && dstHero.typeID == hero.typeID && dstHero.level == hero.level){ if(this.mergeHero(node, dstPosData.hero)) break; } } } } } } //合并英雄 mergeHero(srcNode:Node, dstNode:Node) { let dstHero = dstNode.getComponent(Hero); if(dstHero.isLock){ return false; } dstHero.isLock = true; // srcNode.setSiblingIndex(this.bagPosList.length+this.attackPosList.length) srcNode.getComponent(Hero).flyTo(dstNode.position,()=>{ if(isValid(dstHero)){ dstHero.isLock = false; dstHero.levelUp() if(dstHero.posIndex >= this.bagPosList.length){ let index = dstHero.posIndex - this.bagPosList.length; this.battleControl.levelUp(index) } this.levelUpEffectIndex = this.levelUpEffectIndex++%this.levelUpEffect.length; this.levelUpEffect[this.levelUpEffectIndex].position = dstNode.position this.levelUpEffect[this.levelUpEffectIndex].active = true this.levelUpEffect[this.levelUpEffectIndex].getComponent(sp.Skeleton).setAnimation(0, "animation", false) this.removeHeroPos(srcNode) this.checkMerge(dstNode) } }) return true; } addEnemy(eventData: BattleEventData_EnemyBorn) { //添加敌人 let node:Node = null; if(this.enemyPool.length > 0){ node = this.enemyPool.pop(); } else { node = instantiate(this.ememyModelList[0]); node.parent = this.roleNode; } node.setSiblingIndex(0) node.getComponent(Enemy).resetData(eventData.typeID,eventData.ID,MapDataPosToView(eventData.position.x,eventData.position.y),eventData.life,eventData.lifeMax) node.getComponent(Enemy).startMove("move1") this.enemyMap.set(eventData.ID,node); } onClickStart() { this.bStart = true; } onClickStop() { this.bStart = false; } onClickAddHero() { Framework.audio.playEffect(AudioID.Click); this.addHero(); } //重置坐标 resetHeroPos(heroNode:Node) { let hero = heroNode.getComponent(Hero) if(!hero) { return; } let posID = hero.posIndex; if(posID != -1){ if(posID < this.bagPosList.length) heroNode.position = this.bagPosList[posID].pos; else if(posID < this.bagPosList.length + this.attackPosList.length){ heroNode.position = this.attackPosList[posID - this.bagPosList.length].pos; this.battleControl.addHeroInPos(hero.typeID,hero.level,posID - this.bagPosList.length) } } } //设置新坐标 setHeroPos(hero:Node,newPosID:number) { let posID = hero.getComponent(Hero).posIndex; if(posID != -1){ if(posID < this.bagPosList.length) this.bagPosList[posID].hero = null; else if(posID < this.bagPosList.length + this.attackPosList.length){ this.attackPosList[posID - this.bagPosList.length].hero = null; } } if(newPosID != -1){ if(newPosID < this.bagPosList.length){ this.bagPosList[newPosID].hero = hero; hero.position = this.bagPosList[newPosID].pos; } else if(newPosID < this.bagPosList.length + this.attackPosList.length){ let index = newPosID - this.bagPosList.length; this.attackPosList[index].hero = hero; hero.position = this.attackPosList[index].pos; let heroObj = hero.getComponent(Hero) this.battleControl.addHeroInPos(heroObj.typeID,heroObj.level,index) } hero.getComponent(Hero).posIndex = newPosID } } removeHeroPos(hero:Node) { let posID = hero.getComponent(Hero).posIndex; if(posID != -1){ this.heroList.splice(this.heroList.indexOf(hero), 1) this.heroPool[hero.getComponent(Hero).typeID].push(hero) hero.getComponent(Hero).clearData(); if(posID < this.bagPosList.length) this.bagPosList[posID].hero = null; else if(posID < this.bagPosList.length + this.attackPosList.length){ this.attackPosList[posID - this.bagPosList.length].hero = null; this.battleControl.removeHeroInPos(posID - this.bagPosList.length) } } } changeHeroPos(hero1:Node,hero2:Node) { let posID1 = hero1.getComponent(Hero).posIndex; let posID2 = hero2.getComponent(Hero).posIndex; hero1.getComponent(Hero).posIndex = posID2 hero2.getComponent(Hero).posIndex = posID1 if(posID1 != -1){ if(posID1 < this.bagPosList.length){ hero2.position = this.bagPosList[posID1].pos; this.bagPosList[posID1].hero = hero2; } else if(posID1 < this.bagPosList.length + this.attackPosList.length){ hero2.position = this.attackPosList[posID1 - this.bagPosList.length].pos; let index = posID1 - this.bagPosList.length; this.attackPosList[index].hero = hero2; let heroObj = hero2.getComponent(Hero) this.battleControl.addHeroInPos(heroObj.typeID,heroObj.level,index) } hero2.getComponent(Hero).stand() } if(posID2 != -1){ if(posID2 < this.bagPosList.length){ hero1.position = this.bagPosList[posID2].pos; this.bagPosList[posID2].hero = hero1; } else if(posID2 < this.bagPosList.length + this.attackPosList.length){ hero1.position = this.attackPosList[posID2 - this.bagPosList.length].pos; let index = posID2 - this.bagPosList.length; this.attackPosList[index].hero = hero1; let heroObj = hero1.getComponent(Hero) this.battleControl.addHeroInPos(heroObj.typeID,heroObj.level,index) } hero1.getComponent(Hero).stand() } } addHurt(pos:Vec3,value:number){ let node:Node = null; if(this.hurtPool.length > 0){ node = this.hurtPool.pop(); } else { node = instantiate(this.hurtModelList[0]); node.parent = this.roleNode; } node.position = pos; this.hurtList.push(node); node.getComponent(Hurt).hurt(value,()=>{ this.hurtList.splice(this.hurtList.indexOf(node), 1) this.hurtPool.push(node) }) } updateSiblingIndex() { let children = this.roleNode.children children.sort((a, b) => { let battleNodeA = a.getComponent(BattleNodeBase); let battleNodeB = b.getComponent(BattleNodeBase); if (!battleNodeA || !battleNodeB) { return 0; } let priorityA = battleNodeA.priority let priorityB = battleNodeB.priority if (priorityA != priorityB) { return priorityA - priorityB; } if(this.touchStart == b){ return -1; } if(this.touchStart == a){ return 1; } //特殊状态 if(battleNodeB.isLock){ return -1; } if(battleNodeA.isLock){ return 1; } if (a.position.y != b.position.y) { return b.position.y - a.position.y; } else { a.position.x - b.position.x } }); for (let i = 0; i < children.length; i++) { children[i].setSiblingIndex(i); } } setRadius(radius:number){ this.radiusNode.scale = v3(0.4*radius,0.4*radius,1) } }