GameMain.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. import PlaySoundManager from '../Manager/core/PlaySoundManager';
  2. import CCUtils from '../Utiles/CCUtils';
  3. import Utiles from '../Utiles/Utiles';
  4. /** @type {*} */
  5. const { ccclass, property } = cc._decorator;
  6. /**
  7. * 游戏类型
  8. */
  9. export enum GameType {
  10. /** 节奏练习 */
  11. Rhythmexercises = 1,
  12. /** 节奏大师 */
  13. RhythmMaster = 2,
  14. }
  15. /**
  16. * 游戏状态
  17. *
  18. * @export
  19. * @enum {number}
  20. */
  21. export enum GameStatus {
  22. /** 游戏未开始 */
  23. GameNotStart = 1,
  24. /** 游戏开始 */
  25. GameStart = 2,
  26. /** 游戏结束 */
  27. GameOver = 3,
  28. }
  29. /**
  30. * 游戏核心逻辑
  31. *
  32. * @export
  33. * @class GameMain
  34. * @extends {cc.Component}
  35. */
  36. @ccclass
  37. export default class GameMain extends cc.Component {
  38. @property(cc.Node)
  39. private ball: cc.Node = null;
  40. /** 移动速度 */
  41. private speed: number = 800;
  42. /** 当前背景 */
  43. private curBg: cc.Node = null;
  44. /** 监听触摸层 */
  45. private touchLayer: cc.Node = null;
  46. private noteNodes: cc.Node[] = [];
  47. private noteIndex: number = 0;
  48. private createIndex: number = 0;
  49. /** 音符持续时间 */
  50. private songTimes: Array<number> = [];
  51. private sunTime: number = 0;
  52. private curClip: cc.AudioClip = null;
  53. private errorScope: number = 400;
  54. public notePool: any = null;
  55. public recycelIndex: number = 0;
  56. public mapLayer: cc.Node = null;
  57. public gameIsOver: boolean = false;
  58. // LIFE-CYCLE CALLBACKS:
  59. /** 飘分 */
  60. public scoreLabel: cc.Node = null;
  61. public sumScoreLabel: cc.Node = null;
  62. public addScoreNum: number = 20;
  63. public sumScoreNum: number = 0;
  64. public failNode: cc.Node = null;
  65. public gameStartBtn: cc.Node= null;
  66. onLoad() {
  67. this.createNotes();
  68. this.node.opacity = 50;
  69. this.touchLayer = CCUtils.findChild(this.node, 'touchLayer');
  70. this.scoreLabel = CCUtils.findChild(this.node, 'Camera/scoreLabel');
  71. this.scoreLabel.getComponent(cc.Label).string = `+${this.addScoreNum}`;
  72. this.sumScoreLabel = CCUtils.findChild(this.node, 'Camera/sumScoreLabel');
  73. this.sumScoreLabel.getComponent(cc.Label).string = this.sumScoreNum + '';
  74. this.failNode = CCUtils.findChild(this.node, 'failNode');
  75. this.failNode.active = false;
  76. this.touchLayer.on(cc.Node.EventType.TOUCH_START, this.onTouchBegan.bind(this), this);
  77. this.touchLayer.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMoved.bind(this), this);
  78. this.touchLayer.on(cc.Node.EventType.TOUCH_END, this.onTouchEnded.bind(this), this);
  79. this.touchLayer.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnded.bind(this), this);
  80. this.gameStartBtn = CCUtils.findChild(this.node, 'lockGame/gameStart');
  81. cc.tween(this.node).to(0.8, { opacity: 255 }).start();
  82. this.gameStartBtn.y = 1200;
  83. this.gameStartBtn.scale = 0.8;
  84. cc.tween(this.gameStartBtn).to(0.4, { y: -70, scale: 1 }).to(0.1, { y: 10, scale: 0.9 }).to(0.12, { y: 0 , scale: 1}).start();
  85. }
  86. protected onEnable(): void {
  87. this.curBg = CCUtils.findChild(this.node, 'Camera/bgNode/bg1');
  88. this.mapLayer = CCUtils.findChild(this.node, 'mapLayer');
  89. this.songTimes = Utiles.getSongTimes();
  90. PlaySoundManager.getInstance().loadSound('sound/gameSong/0', (clip: any): void => {
  91. this.curClip = clip;
  92. console.log('this.curClip: ', this.curClip);
  93. this.gameStartBtn.on('click', this.gameStart, this);
  94. });
  95. this.resetGameData();
  96. this.addOnEvent();
  97. this.resetBallState();
  98. this.initNotePos();
  99. }
  100. protected onDisable(): void {
  101. this.gameStartBtn.off('click', this.gameStart, this);
  102. this.clearNotes();
  103. }
  104. public updateScore(): void {
  105. this.sumScoreNum += this.addScoreNum;
  106. this.sumScoreLabel.getComponent(cc.Label).string = this.sumScoreNum + '';
  107. }
  108. public resetGameData(): void {
  109. this.mapLayer.y = -186.621;
  110. this.sunTime = 0;
  111. this.noteIndex = 0;
  112. this.createIndex = 0;
  113. this.recycelIndex = 0;
  114. this.gameIsOver = false;
  115. this.addScoreNum = 20;
  116. this.sumScoreNum = 0;
  117. }
  118. public clearNotes(): void {
  119. for (let i = 0; i < this.noteNodes.length; i++) {
  120. this.removeNote(this.noteNodes[i]);
  121. }
  122. this.noteNodes = [];
  123. }
  124. public addOnEvent(): void {}
  125. /**
  126. * 开始游戏
  127. *
  128. * @memberof GameMain
  129. */
  130. public gameStart(): void {
  131. console.log('this.songTimes.length: ', this.songTimes.length);
  132. this.musicPlay();
  133. this.schedule(this.updateGame);
  134. CCUtils.findChild(this.node, 'lockGame').active = false;
  135. }
  136. public musicPlay(): void {
  137. PlaySoundManager.getInstance().playSound(this.curClip, false);
  138. }
  139. public updateGame(dt): void {
  140. const offY: number = this.speed * dt;
  141. this.ball.parent.y += offY;
  142. if (this.noteIndex <= this.songTimes.length - 1) {
  143. if (this.noteNodes[this.noteIndex] != null) {
  144. // console.log('====this.noteIndex===: ', this.noteIndex);
  145. const worldPos1: cc.Vec2 = this.ball.parent.convertToWorldSpaceAR(cc.Vec2.ZERO);
  146. const worldPos2: cc.Vec2 = this.noteNodes[this.noteIndex].convertToWorldSpaceAR(cc.Vec2.ZERO);
  147. // console.log('worldPos2: ', worldPos2.y);
  148. if (worldPos1.y >= worldPos2.y + this.errorScope) {
  149. // console.log('===updateGame: ', this.noteIndex);
  150. // this.noteNodes[this.noteIndex]['flag'] = false;
  151. this.noteIndex++;
  152. console.log('=============+++++');
  153. // alert('游戏结束');
  154. this.updateNotePos();
  155. }
  156. } else {
  157. this.gameOver();
  158. }
  159. }
  160. }
  161. public createNotes(): void {
  162. // 创建对象池
  163. const initNumber: number = 20;
  164. this.notePool = new cc.NodePool();
  165. for (let i: number = 0; i < initNumber; ++i) {
  166. const enemy: any = cc.instantiate(CCUtils.findChild(this.node, 'note'));
  167. this.notePool.put(enemy);
  168. }
  169. }
  170. /**
  171. * 初始化音符坐标
  172. *
  173. * @memberof GameMain
  174. */
  175. public initNotePos(): void {
  176. for (let i: number = 0; i < 20; i++) {
  177. this.addNote();
  178. }
  179. }
  180. public addNote(): void {
  181. if (!this.songTimes) return;
  182. const node: cc.Node = this.getNote();
  183. node.active = true;
  184. node.parent = this.mapLayer;
  185. this.sunTime += this.songTimes[this.createIndex];
  186. // 转弯
  187. if (this.noteNodes.length == 0 || (this.noteNodes[this.noteNodes.length - 1].x = 10)) {
  188. node.x = -10;
  189. } else {
  190. node.x = 10;
  191. }
  192. CCUtils.findChild(node, 'noteSp').getComponent(sp.Skeleton).setAnimation(0, '01', false);
  193. const num: number = Number(this.sunTime.toFixed(2));
  194. node.y = this.speed * num;
  195. this.noteNodes.push(node);
  196. this.createIndex++;
  197. }
  198. /**
  199. * 移除音符节点
  200. *
  201. * @memberof RhythmexercisesDriver
  202. */
  203. private removeNote(node: cc.Node): void {
  204. // console.log('node;', node);
  205. if (node == null) return;
  206. CCUtils.findChild(node, 'noteSp').getComponent(sp.Skeleton).setAnimation(0, '02', false);
  207. node.active = false;
  208. this.notePool.put(node);
  209. }
  210. public updateNotePos(): void {
  211. if (this.noteIndex > 10) {
  212. if (this.createIndex >= this.songTimes.length) {
  213. console.warn('音符生成完毕', this.createIndex, ' this.songTimes.length: ', this.songTimes.length);
  214. return;
  215. }
  216. this.removeNote(this.noteNodes[this.recycelIndex++]);
  217. this.addNote();
  218. }
  219. // this.noteIndex
  220. // for (let i: number = 0; i < this.noteNodes.length; i++) {
  221. // // 找到已经过去的音符
  222. // // console.log('flag', this.noteNodes[i]['flag']);
  223. // const node: cc.Node = this.getNote();
  224. // if (!node['flag']) {
  225. // node['flag'] = true;
  226. // CCUtils.findChild(node, 'noteSp').getComponent(sp.Skeleton).setAnimation(0, '01', false);
  227. // this.sunTime += this.songTimes[this.createIndex];
  228. // const num: number = Number(this.sunTime.toFixed(2));
  229. // node.y = this.speed * num;
  230. // // ++this.createIndex;
  231. // return;
  232. // }
  233. // }
  234. }
  235. /**
  236. * 初始化球
  237. *
  238. * @memberof GameMain
  239. */
  240. public resetBallState(): void {
  241. this.ball.x = -150;
  242. this.ball.angle = 0;
  243. }
  244. /**
  245. * 背景管理
  246. *
  247. * @private
  248. * @memberof GameMain
  249. */
  250. private bgManager(): void {}
  251. private changeBgColor(): void {
  252. this.curBg.stopAllActions();
  253. const c: cc.Color = cc.color(Utiles.random(50, 255), Utiles.random(50, 255), Utiles.random(50, 255));
  254. cc.tween(this.curBg).delay(0.3).to(0.5, { color: c }).start();
  255. CCUtils.findChild(this.ball.parent, 'changeBg').getComponent(sp.Skeleton).setAnimation(0, '01', false);
  256. }
  257. private changeBallDir(): void {
  258. this.ball.stopAllActions();
  259. this.ball.angle = 0;
  260. const time: number = 0.05;
  261. if (this.ball.x > 0) {
  262. this.ball;
  263. cc.tween(this.ball).to(time, { angle: -30, x: -150 }).to(time, { angle: 0 }).start();
  264. // this.ball.x = -150;
  265. } else {
  266. cc.tween(this.ball).to(time, { angle: 30, x: 150 }).to(time, { angle: 0 }).start();
  267. // this.ball.x = 150;
  268. }
  269. console.log('changeBallDir: ', this.ball.x);
  270. }
  271. private playNoteAnim(): void {
  272. // this.noteNodes[this.noteIndex]['flag'] = false;
  273. CCUtils.findChild(this.noteNodes[this.noteIndex], 'noteSp').getComponent(sp.Skeleton).setAnimation(0, '02', false);
  274. this.scoreLabelAction();
  275. this.noteIndex++;
  276. }
  277. /**
  278. * 节奏判定
  279. * @returns
  280. */
  281. private onTouchBegan(): void {
  282. if (this.gameIsOver) {
  283. return;
  284. } else {
  285. // 判断是否碰到音符
  286. if (this.noteNodes[this.noteIndex] != null) {
  287. const worldPos1: cc.Vec2 = this.ball.parent.convertToWorldSpaceAR(cc.Vec2.ZERO);
  288. const worldPos2: cc.Vec2 = this.noteNodes[this.noteIndex].convertToWorldSpaceAR(cc.Vec2.ZERO);
  289. this.changeBallDir();
  290. console.log('this.noteIndex: ', this.noteIndex);
  291. // 判断是否在音符范围内,在的话,再播放动画
  292. if (worldPos1.y >= worldPos2.y - 120 && worldPos1.y <= worldPos2.y + this.errorScope) {
  293. this.changeBgColor();
  294. this.playNoteAnim();
  295. this.updateNotePos();
  296. this.updateScore();
  297. } else {
  298. this.gameOver();
  299. }
  300. } else {
  301. this.gameOver();
  302. }
  303. }
  304. }
  305. private onTouchMoved(): void {}
  306. private onTouchEnded(): void {}
  307. /**
  308. * 游戏结束
  309. *
  310. * @private
  311. * @memberof GameMain
  312. */
  313. private gameOver(): void {
  314. console.log('======debug===gameOver');
  315. CCUtils.findChild(this.node, 'Camera').setPosition(cc.v2(0, 0));
  316. this.gameFail();
  317. cc.audioEngine.stopAllEffects();
  318. CCUtils.findChild(this.node, 'lockGame').active = true;
  319. this.unschedule(this.updateGame);
  320. this.resetGameData();
  321. this.resetBallState();
  322. this.clearNotes();
  323. this.initNotePos();
  324. }
  325. private gameFail(): void {
  326. this.failNode.active = true;
  327. this.playLoadingTextEffect(CCUtils.findChild(this.failNode, 'failLabel'), 0.08, ' FAIL \n 游戏结束');
  328. }
  329. private playLoadingTextEffect(node: cc.Node, t: number, str: string): void {
  330. let strTemp: string = '';
  331. for (let i: number = 0; i < str.length; i++) {
  332. cc.tween(node)
  333. .delay(t * i)
  334. .call((): void => {
  335. strTemp += str[i];
  336. node.getComponent(cc.Label).string = strTemp;
  337. })
  338. .start();
  339. }
  340. }
  341. /**
  342. * 再来一次
  343. *
  344. * @private
  345. * @memberof GameMain
  346. */
  347. private againGame(): void {
  348. this.resetsGame();
  349. }
  350. /**
  351. * 重置游戏数据
  352. *
  353. * @private
  354. * @memberof GameMain
  355. */
  356. private resetsGame(): void {}
  357. /**
  358. * 从对象池获取音符
  359. *
  360. * @memberof RhythmexercisesNote
  361. */
  362. public getNote(): cc.Node {
  363. let note: cc.Node = null;
  364. if (this.notePool.size() > 0) {
  365. note = this.notePool.get();
  366. } else {
  367. note = cc.instantiate(CCUtils.findChild(this.node, 'note'));
  368. }
  369. return note;
  370. }
  371. /**
  372. * 回收到对象池
  373. *
  374. * @memberof RhythmexercisesNote
  375. */
  376. public recycleNote(node: cc.Node): void {
  377. if (node == null) return;
  378. this.notePool.put(node);
  379. }
  380. /**
  381. * 清空对象池
  382. *
  383. * @memberof RhythmexercisesNote
  384. */
  385. public clearPool(): void {
  386. this.notePool.clear();
  387. }
  388. public scoreLabelAction(): void {
  389. this.scoreLabel.stopAllActions();
  390. this.scoreLabel.active = true;
  391. this.scoreLabel.opacity = 255;
  392. this.scoreLabel.setPosition(cc.v2(0, -200));
  393. this.scoreLabel.scale = 1;
  394. cc.tween(this.scoreLabel).to(0.3, { scale: 1.5, x: 135, y: -140 }).to(0.2, { opacity: 0 }).start();
  395. }
  396. }