import { _decorator, Component, Input, input, instantiate, KeyCode, macro, math, Node, Prefab, Sprite, UITransform, v3, Vec3 } from 'cc'; import { GameMgr } from '../manager/GameMgr'; import { ArrayUtil } from '../util/ArrayUtil'; import { ShelveType } from '../enum/ShelveType'; import { ShelveLocker } from './ShelveLocker'; import { ShelveBase } from '../scriptBase/ShelveBase'; import { CommonShelve } from './CommonShelve'; import { SmallShelve } from './SmallShelve'; import { UIMgr } from '../manager/UIMgr'; import { UI } from '../enum/UI'; import { PREVIEW } from 'cc/env'; import { Mode, ModeName } from '../enum/Mode'; import { cfg_level_gs, cfg_level_ls, cfg_level_tp } from '../config/cfg_level'; import { DtoLevelCfg } from '../dto/DtoLevelCfg'; import { DtoLevelData } from '../dto/DtoLevelData'; import { cfg_icon_gs, cfg_icon_ls, cfg_icon_tp } from '../config/cfg_icon'; import { DtoIconCfg } from '../dto/DtoIconCfg'; import { ResMgr } from '../manager/ResMgr'; import { Bundle } from '../enum/Bundle'; import { Global } from '../Global'; import { EventMgr } from '../manager/EventMgr'; import { EventType } from '../enum/EventType'; import { CoinMgr } from '../manager/CoinMgr'; import { ComboBox } from './ComboBox'; import { Goods } from './Goods'; import { AudioMgr } from '../manager/AudioMgr'; const { ccclass, property } = _decorator; @ccclass('Game/Stage') export class Stage extends Component { @property(Sprite) private bg: Sprite = null @property(Node) private shelveBox: Node = null @property(ComboBox) private comboBox: ComboBox = null @property(Node) private tip: Node = null @property(Prefab) private shelveLockerPre: Prefab = null @property(Prefab) private shelvePreArr: Prefab[] = [] private levelCfg: DtoLevelCfg = null private levelData: DtoLevelData = null private iconCfg: DtoIconCfg = null private shelveArr: ShelveBase[] = [] private doubleCoin: boolean = false private isBusy: boolean = false protected onLoad(): void { const bgName: string = 'bg_' + ModeName[GameMgr.mode] this.bg.spriteFrame = ResMgr.getSpriteFrame(Bundle.Game, bgName, 'image/') EventMgr.on(EventType.MergeGoods, this.onMergeGoods, this) EventMgr.on(EventType.TimeOut, this.onTimeOut, this) EventMgr.on(EventType.TimeOutAlert, this.onTimeOutAlert, this) EventMgr.on(EventType.UseSkillFreezeTime, this.onUseSkillFreezeTime, this) EventMgr.on(EventType.UseSkillDoubleCoin, this.onUseDoubleCoin, this) EventMgr.on(EventType.UseSkillRefreshPosition, this.onUseRefreshPos, this) EventMgr.on(EventType.UseSkillEraseGroup, this.onUseEraseGroup, this) if (PREVIEW) { input.on(Input.EventType.KEY_DOWN, (e) => { if (e.keyCode !== KeyCode.KEY_Q) return if (GameMgr.Pause) return UIMgr.open(UI.Win) }, this) } } protected onDestroy(): void { UIMgr.close(UI.Game) this.unscheduleAllCallbacks() EventMgr.off(EventType.MergeGoods, this.onMergeGoods, this) EventMgr.off(EventType.TimeOut, this.onTimeOut, this) EventMgr.off(EventType.TimeOutAlert, this.onTimeOutAlert, this) EventMgr.off(EventType.UseSkillFreezeTime, this.onUseSkillFreezeTime, this) EventMgr.off(EventType.UseSkillDoubleCoin, this.onUseDoubleCoin, this) EventMgr.off(EventType.UseSkillRefreshPosition, this.onUseRefreshPos, this) EventMgr.off(EventType.UseSkillEraseGroup, this.onUseEraseGroup, this) } protected start() { UIMgr.open(UI.Game) this.tip.active = GameMgr.mode === Mode.tp && GameMgr.CurLevel === 0 this.scheduleOnce(() => { //Difficulty increase 难度飙升 if (GameMgr.isHardLevel) UIMgr.open(UI.StageTip, 'Difficulty increase') }, 1) switch (GameMgr.mode) { case Mode.tp: this.levelCfg = cfg_level_tp this.iconCfg = cfg_icon_tp break; case Mode.gs: this.levelCfg = cfg_level_gs this.iconCfg = cfg_icon_gs break case Mode.ls: this.levelCfg = cfg_level_ls this.iconCfg = cfg_icon_ls break } if (GameMgr.CurLevel >= this.levelCfg.length) { this.levelData = ArrayUtil.pickItem(this.levelCfg) } else { this.levelData = this.levelCfg[GameMgr.CurLevel] } const shelveMap: number[][] = this.levelData.shelveMap const group: number = this.levelData.group const lockCnt: number = this.levelData.lockCnt const goodsTypeCnt: number = this.levelData.GoodsTypeCnt Global.Level_Time = this.levelData.time // Global.Level_Time = 10 EventMgr.emit(EventType.TimeReset) this.createShelves(shelveMap) this.createShelveLockers(lockCnt) this.createGoodsArr(group, goodsTypeCnt) this.createGoodsData() this.schedule(this.onCheckWin, 0.5, macro.REPEAT_FOREVER) } private createShelves(shelveMap: number[][]): void { const row: number = shelveMap.length const col: number = shelveMap[0].length const uiTrans: UITransform = this.shelveBox.getComponent(UITransform) const spaceX: number = 0 const spaceY: number = 0 uiTrans.width = col * 230 + spaceX * (col - 1) uiTrans.height = row * 145 + spaceY * (row - 1) for (let i = 0; i < shelveMap.length; i++) { for (let j = 0; j < shelveMap[i].length; j++) { const type: ShelveType = shelveMap[i][j] const shelvePre: Prefab = this.shelvePreArr[type] const shelveNode: Node = instantiate(shelvePre) this.shelveBox.addChild(shelveNode) } } this.shelveArr = this.shelveBox.getComponentsInChildren(ShelveBase) } private createShelveLockers(lockCnt: number): void { if (lockCnt <= 0) return const shelves: ShelveBase[] = ArrayUtil.pickItems(this.shelveArr, lockCnt, true) for (let i = 0; i < shelves.length; i++) { const shelve: ShelveBase = shelves[i]; const shelveLockerNode: Node = instantiate(this.shelveLockerPre) shelve.node.addChild(shelveLockerNode) const shelveLocker: ShelveLocker = shelveLockerNode.getComponent(ShelveLocker) shelveLocker.UnlockCnt = math.randomRangeInt(3, 6) } } private createGoodsArr(group: number, goodsTypeCnt: number): void { const idxArr: number[] = ArrayUtil.pickIndexs(this.iconCfg, goodsTypeCnt, true) GameMgr.goodsArr = [] for (let i = 0; i < group; i++) { const goodsId: number = ArrayUtil.pickItem(idxArr) + 1 GameMgr.goodsArr.push(goodsId, goodsId, goodsId) } ArrayUtil.shuffle(GameMgr.goodsArr) } private createGoodsData(): void { const commonShelveArr: CommonShelve[] = [] const smallShelveArr: SmallShelve[] = [] for (let i = 0; i < this.shelveArr.length; i++) { const shelve: ShelveBase = this.shelveArr[i]; if (shelve instanceof CommonShelve) { commonShelveArr.push(shelve) } else if (shelve instanceof SmallShelve) { smallShelveArr.push(shelve) } } //先悬浮格子 for (let i = 0; i < smallShelveArr.length; i++) { const smallShelve: SmallShelve = smallShelveArr[i]; const smallShelveId: number = smallShelve.Id if (!GameMgr.goodsData.hasOwnProperty(smallShelveId)) { GameMgr.goodsData[smallShelveId] = { 0: [], } } // const cnt: number = math.randomRangeInt(2, 4) for (let j = 0; j < 3; j++) { const goodsId: number = GameMgr.goodsArr.shift() GameMgr.goodsData[smallShelveId][0].push(goodsId) } } const placeCnt: number = commonShelveArr.length * 3 while (GameMgr.goodsArr.length > 0) { //筛选槽位 const placeArr: number[] = [] for (let i = 0; i < placeCnt; i++) { placeArr.push(i) } ArrayUtil.shuffle(placeArr) if (placeCnt <= 6) { placeArr.splice(0, math.randomRangeInt(2, 3)) } else { placeArr.splice(0, math.randomRangeInt(4, 6)) } for (let i = 0; i < placeCnt; i++) { const placeId: number = i const commonShelveId: number = commonShelveArr[Math.floor(placeId / 3)].Id const slotId: number = placeId % 3 if (!GameMgr.goodsData.hasOwnProperty(commonShelveId)) { GameMgr.goodsData[commonShelveId] = { 0: [], 1: [], 2: [], } } let goodsId: number = -1 if (GameMgr.goodsArr.length <= 0 || !placeArr.includes(placeId)) goodsId = -1 else goodsId = GameMgr.goodsArr.shift() GameMgr.goodsData[commonShelveId][slotId].push(goodsId) } } } private onCheckWin(): void { const isWin: boolean = this.checkWin() if (!isWin) return if (this.isBusy) return this.unscheduleAllCallbacks() UIMgr.open(UI.Win) } private checkWin(): boolean { for (let i = 0; i < this.shelveArr.length; i++) { const shelve: ShelveBase = this.shelveArr[i]; if (!shelve.isEmpty) return false } return true } private onTimeOut(): void { const isWin: boolean = this.checkWin() if (isWin) return UIMgr.open(UI.TimeOut) } private onTimeOutAlert(): void { const effectRedAlertPre: Prefab = ResMgr.getRes(Bundle.Game, 'EffectRedAlert') const effectRedAlertNode: Node = instantiate(effectRedAlertPre) this.node.addChild(effectRedAlertNode) } private onUseSkillFreezeTime(): void { const effectFreezePre: Prefab = ResMgr.getRes(Bundle.Game, 'EffectFreeze') const effectFreezeNode: Node = instantiate(effectFreezePre) this.node.addChild(effectFreezeNode) } private onMergeGoods(shelveWorldPos: Vec3): void { this.comboBox.CurCombo++ AudioMgr.playSfx(`bomb_${this.comboBox.CurCombo}`) CoinMgr.CurCoin += this.doubleCoin ? this.comboBox.CurCombo * 2 : this.comboBox.CurCombo this.comboBox.createFloatText(shelveWorldPos) } private onUseDoubleCoin(): void { AudioMgr.playSfx('星星道具') this.doubleCoin = true this.scheduleOnce(this.onAfterDoubleCoin, Global.Double_Coin_Duration) } private onAfterDoubleCoin(): void { this.doubleCoin = false } private onUseRefreshPos(): void { AudioMgr.playSfx('转换道具') for (let i = 0; i < this.shelveArr.length; i++) { const shelve: ShelveBase = this.shelveArr[i] const goodsIdArr: number[] = shelve.GoodsIdArr for (let j = 0; j < goodsIdArr.length; j++) { const goodsId: number = goodsIdArr[j]; GameMgr.goodsArr.push(goodsId) } } ArrayUtil.shuffle(GameMgr.goodsArr) this.createGoodsData() for (let i = 0; i < this.shelveArr.length; i++) { const shelve: ShelveBase = this.shelveArr[i] shelve.clear() this.scheduleOnce(() => { shelve.init() }) } this.isBusy = true this.scheduleOnce(() => { this.isBusy = false }, 0.5) } private onUseEraseGroup(): void { AudioMgr.playSfx('灯泡道具') //先统计场上的物品 const goodsMap = {} for (let i = 0; i < this.shelveArr.length; i++) { const shelve: ShelveBase = this.shelveArr[i]; const info: Object = shelve.GoodsInfo for (const layer in info) { if (Object.prototype.hasOwnProperty.call(info, layer)) { for (const slot in info[layer]) { if (Object.prototype.hasOwnProperty.call(info[layer], slot)) { const goods: Goods = info[layer][slot]; const goodsId: number = goods.Id if (!goodsMap.hasOwnProperty(goodsId)) { goodsMap[goodsId] = [] } goodsMap[goodsId].push(goods) } } } } for (const goodsId in goodsMap) { if (Object.prototype.hasOwnProperty.call(goodsMap, goodsId)) { ArrayUtil.shuffle(goodsMap[goodsId]) } } } //筛选出超过三个的物品 const map2 = {} for (const goodsId in goodsMap) { if (Object.prototype.hasOwnProperty.call(goodsMap, goodsId)) { if (goodsMap[goodsId].length >= 3) { map2[goodsId] = goodsMap[goodsId] } } } //从中挑选三组 const map3 = {} let cnt: number = 0 for (const goodsId in map2) { if (Object.prototype.hasOwnProperty.call(map2, goodsId)) { map3[goodsId] = map2[goodsId] cnt++ if (cnt >= 3) break } } //将这三组中随机三个物品消除 for (const goodsId in map3) { if (Object.prototype.hasOwnProperty.call(map3, goodsId)) { const goodsArr: Goods[] = map3[goodsId]; const pickedGoodsArr: Goods[] = ArrayUtil.pickItems(goodsArr, 3, true) for (let i = 0; i < pickedGoodsArr.length; i++) { const goods: Goods = pickedGoodsArr[i]; const shelve: ShelveBase = goods.node.parent.parent.getComponent(ShelveBase) if (!shelve) { continue } shelve.removeGoods(goods) } } } } }