MainGameLogic.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. import { _decorator, Component, Label, Node, tween, UIOpacity, v3, Vec3, Sprite, UITransform, instantiate } from 'cc';
  2. import { AudioManager } from '../AudioManager';
  3. import LocalizedLabel from '../i18n/LocalizedLabel';
  4. import PoolManager from '../PoolManager';
  5. import { Popup } from '../src/ui/page/popup';
  6. import { Url } from '../Url';
  7. import { BlockConfig, BlockState, GridBoardData } from './Block/BlockData';
  8. import GlobalData from './GlobalData';
  9. import { GridBlockMgr } from './GridBlockMgr';
  10. import { Guide } from './Guide';
  11. import { LocalStorageMgr } from './LocalStorageMgr';
  12. import { TouchMgr } from './TouchMgr';
  13. import { BlockController } from './Block/BlockController';
  14. const { ccclass, property } = _decorator;
  15. @ccclass('MainGameLogic')
  16. export class MainGameLogic extends Component {
  17. /** 单例模式 */
  18. private static _ins: MainGameLogic;
  19. constructor() {
  20. super();
  21. MainGameLogic._ins = this;
  22. }
  23. public static get ins(): MainGameLogic {
  24. if (!MainGameLogic._ins) {
  25. MainGameLogic._ins = new MainGameLogic();
  26. }
  27. return MainGameLogic._ins;
  28. }
  29. @property(Node)
  30. background: Node = null;
  31. @property(Node)
  32. guide: Node = null;
  33. @property(Label)
  34. curScoreLabel: Label = null;
  35. @property(Label)
  36. historyScoreLabel: Label = null;
  37. @property(Label)
  38. todayScoreLabel: Label = null;
  39. /** 当前得分 */
  40. public curScore: number = 0;
  41. /** 特殊处理总钱数 */
  42. spaciCashTotal: number = 0;
  43. sssspaciCashTotal: number = 0;
  44. @property(Label)
  45. refrashPropLabel: Label = null;
  46. @property(Label)
  47. hummerPropLabel: Label = null;
  48. lotteryData: any = null;
  49. private lastReturnedIndex: number = 0;
  50. @property(Node)
  51. tarPropRefrashIcon: Node = null;
  52. @property(Node)
  53. tarPropHummerIcon: Node = null;
  54. //特效展示节点
  55. @property(Node)
  56. effectsContainer: Node = null;
  57. propInUse: boolean = false;
  58. @property(Node)
  59. autoPlayBtn: Node = null; // 自动放置按钮
  60. isAutoPlaying: boolean = false; // 自动播放状态
  61. autoPlayTimer: any = null; // 自动播放计时器
  62. start() {
  63. AudioManager.ins.play(Url.AUDIO.BGM);
  64. this.gameStart();
  65. }
  66. //游戏开始
  67. gameStart() {
  68. if (!GlobalData.isCommer || GlobalData.guideRecord >= 5) {
  69. GlobalData.isCommer = false;
  70. LocalStorageMgr.setItem(LocalStorageMgr.isCommer_key, GlobalData.isCommer);
  71. GridBlockMgr.ins.generateBoard_effect(GlobalData.lastGameBoard);
  72. this.scheduleOnce(() => {
  73. GridBlockMgr.ins.generateSpecificSelectionBlock(false)
  74. }, 2);
  75. this.guide.active = false;
  76. } else {
  77. console.log("开启新手引导");
  78. this.guide.active = true;
  79. }
  80. mtec.cc.adaptBackgroundNode(this.background);
  81. //不需要
  82. // this.checkAndUpdateDailyHighScore(GlobalData.lastLoginDate);
  83. //更新道具数量,不需要
  84. // this.updatePropNum();
  85. }
  86. //游戏结束
  87. gameOver() {
  88. this.scheduleOnce(async () => {
  89. await Popup.Gameoverpage();
  90. }, 3)
  91. }
  92. //重新开始游戏
  93. reStartGame() {
  94. this.curScore = 0;
  95. GlobalData.curScore = 0;
  96. LocalStorageMgr.setItem(LocalStorageMgr.curScore_key, GlobalData.curScore);
  97. this.updateScores(GlobalData.curScore)
  98. GridBlockMgr.ins.generateBoard_effect(GridBoardData.customizeBoardData5);
  99. this.scheduleOnce(() => {
  100. GridBlockMgr.ins.generateSpecificSelectionBlock(false)
  101. }, 2)
  102. }
  103. // 生成一个分数特效
  104. async createEleAddScoreEff(effPos: Vec3, scoreNum: number) {
  105. let addsecore = await PoolManager.getObject('labelTip');
  106. addsecore.setParent(this.effectsContainer);
  107. addsecore.setPosition(effPos);
  108. addsecore.angle = 0;
  109. addsecore.getComponent(Label).string = '+' + scoreNum.toString();
  110. // addsecore.qtJumpDistance(new Vec3(this.randInt(-400, 400), -this.randInt(1000, 1500), 0), this.randInt(1000, 1300), 1, 1)
  111. // .call(() => {
  112. // PoolManager.putObject('labelTip', addsecore)
  113. // })
  114. // .start();
  115. tween(addsecore)
  116. .to(0.3, { scale: v3(6, 6, 1) })
  117. .delay(0.5)
  118. .to(0.5, { scale: v3(0, 0, 1) }, { easing: 'backIn' })
  119. .call(() => {
  120. this.updateScores(scoreNum);
  121. PoolManager.putObject('labelTip', addsecore)
  122. })
  123. .start();
  124. }
  125. // 生成连续消除特效
  126. async createConsecutiveEffect(effPos: Vec3, totalClearedLines: number) {
  127. if (!effPos) {
  128. return
  129. }
  130. let consecutiveEff;
  131. let name;
  132. if (totalClearedLines < 2) {
  133. return;
  134. }
  135. if (totalClearedLines == 2) {
  136. //good
  137. consecutiveEff = await PoolManager.getObject('good');
  138. AudioManager.ins.playOneShot(Url.AUDIO.SFX17, 1);
  139. name = 'good'
  140. } else if (totalClearedLines == 3) {
  141. //great
  142. consecutiveEff = await PoolManager.getObject('great');
  143. AudioManager.ins.playOneShot(Url.AUDIO.SFX18, 1);
  144. name = 'great'
  145. } else if (totalClearedLines == 4) {
  146. //excellent
  147. consecutiveEff = await PoolManager.getObject('excellent');
  148. AudioManager.ins.playOneShot(Url.AUDIO.SFX19, 1);
  149. name = 'excellent'
  150. } else if (totalClearedLines == 5) {
  151. //amazing
  152. consecutiveEff = await PoolManager.getObject('amazing');
  153. AudioManager.ins.playOneShot(Url.AUDIO.SFX20, 1);
  154. name = 'amazing'
  155. } else if (totalClearedLines >= 6) {
  156. //unbelievable
  157. consecutiveEff = await PoolManager.getObject('unbelievable');
  158. AudioManager.ins.playOneShot(Url.AUDIO.SFX21, 1);
  159. name = 'unbelievable'
  160. }
  161. consecutiveEff.setParent(this.effectsContainer);
  162. consecutiveEff.setPosition(effPos);
  163. consecutiveEff.angle = 0;
  164. consecutiveEff.setScale(v3(0, 0, 1))
  165. // consecutiveEff.qtJumpDistance(new Vec3(this.randInt(-400, 400), -this.randInt(1000, 1500), 0), this.randInt(1000, 1200), 1, 1)
  166. // .call(() => {
  167. // PoolManager.putObject(name, consecutiveEff)
  168. // })
  169. // .start();
  170. tween(consecutiveEff)
  171. .to(0.3, { scale: v3(1, 1, 1) })
  172. .delay(0.5)
  173. .to(0.5, { scale: v3(0, 0, 1) }, { easing: 'backIn' })
  174. .call(() => {
  175. PoolManager.putObject(name, consecutiveEff)
  176. })
  177. .start();
  178. }
  179. // 生成一个tip吐司、
  180. async createOneTipTpast(str: string, insert: string = null) {
  181. let tip: Node = await PoolManager.getObject('tip');
  182. tip.setParent(this.effectsContainer);
  183. tip.setPosition(v3(0, 0, 0));
  184. tip.getComponent(UIOpacity).opacity = 255;
  185. let tiplabel = tip.children[0].getComponent(Label)
  186. let localizedLabel = tiplabel.node.getComponent(LocalizedLabel);
  187. localizedLabel.setTextKeyAndOption(str, insert);
  188. tween(tip)
  189. .delay(0.5)
  190. .to(0.5, { position: v3(0, 50, 0) })
  191. .call(() => {
  192. PoolManager.putObject('tip', tip)
  193. })
  194. .start()
  195. tween(tip.getComponent(UIOpacity))
  196. .delay(0.5)
  197. .to(0.5, { opacity: 0 })
  198. .start()
  199. }
  200. colorMap = {
  201. BLUE: '#00B8FF', // 蓝色
  202. DEEPBLUE: '#00008B', // 深蓝色
  203. GREEN: '#008000', // 绿色
  204. ORANGE: '#FFA500', // 橘色
  205. PURPLE: '#800080', // 紫色
  206. RED: '#FF0000', // 红色
  207. YELLOW: '#FFFF00' // 黄色
  208. };
  209. /// 根据 Url.BLOCK 对象的值获取对应的颜色值
  210. getColorHexFromUrl(blockUrl) {
  211. // 遍历 Url.BLOCK 对象,找到匹配的键名
  212. for (let key in Url.BLOCK) {
  213. if (Url.BLOCK[key] === blockUrl) {
  214. return this.colorMap[key]; // 返回对应的颜色值
  215. }
  216. }
  217. return 'Invalid block URL'; // 如果未找到匹配项,返回错误信息
  218. }
  219. async createOneBlockEfEffect(blocknode: Node, block_color: string) {
  220. let colorHEX = this.getColorHexFromUrl(block_color);
  221. for (let i = 0; i < 2; i++) {
  222. let tarEfPos = TouchMgr.ins.getNodeAToNodeBPoint(blocknode, this.effectsContainer);
  223. let blockef = await PoolManager.getObject('ef');
  224. blockef.setParent(this.effectsContainer);
  225. blockef.setPosition(tarEfPos.add(v3(this.randInt(-20, 20), this.randInt(-20, 20), 0)));
  226. blockef.active = true;
  227. blockef.getComponent(UIOpacity).opacity = 255;
  228. // blockef.getComponent(Sprite).color = new Color().fromHEX(colorHEX);
  229. blockef.setScale(v3(0, 0, 0));
  230. let s = this.randFloat(0.5, 1.2);
  231. tween(blockef)
  232. .parallel(
  233. tween().to(0.3, { scale: v3(s, s, 0) }),
  234. tween().to(0.3, { angle: this.randInt(0, 360) })
  235. )
  236. .start()
  237. tween(blockef.getComponent(UIOpacity))
  238. .delay(0.3)
  239. .to(0.3, { opacity: 0 })
  240. .call(() => {
  241. PoolManager.putObject('ef', blockef); // 回收到对象池
  242. })
  243. .start()
  244. }
  245. }
  246. // 随机生成一个力的值
  247. getRandomForce(min1, max1, min2, max2) {
  248. // 50% 的概率选择第一个区间 [-5000, -2000],或第二个区间 [2000, 5000]
  249. if (Math.random() < 0.5) {
  250. return Math.random() * (max1 - min1) + min1; // [-5000, -2000]
  251. } else {
  252. return Math.random() * (max2 - min2) + min2; // [2000, 5000]
  253. }
  254. }
  255. randInt(min: number, max: number = undefined): number {
  256. if (max === undefined) {
  257. max = min;
  258. min = 0;
  259. }
  260. min = Math.ceil(min);
  261. max = Math.floor(max);
  262. return Math.floor(Math.random() * (max - min)) + min;
  263. }
  264. randFloat(min: number, max: number = undefined): number {
  265. if (max === undefined) {
  266. max = min;
  267. min = 0;
  268. }
  269. return Math.random() * (max - min) + min;
  270. }
  271. /**
  272. * 使用锤子道具特效
  273. * @param targetPos 飞向目标位置
  274. */
  275. // async usePropHummerEffect(targetPos: Vec3, call) {
  276. // let hummer = await PoolManager.getObject('hummer');
  277. // hummer.setParent(this.effectsContainer);
  278. // hummer.setPosition(v3(0, 0, 0));
  279. // hummer.setScale(2, 2, 1);
  280. // hummer.angle = 0;
  281. // tween(hummer)
  282. // .delay(0.2)
  283. // .parallel(
  284. // tween().to(0.3, { position: targetPos }),
  285. // tween().to(0.3, { angle: -30 })
  286. // )
  287. // .call(() => {
  288. // AudioManager.ins.playOneShot(Url.AUDIO.SFX8, 1);
  289. // })
  290. // .to(0.2, { angle: 70 })
  291. // .call(() => {
  292. // call();
  293. // PoolManager.putObject('hummer', hummer);
  294. // })
  295. // .start()
  296. // }
  297. // updatePropNum() {
  298. // this.refrashPropLabel.string = 'x' + GlobalData.refrashPropNum.toString();
  299. // this.hummerPropLabel.string = 'x' + GlobalData.hummerPropNum.toString();
  300. // let refrashadicon = this.refrashPropLabel.node.parent.getChildByName('adicon');
  301. // let hummeradicon = this.hummerPropLabel.node.parent.getChildByName('adicon');
  302. // if (GlobalData.refrashPropNum == 0) {
  303. // this.refrashPropLabel.node.active = false;
  304. // refrashadicon.active = true;
  305. // } else {
  306. // this.refrashPropLabel.node.active = true;
  307. // refrashadicon.active = false;
  308. // }
  309. // if (GlobalData.hummerPropNum == 0) {
  310. // this.hummerPropLabel.node.active = false;
  311. // hummeradicon.active = true;
  312. // } else {
  313. // this.hummerPropLabel.node.active = true;
  314. // hummeradicon.active = false;
  315. // }
  316. // }
  317. // async useRefrashProp(event, _gameOverUse = false) {
  318. // if (_gameOverUse) {
  319. // AudioManager.ins.playOneShot(Url.AUDIO.SFX7, 1);
  320. // GridBlockMgr.ins.generateSpecificSelectionBlock(true);
  321. // return
  322. // }
  323. // if (this.propInUse) {
  324. // return
  325. // }
  326. // if (GlobalData.refrashPropNum > 0) {
  327. // this.propInUse = true;
  328. // AudioManager.ins.playOneShot(Url.AUDIO.SFX7, 1);
  329. // GridBlockMgr.ins.generateSpecificSelectionBlock(true);
  330. // GlobalData.refrashPropNum--;
  331. // this.updatePropNum();
  332. // } else {
  333. // AudioManager.ins.pauseBgm();
  334. // // 触发广告
  335. // let isCom = await true;
  336. // if (isCom) {
  337. // GlobalData.refrashPropNum++;
  338. // this.updatePropNum();
  339. // AudioManager.ins.resumeBgm();
  340. // }
  341. // }
  342. // LocalStorageMgr.setItem(LocalStorageMgr.refrashPropNum_key, GlobalData.refrashPropNum)
  343. // }
  344. // async useHummerProp(event, _gameOverUse = false) {
  345. // // console.log(_gameOverUse);
  346. // if (_gameOverUse) {
  347. // GridBlockMgr.ins.chechAndEliminateRandomArea();
  348. // return
  349. // }
  350. // if (this.propInUse) {
  351. // return
  352. // }
  353. // if (GlobalData.hummerPropNum > 0) {
  354. // this.propInUse = true;
  355. // let isUse = GridBlockMgr.ins.chechAndEliminateRandomArea();
  356. // // console.log(isUse);
  357. // if (isUse) {
  358. // GlobalData.hummerPropNum--;
  359. // this.updatePropNum();
  360. // }
  361. // } else {
  362. // AudioManager.ins.pauseBgm();
  363. // // 触发广告
  364. // let isCom = await true;
  365. // if (isCom) {
  366. // GlobalData.hummerPropNum++;
  367. // this.updatePropNum();
  368. // AudioManager.ins.resumeBgm();
  369. // }
  370. // }
  371. // LocalStorageMgr.setItem(LocalStorageMgr.hummerPropNum_key, GlobalData.hummerPropNum)
  372. // }
  373. /** 检测引导和合成次数 */
  374. public async detectGuideAndElimiTimes(add_tempel_lotNum: number) {
  375. GlobalData.elimiTimes++;
  376. LocalStorageMgr.setItem(LocalStorageMgr.elimiTimes_key, GlobalData.elimiTimes);
  377. if (GlobalData.isCommer) {
  378. Guide.ins.completeCurGuide(GlobalData.elimiTimes + 1);
  379. }
  380. }
  381. /** 检查是否是新的一天并更新今日最高分 */
  382. // public checkAndUpdateDailyHighScore(lastLoginDate: string): void {
  383. // // 更新当前得分
  384. // this.curScore = GlobalData.curScore;
  385. // // 获取当前日期
  386. // const currentDate = new Date().toDateString();
  387. // // 检查是否是同一天
  388. // console.log('是否是同一天:', lastLoginDate == currentDate);
  389. // if (lastLoginDate !== currentDate) {//不是同一天
  390. // GlobalData.todayHighScore = 0;
  391. // LocalStorageMgr.setItem(LocalStorageMgr.todayHighScore_key, GlobalData.todayHighScore);
  392. // } else {
  393. // if (GlobalData.curScore >= GlobalData.todayHighScore) {
  394. // GlobalData.todayHighScore = GlobalData.curScore;
  395. // LocalStorageMgr.setItem(LocalStorageMgr.todayHighScore_key, GlobalData.todayHighScore);
  396. // }
  397. // }
  398. // // 更新最后登录日期
  399. // LocalStorageMgr.setItem(LocalStorageMgr.lastLoginDate_key, currentDate);
  400. // this.updateScoreLabel(this.historyScoreLabel, GlobalData.historyHighScore);
  401. // this.updateScoreLabel(this.todayScoreLabel, GlobalData.todayHighScore);
  402. // this.updateScoreLabel(this.curScoreLabel, GlobalData.curScore);
  403. // }
  404. /** 更新分数 */
  405. public updateScores(addScore: number): void {
  406. // 更新当前得分
  407. this.curScore += addScore;
  408. GlobalData.curScore = this.curScore;
  409. // 更新今日最高分
  410. if (this.curScore > GlobalData.todayHighScore) {
  411. GlobalData.todayHighScore = this.curScore;
  412. this.updateScoreLabel(this.todayScoreLabel, this.curScore)
  413. }
  414. // 更新历史最高分
  415. if (this.curScore > GlobalData.historyHighScore) {
  416. GlobalData.historyHighScore = this.curScore;
  417. this.updateScoreLabel(this.historyScoreLabel, this.curScore)
  418. }
  419. this.updateScoreLabel(this.curScoreLabel, this.curScore);
  420. // 保存分数的方法
  421. LocalStorageMgr.setItem(LocalStorageMgr.historyHighScore_key, GlobalData.historyHighScore);
  422. LocalStorageMgr.setItem(LocalStorageMgr.todayHighScore_key, GlobalData.todayHighScore);
  423. LocalStorageMgr.setItem(LocalStorageMgr.curScore_key, GlobalData.curScore);
  424. }
  425. /**
  426. * 更新分数标签,使其逐渐增长到新分数
  427. * @param tarLabel 目标标签
  428. * @param newScore 新分数
  429. * @param duration 动画持续时间
  430. */
  431. updateScoreLabel(tarLabel: Label, newScore: number, duration: number = 1): void {
  432. const currentScore = parseInt(tarLabel.string) || 0;
  433. const delta = newScore - currentScore;
  434. if (delta === 0) {
  435. return;
  436. }
  437. tween({ value: currentScore })
  438. .to(duration, { value: newScore }, {
  439. onUpdate: (target: { value: number }) => {
  440. tarLabel.string = Math.floor(target.value).toString();
  441. }
  442. })
  443. .start();
  444. //当前分数超过关分数就通关
  445. if ((newScore >= 100)) {
  446. console.log("通关了");
  447. }
  448. }
  449. }