import { SaveDataManager } from "../../component/SaveDataManager"; import { tMgr, WindowName } from "../../Global"; import Ball from "../../prefabs/Ball"; import { UIManager } from "../../ui/UIManager"; import { UITitleData } from "../../ui/uiView/UITitleData"; import GlobalNode from "../GlobalNode"; import { PhysicsControl } from "../physics/PhysicsControl"; import { GamePlayTable, TableName } from "../table/TableDefine"; import { BattleEvent, getGlobalNode, UserSkill } from "./BattleConst"; import { BattleManager } from "./BattleManager"; import { BattleProfit } from "./BattleProfit"; import { IUpdate } from "./inter/IUpdate"; import { MapData } from "./map/MapData"; import { MapManager } from "./map/MapManager"; import { MapUtil } from "./map/MapUtil"; import { MapView } from "./map/MapView"; import { ObjData } from "./map/ObjData"; import { UserSkillBomb } from "./userSkill/UserSkillBomb"; import { UserSkillDoubleShoot } from "./userSkill/UserSkillDoubleShoot"; import { UserSkillShield } from "./userSkill/UserSkillShield"; import { UserSkillShuriken } from "./userSkill/UserSkillShuriken"; /**单局战斗数据模型 */ export class Battle { private _mapView: MapView; get mapView(): MapView { return this._mapView; } private _mapData: MapData; get mapData(): MapData { return this._mapData; } private _callBack: Function; private _callBackThisObj: any; private _marblesBornPos: cc.Vec2; get marblesBornPos(): cc.Vec2 { return this._marblesBornPos; } private _marblesBornPosNextRound: cc.Vec2 = cc.v2(); get marblesBornPosNextRound(): cc.Vec2 { return this._marblesBornPosNextRound; } private _round: number = 0; /**回合数,开始射击时 +1 */ get round(): number { return this._round; } private _roundRunning: boolean = false; get roundRunning(): boolean { return this._roundRunning; } private _roundLastTime: number = 0; private _marblesNum: number = 50; get marblesNum(): number { return this._marblesNum; } private _marblesToShoot: number = 0; /**已发射的弹球 */ private _marblesCount = 0; private _marblesCollectCount: number = 0; /**已收集的弹球 */ get marblesCollectCount(): number { return this._marblesCollectCount; } private _shootVec: cc.Vec2 = cc.v2(); private _shootInterval: number = 0; private _shootIntervalCount: number = 0; private _profit: BattleProfit; /**战斗收益 */ get profit(): BattleProfit { return this._profit; } private _marblesPool: cc.Node[] = []; private _prefabCollection: cc.Node; get prefabCollection(): cc.Node { return this._prefabCollection; } private _roundClearList: ObjData[] = []; /**彩虹护盾次数 */ shieldCount: number = 0; /**地图缩放值 */ scale: number = 1; doubleShoot: boolean = false; private _levelId: number = 0; get levelId(): number { return this._levelId; } private _speedUp: boolean = false; get speedUp(): boolean { return this._speedUp; } /**复活次数 */ reviveCount: number = 0; bigBombTriggered: boolean = false; private _collecting: boolean = false; private _updateObj: IUpdate[] = []; private _updateObjToRemoved: IUpdate[] = []; //#region public method init(levelId: number, callBack: Function, thisObj: any, prefab: cc.Prefab) { /** * Project Marbles * Date: 2022.4 * * Programme made by Sean * Art by Qin Wu, Yan Fan, Weirui Yu * * Some other morons are included, these morons do not care about quailty of game, we paid lots of works, and they did not make any progress, totally useless crap. */ this._levelId = levelId; this._profit = new BattleProfit(this); this._callBack = callBack; this._callBackThisObj = thisObj; // this._blockPrefab = blockPrefab; // this._ballPrefab = ballPrefab; this._prefabCollection = cc.instantiate(prefab); let config = tMgr.getConfig(TableName.GAME_PLAY, 2) as GamePlayTable; //发射弹球频率 this._shootInterval = config.Value; config = tMgr.getConfig(TableName.GAME_PLAY, levelId == 1 ? 7 : 8) as GamePlayTable;//弹球数量 this._marblesNum = config.Value + (UITitleData.isBattleBonus ? 10 : 0); if (this._levelId == 0) { MapManager.ins.loadMap('test1', this.onMapLoadFinish, this); } else { MapManager.ins.loadMap('map-' + levelId.toString(), this.onMapLoadFinish, this); } } update(dt: number) { if (this._roundRunning) { this._roundLastTime += dt; //加速控制 if (this._roundLastTime > (tMgr.getConfig(TableName.GAME_PLAY, 4) as GamePlayTable).Value && PhysicsControl.TIME_SCALE != (tMgr.getConfig(TableName.GAME_PLAY, 5) as GamePlayTable).Value) { this._speedUp = true; PhysicsControl.ins.setTimeScale((tMgr.getConfig(TableName.GAME_PLAY, 5) as GamePlayTable).Value); } } if (this._marblesToShoot > 0) { this._shootIntervalCount += dt; if (this._shootIntervalCount >= this._shootInterval) { // this._shootIntervalCount -= this._shootInterval; this._shootIntervalCount = 0; //直接重置为0,使小球间隔更均匀,但是时间上不够准确 this.shootMarbles(); } } if (this._updateObjToRemoved.length > 0) { for (let i = 0; i < this._updateObjToRemoved.length; ++i) { let index = this._updateObj.indexOf(this._updateObjToRemoved[i]); if (index > -1) { this._updateObj.splice(index, 1); } } } this._updateObjToRemoved.length = 0; if (this._updateObj.length > 0) { for (let i = 0; i < this._updateObj.length; ++i) { this._updateObj[i].onUpdate(dt); } } PhysicsControl.ins.update(dt); } regUpdateObj(obj: IUpdate) { if (!this._updateObj.includes(obj)) { this._updateObj.push(obj); } } unregUpdateObj(obj: IUpdate) { if (!this._updateObjToRemoved.includes(obj)) { this._updateObjToRemoved.push(obj); } } destroy() { this._updateObj.length = 0; this._updateObjToRemoved.length = 0; PhysicsControl.ins.setPhysicsEnable(false); } shoot(dir: cc.Vec2) { if (!this._roundRunning) { BattleManager.ins.shootTouchEnable = false; this._shootIntervalCount = 0; PhysicsControl.ins.setPhysicsEnable(true); PhysicsControl.ins.setTimeScale(1); this._marblesToShoot = this._marblesNum * (this.doubleShoot ? 2 : 1); this._shootVec.set(dir); this._shootVec.normalizeSelf(); let speed = this.getPhysiceBallSpeed(); this._shootVec.multiplyScalar(speed); this._doubleShootVec.set(this._shootVec); this._doubleShootVec.x = -this._doubleShootVec.x; this.onRoundStart(); } } private _ballTargetCache: cc.Vec3 = cc.v3(); marblesCollected(collisonWorldPoint: cc.Vec2, ballNode: cc.Node) { if (this.shieldCount > 0) { this.shieldCount--; if (this.shieldCount == 0) { BattleManager.ins.eventNode.emit(BattleEvent.SKILL_END, UserSkill.SHIELD); } return; } if (this._marblesCollectCount == 0) { ++this._marblesCollectCount; this._mapView.convertToNodeSpaceAR(collisonWorldPoint, this._marblesBornPosNextRound); // this._marblesBornPosNextRound.y += 15; this._marblesBornPosNextRound.y = -this._mapView.height / 2 + 15; this._ballTargetCache.x = this._marblesBornPosNextRound.x; this._ballTargetCache.y = this._marblesBornPosNextRound.y; BattleManager.ins.eventNode.emit(BattleEvent.BORN_POS_CHANGE); ballNode.active = false; } else { this.doCollect(ballNode); } } collectAll() { if (!this._collecting && this.roundRunning) { this._collecting = true; this._marblesToShoot = 0; let count: number = 0; for (let i = 0; i < this._marblesPool.length; ++i) { if (this._marblesPool[i].active && !this._marblesPool[i].getComponent(Ball).collecting) { this.doCollect(this._marblesPool[i]); count++; } } // console.log('collected', count); // if (count == 0) { if (count == 0 && this._marblesCollectCount == this._marblesCount) { //球都收完了 // console.log('收完了'); this.onRoundFinish(); } } // roundFinish && this.roundFinish(); } /**结算战斗 */ finishBattle(win: boolean, delay: boolean = true) { this._marblesToShoot = 0; win && (this._profit.star = MapUtil.getStarRate(this._mapData)); if (win && this._levelId > SaveDataManager.ins.runtimeData.curLevel) { SaveDataManager.ins.runtimeData.curLevel = this._levelId; SaveDataManager.ins.saveData(); } if (delay) { getGlobalNode().getComponent(GlobalNode).scheduleOnce(() => { UIManager.ins.openWindow(win ? WindowName.BATTLE_RESULT_PRE_ANI : WindowName.BATTLE_RESULT, win); }, 1); } else { UIManager.ins.openWindow(win ? WindowName.BATTLE_RESULT_PRE_ANI : WindowName.BATTLE_RESULT, win); } } addMarbles(num: number) { this._marblesNum += num; } addToRoundClear(target: ObjData): void { if (this._roundClearList.indexOf(target) == -1) { this._roundClearList.push(target); } } useSkill(skillId: UserSkill, free: boolean = false) { if (skillId == UserSkill.BOMB) { new UserSkillBomb(this, skillId).start(free); } else if (skillId == UserSkill.SHURIKEN) { new UserSkillShuriken(this).start(free); } else if (skillId == UserSkill.SHIELD) { new UserSkillShield(this, skillId).start(free); } else if (skillId == UserSkill.DOUBLE_SHOOT) { new UserSkillDoubleShoot(this, skillId).start(free); } } /**获取小球在物理引擎中的速度,将地图的缩放计算在内 */ getPhysiceBallSpeed(): number { return (tMgr.getConfig(TableName.GAME_PLAY, 3) as GamePlayTable).Value * this.scale; } //#endregion //#region event onBlockDead(combo: number) { BattleManager.ins.eventNode.emit(BattleEvent.BLOCK_COMBO, combo); if (this._mapData.blockData.size == 0) { // this.finishBattle(true); if (this.bigBombTriggered) { this.onRoundFinish(); } else { if (this.roundRunning) { this.collectAll(); } else { //非回合中,使用道具消除了砖块 this.onRoundFinish(); } } } } onObjDead() { } private onMarblesCollectedFinish() { ++this._marblesCollectCount; if (!this.bigBombTriggered) { // if (this.doubleShoot) { // if (this._marblesCollectCount == this._marblesNum * 2) { // this.onRoundFinish(); // } // } // else { // if (this._marblesCollectCount == this._marblesNum) { // this.onRoundFinish(); // } // } if (this._marblesCollectCount == this._marblesCount) { // console.log('自己收完了'); this.onRoundFinish(); } } } private onRoundStart() { this._roundRunning = true; this._roundLastTime = 0; this._marblesCount = 0; this._marblesCollectCount = 0; BattleManager.ins.eventNode.emit(BattleEvent.ROUND_START); } private onRoundFinish() { this._round++; this._roundRunning = false; this._speedUp = false; this._collecting = false; this._mapData.roundFinish(); this.doubleShoot && (this.doubleShoot = false); for (let i = 0; i < this._roundClearList.length; ++i) { this._roundClearList[i].dead(); } this._roundClearList.length = 0; this._profit.roundFinish(); this._marblesBornPos.set(this._marblesBornPosNextRound); PhysicsControl.ins.setTimeScale(1); PhysicsControl.ins.setPhysicsEnable(false); let lose = this._mapData.slideDown(); BattleManager.ins.eventNode.emit(BattleEvent.ROUND_END); if (lose) { // this.finishBattle(false); UIManager.ins.openWindow(WindowName.REVIVE); } else { if (this._mapData.blockData.size == 0) { this.finishBattle(true); // this.collectAll(true); } else { BattleManager.ins.shootTouchEnable = true; } } } //#endregion //#region private method private onMapLoadFinish(data: MapData) { this._mapData = data; this._mapData.battle = this; this._mapView = MapManager.ins.renderMap(data, this._prefabCollection); //弹球出生点 this._marblesBornPos = cc.v2(0, -this._mapView.height / 2 + 15); this._marblesBornPosNextRound.set(this._marblesBornPos); this._ballTargetCache.x = this._marblesBornPos.x; this._ballTargetCache.y = this._marblesBornPos.y; for (let i = 0; i < this._marblesNum; ++i) { this._marblesPool.push(this.makeMarbleNode()); } this._mapData.battleStart(); this._callBack.call(this._callBackThisObj); } private _doubleShootVec: cc.Vec2 = cc.v2(); private shootMarbles() { if (this._marblesToShoot > 0) { let marbles: cc.Node; if (this._marblesCount < this._marblesPool.length) { marbles = this._marblesPool[this._marblesCount]; } else { marbles = this.makeMarbleNode(); this._marblesPool.push(marbles); } marbles.setPosition(this.marblesBornPos); if (this.doubleShoot) { if (this._marblesCount % 2 == 0) { marbles.getComponent(cc.RigidBody).linearVelocity = this._shootVec; } else { marbles.getComponent(cc.RigidBody).linearVelocity = this._doubleShootVec; } } else { marbles.getComponent(cc.RigidBody).linearVelocity = this._shootVec; } !marbles.parent && this._mapView.ballLayer.addChild(marbles); marbles.active = true; this._marblesCount++; this._marblesToShoot--; } } private makeMarbleNode(): cc.Node { let ball = cc.instantiate(this._prefabCollection.getChildByName('ball')); ball.setPosition(this.marblesBornPos); ball.getComponent(cc.RigidBody).linearVelocity.x = 0; ball.getComponent(cc.RigidBody).linearVelocity.y = 0; ball.active = false; return ball } private doCollect(ballNode: cc.Node) { ballNode.getComponent(Ball).collecting = true; ballNode.getComponent(cc.PhysicsCollider).enabled = false; ballNode.getComponent(cc.RigidBody).linearVelocity = cc.Vec2.ZERO; let dis = cc.Vec3.distance(ballNode.position, this._ballTargetCache); let time = dis / (tMgr.getConfig(TableName.GAME_PLAY, 3) as GamePlayTable).Value; if (time <= 0.02) { this.finishCollect(ballNode); } else { // PhysicsControl.ins.setTimeScale((tMgr.getConfig(TableName.GAME_PLAY, 5) as GamePlayTable).Value); this._speedUp && (time = time / (tMgr.getConfig(TableName.GAME_PLAY, 5) as GamePlayTable).Value); cc.tween(ballNode).to(time, { position: this._ballTargetCache }).call(this.finishCollect.bind(this)).start(); } } private finishCollect(ballNode: cc.Node) { ballNode.active = false; ballNode.getComponent(cc.PhysicsCollider).enabled = true; // ballNode.getComponent(cc.RigidBody).enabled = true; ballNode.getComponent(Ball).collecting = false; BattleManager.ins.curBattle.onMarblesCollectedFinish(); } //#endregion }