Stage.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. import { _decorator, Component, Input, input, instantiate, KeyCode, macro, math, Node, Prefab, Sprite, UITransform, v3, Vec3 } from 'cc';
  2. import { GameMgr } from '../manager/GameMgr';
  3. import { ArrayUtil } from '../util/ArrayUtil';
  4. import { ShelveType } from '../enum/ShelveType';
  5. import { ShelveLocker } from './ShelveLocker';
  6. import { ShelveBase } from '../scriptBase/ShelveBase';
  7. import { CommonShelve } from './CommonShelve';
  8. import { SmallShelve } from './SmallShelve';
  9. import { UIMgr } from '../manager/UIMgr';
  10. import { UI } from '../enum/UI';
  11. import { PREVIEW } from 'cc/env';
  12. import { Mode, ModeName } from '../enum/Mode';
  13. import { cfg_level_gs, cfg_level_ls, cfg_level_tp } from '../config/cfg_level';
  14. import { DtoLevelCfg } from '../dto/DtoLevelCfg';
  15. import { DtoLevelData } from '../dto/DtoLevelData';
  16. import { cfg_icon_gs, cfg_icon_ls, cfg_icon_tp } from '../config/cfg_icon';
  17. import { DtoIconCfg } from '../dto/DtoIconCfg';
  18. import { ResMgr } from '../manager/ResMgr';
  19. import { Bundle } from '../enum/Bundle';
  20. import { Global } from '../Global';
  21. import { EventMgr } from '../manager/EventMgr';
  22. import { EventType } from '../enum/EventType';
  23. import { CoinMgr } from '../manager/CoinMgr';
  24. import { ComboBox } from './ComboBox';
  25. import { Goods } from './Goods';
  26. import { AudioMgr } from '../manager/AudioMgr';
  27. const { ccclass, property } = _decorator;
  28. @ccclass('Game/Stage')
  29. export class Stage extends Component {
  30. @property(Sprite)
  31. private bg: Sprite = null
  32. @property(Node)
  33. private shelveBox: Node = null
  34. @property(ComboBox)
  35. private comboBox: ComboBox = null
  36. @property(Node)
  37. private tip: Node = null
  38. @property(Prefab)
  39. private shelveLockerPre: Prefab = null
  40. @property(Prefab)
  41. private shelvePreArr: Prefab[] = []
  42. private levelCfg: DtoLevelCfg = null
  43. private levelData: DtoLevelData = null
  44. private iconCfg: DtoIconCfg = null
  45. private shelveArr: ShelveBase[] = []
  46. private doubleCoin: boolean = false
  47. private isBusy: boolean = false
  48. protected onLoad(): void {
  49. const bgName: string = 'bg_' + ModeName[GameMgr.mode]
  50. this.bg.spriteFrame = ResMgr.getSpriteFrame(Bundle.Game, bgName, 'image/')
  51. EventMgr.on(EventType.MergeGoods, this.onMergeGoods, this)
  52. EventMgr.on(EventType.TimeOut, this.onTimeOut, this)
  53. EventMgr.on(EventType.TimeOutAlert, this.onTimeOutAlert, this)
  54. EventMgr.on(EventType.UseSkillFreezeTime, this.onUseSkillFreezeTime, this)
  55. EventMgr.on(EventType.UseSkillDoubleCoin, this.onUseDoubleCoin, this)
  56. EventMgr.on(EventType.UseSkillRefreshPosition, this.onUseRefreshPos, this)
  57. EventMgr.on(EventType.UseSkillEraseGroup, this.onUseEraseGroup, this)
  58. if (PREVIEW) {
  59. input.on(Input.EventType.KEY_DOWN, (e) => {
  60. if (e.keyCode !== KeyCode.KEY_Q) return
  61. if (GameMgr.Pause) return
  62. UIMgr.open(UI.Win)
  63. }, this)
  64. }
  65. }
  66. protected onDestroy(): void {
  67. UIMgr.close(UI.Game)
  68. this.unscheduleAllCallbacks()
  69. EventMgr.off(EventType.MergeGoods, this.onMergeGoods, this)
  70. EventMgr.off(EventType.TimeOut, this.onTimeOut, this)
  71. EventMgr.off(EventType.TimeOutAlert, this.onTimeOutAlert, this)
  72. EventMgr.off(EventType.UseSkillFreezeTime, this.onUseSkillFreezeTime, this)
  73. EventMgr.off(EventType.UseSkillDoubleCoin, this.onUseDoubleCoin, this)
  74. EventMgr.off(EventType.UseSkillRefreshPosition, this.onUseRefreshPos, this)
  75. EventMgr.off(EventType.UseSkillEraseGroup, this.onUseEraseGroup, this)
  76. }
  77. protected start() {
  78. UIMgr.open(UI.Game)
  79. this.tip.active = GameMgr.mode === Mode.tp && GameMgr.CurLevel === 0
  80. this.scheduleOnce(() => {
  81. //Difficulty increase 难度飙升
  82. if (GameMgr.isHardLevel) UIMgr.open(UI.StageTip, 'Difficulty increase')
  83. }, 1)
  84. switch (GameMgr.mode) {
  85. case Mode.tp:
  86. this.levelCfg = cfg_level_tp
  87. this.iconCfg = cfg_icon_tp
  88. break;
  89. case Mode.gs:
  90. this.levelCfg = cfg_level_gs
  91. this.iconCfg = cfg_icon_gs
  92. break
  93. case Mode.ls:
  94. this.levelCfg = cfg_level_ls
  95. this.iconCfg = cfg_icon_ls
  96. break
  97. }
  98. if (GameMgr.CurLevel >= this.levelCfg.length) {
  99. this.levelData = ArrayUtil.pickItem(this.levelCfg)
  100. } else {
  101. this.levelData = this.levelCfg[GameMgr.CurLevel]
  102. }
  103. const shelveMap: number[][] = this.levelData.shelveMap
  104. const group: number = this.levelData.group
  105. const lockCnt: number = this.levelData.lockCnt
  106. const goodsTypeCnt: number = this.levelData.GoodsTypeCnt
  107. Global.Level_Time = this.levelData.time
  108. // Global.Level_Time = 10
  109. EventMgr.emit(EventType.TimeReset)
  110. this.createShelves(shelveMap)
  111. this.createShelveLockers(lockCnt)
  112. this.createGoodsArr(group, goodsTypeCnt)
  113. this.createGoodsData()
  114. this.schedule(this.onCheckWin, 0.5, macro.REPEAT_FOREVER)
  115. }
  116. private createShelves(shelveMap: number[][]): void {
  117. const row: number = shelveMap.length
  118. const col: number = shelveMap[0].length
  119. const uiTrans: UITransform = this.shelveBox.getComponent(UITransform)
  120. const spaceX: number = 0
  121. const spaceY: number = 0
  122. uiTrans.width = col * 230 + spaceX * (col - 1)
  123. uiTrans.height = row * 145 + spaceY * (row - 1)
  124. for (let i = 0; i < shelveMap.length; i++) {
  125. for (let j = 0; j < shelveMap[i].length; j++) {
  126. const type: ShelveType = shelveMap[i][j]
  127. const shelvePre: Prefab = this.shelvePreArr[type]
  128. const shelveNode: Node = instantiate(shelvePre)
  129. this.shelveBox.addChild(shelveNode)
  130. }
  131. }
  132. this.shelveArr = this.shelveBox.getComponentsInChildren(ShelveBase)
  133. }
  134. private createShelveLockers(lockCnt: number): void {
  135. if (lockCnt <= 0) return
  136. const shelves: ShelveBase[] = ArrayUtil.pickItems(this.shelveArr, lockCnt, true)
  137. for (let i = 0; i < shelves.length; i++) {
  138. const shelve: ShelveBase = shelves[i];
  139. const shelveLockerNode: Node = instantiate(this.shelveLockerPre)
  140. shelve.node.addChild(shelveLockerNode)
  141. const shelveLocker: ShelveLocker = shelveLockerNode.getComponent(ShelveLocker)
  142. shelveLocker.UnlockCnt = math.randomRangeInt(3, 6)
  143. }
  144. }
  145. private createGoodsArr(group: number, goodsTypeCnt: number): void {
  146. const idxArr: number[] = ArrayUtil.pickIndexs(this.iconCfg, goodsTypeCnt, true)
  147. GameMgr.goodsArr = []
  148. for (let i = 0; i < group; i++) {
  149. const goodsId: number = ArrayUtil.pickItem(idxArr) + 1
  150. GameMgr.goodsArr.push(goodsId, goodsId, goodsId)
  151. }
  152. ArrayUtil.shuffle(GameMgr.goodsArr)
  153. }
  154. private createGoodsData(): void {
  155. const commonShelveArr: CommonShelve[] = []
  156. const smallShelveArr: SmallShelve[] = []
  157. for (let i = 0; i < this.shelveArr.length; i++) {
  158. const shelve: ShelveBase = this.shelveArr[i];
  159. if (shelve instanceof CommonShelve) {
  160. commonShelveArr.push(shelve)
  161. } else if (shelve instanceof SmallShelve) {
  162. smallShelveArr.push(shelve)
  163. }
  164. }
  165. //先悬浮格子
  166. for (let i = 0; i < smallShelveArr.length; i++) {
  167. const smallShelve: SmallShelve = smallShelveArr[i];
  168. const smallShelveId: number = smallShelve.Id
  169. if (!GameMgr.goodsData.hasOwnProperty(smallShelveId)) {
  170. GameMgr.goodsData[smallShelveId] = {
  171. 0: [],
  172. }
  173. }
  174. // const cnt: number = math.randomRangeInt(2, 4)
  175. for (let j = 0; j < 3; j++) {
  176. const goodsId: number = GameMgr.goodsArr.shift()
  177. GameMgr.goodsData[smallShelveId][0].push(goodsId)
  178. }
  179. }
  180. const placeCnt: number = commonShelveArr.length * 3
  181. while (GameMgr.goodsArr.length > 0) {
  182. //筛选槽位
  183. const placeArr: number[] = []
  184. for (let i = 0; i < placeCnt; i++) {
  185. placeArr.push(i)
  186. }
  187. ArrayUtil.shuffle(placeArr)
  188. if (placeCnt <= 6) {
  189. placeArr.splice(0, math.randomRangeInt(2, 3))
  190. } else {
  191. placeArr.splice(0, math.randomRangeInt(4, 6))
  192. }
  193. for (let i = 0; i < placeCnt; i++) {
  194. const placeId: number = i
  195. const commonShelveId: number = commonShelveArr[Math.floor(placeId / 3)].Id
  196. const slotId: number = placeId % 3
  197. if (!GameMgr.goodsData.hasOwnProperty(commonShelveId)) {
  198. GameMgr.goodsData[commonShelveId] = {
  199. 0: [],
  200. 1: [],
  201. 2: [],
  202. }
  203. }
  204. let goodsId: number = -1
  205. if (GameMgr.goodsArr.length <= 0 || !placeArr.includes(placeId)) goodsId = -1
  206. else goodsId = GameMgr.goodsArr.shift()
  207. GameMgr.goodsData[commonShelveId][slotId].push(goodsId)
  208. }
  209. }
  210. }
  211. private onCheckWin(): void {
  212. const isWin: boolean = this.checkWin()
  213. if (!isWin) return
  214. if (this.isBusy) return
  215. this.unscheduleAllCallbacks()
  216. UIMgr.open(UI.Win)
  217. }
  218. private checkWin(): boolean {
  219. for (let i = 0; i < this.shelveArr.length; i++) {
  220. const shelve: ShelveBase = this.shelveArr[i];
  221. if (!shelve.isEmpty) return false
  222. }
  223. return true
  224. }
  225. private onTimeOut(): void {
  226. const isWin: boolean = this.checkWin()
  227. if (isWin) return
  228. UIMgr.open(UI.TimeOut)
  229. }
  230. private onTimeOutAlert(): void {
  231. const effectRedAlertPre: Prefab = ResMgr.getRes(Bundle.Game, 'EffectRedAlert')
  232. const effectRedAlertNode: Node = instantiate(effectRedAlertPre)
  233. this.node.addChild(effectRedAlertNode)
  234. }
  235. private onUseSkillFreezeTime(): void {
  236. const effectFreezePre: Prefab = ResMgr.getRes(Bundle.Game, 'EffectFreeze')
  237. const effectFreezeNode: Node = instantiate(effectFreezePre)
  238. this.node.addChild(effectFreezeNode)
  239. }
  240. private onMergeGoods(shelveWorldPos: Vec3): void {
  241. this.comboBox.CurCombo++
  242. AudioMgr.playSfx(`bomb_${this.comboBox.CurCombo}`)
  243. CoinMgr.CurCoin += this.doubleCoin ? this.comboBox.CurCombo * 2 : this.comboBox.CurCombo
  244. this.comboBox.createFloatText(shelveWorldPos)
  245. }
  246. private onUseDoubleCoin(): void {
  247. AudioMgr.playSfx('星星道具')
  248. this.doubleCoin = true
  249. this.scheduleOnce(this.onAfterDoubleCoin, Global.Double_Coin_Duration)
  250. }
  251. private onAfterDoubleCoin(): void {
  252. this.doubleCoin = false
  253. }
  254. private onUseRefreshPos(): void {
  255. AudioMgr.playSfx('转换道具')
  256. for (let i = 0; i < this.shelveArr.length; i++) {
  257. const shelve: ShelveBase = this.shelveArr[i]
  258. const goodsIdArr: number[] = shelve.GoodsIdArr
  259. for (let j = 0; j < goodsIdArr.length; j++) {
  260. const goodsId: number = goodsIdArr[j];
  261. GameMgr.goodsArr.push(goodsId)
  262. }
  263. }
  264. ArrayUtil.shuffle(GameMgr.goodsArr)
  265. this.createGoodsData()
  266. for (let i = 0; i < this.shelveArr.length; i++) {
  267. const shelve: ShelveBase = this.shelveArr[i]
  268. shelve.clear()
  269. this.scheduleOnce(() => {
  270. shelve.init()
  271. })
  272. }
  273. this.isBusy = true
  274. this.scheduleOnce(() => {
  275. this.isBusy = false
  276. }, 0.5)
  277. }
  278. private onUseEraseGroup(): void {
  279. AudioMgr.playSfx('灯泡道具')
  280. //先统计场上的物品
  281. const goodsMap = {}
  282. for (let i = 0; i < this.shelveArr.length; i++) {
  283. const shelve: ShelveBase = this.shelveArr[i];
  284. const info: Object = shelve.GoodsInfo
  285. for (const layer in info) {
  286. if (Object.prototype.hasOwnProperty.call(info, layer)) {
  287. for (const slot in info[layer]) {
  288. if (Object.prototype.hasOwnProperty.call(info[layer], slot)) {
  289. const goods: Goods = info[layer][slot];
  290. const goodsId: number = goods.Id
  291. if (!goodsMap.hasOwnProperty(goodsId)) {
  292. goodsMap[goodsId] = []
  293. }
  294. goodsMap[goodsId].push(goods)
  295. }
  296. }
  297. }
  298. }
  299. for (const goodsId in goodsMap) {
  300. if (Object.prototype.hasOwnProperty.call(goodsMap, goodsId)) {
  301. ArrayUtil.shuffle(goodsMap[goodsId])
  302. }
  303. }
  304. }
  305. //筛选出超过三个的物品
  306. const map2 = {}
  307. for (const goodsId in goodsMap) {
  308. if (Object.prototype.hasOwnProperty.call(goodsMap, goodsId)) {
  309. if (goodsMap[goodsId].length >= 3) {
  310. map2[goodsId] = goodsMap[goodsId]
  311. }
  312. }
  313. }
  314. //从中挑选三组
  315. const map3 = {}
  316. let cnt: number = 0
  317. for (const goodsId in map2) {
  318. if (Object.prototype.hasOwnProperty.call(map2, goodsId)) {
  319. map3[goodsId] = map2[goodsId]
  320. cnt++
  321. if (cnt >= 3) break
  322. }
  323. }
  324. //将这三组中随机三个物品消除
  325. for (const goodsId in map3) {
  326. if (Object.prototype.hasOwnProperty.call(map3, goodsId)) {
  327. const goodsArr: Goods[] = map3[goodsId];
  328. const pickedGoodsArr: Goods[] = ArrayUtil.pickItems(goodsArr, 3, true)
  329. for (let i = 0; i < pickedGoodsArr.length; i++) {
  330. const goods: Goods = pickedGoodsArr[i];
  331. const shelve: ShelveBase = goods.node.parent.parent.getComponent(ShelveBase)
  332. if (!shelve) {
  333. continue
  334. }
  335. shelve.removeGoods(goods)
  336. }
  337. }
  338. }
  339. }
  340. }