customMenu.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. /******************************
  2. * This file holds game states.
  3. ******************************/
  4. /** [CUSTOM MENU STATE] Screen where the user can customise the selected game - game mode, math operation, level of difficulty.
  5. *
  6. * @namespace
  7. */
  8. const customMenuState = {
  9. /**
  10. * Preloads media for current state
  11. */
  12. preload: function () {
  13. // LOADING MEDIA
  14. game.load.sprite(url[gameType].sprite);
  15. game.load.image(url[gameType].image);
  16. },
  17. /**
  18. * Main code
  19. */
  20. create: function () {
  21. // FOR MOODLE
  22. if (moodle && iLMparameters.iLM_PARAM_SendAnswer == 'false') {
  23. // Student role
  24. game.state.start('map');
  25. } else {
  26. // Background color
  27. game.add.geom.rect(
  28. 0,
  29. 0,
  30. context.canvas.width,
  31. context.canvas.height,
  32. undefined,
  33. 0,
  34. colors.blueBg,
  35. 1
  36. );
  37. // Floor
  38. for (let i = 0; i < context.canvas.width / 100; i++) {
  39. game.add.image(i * 100, context.canvas.height - 100, 'floor');
  40. }
  41. // Overtitle : Selected game
  42. game.add.text(
  43. context.canvas.width / 2,
  44. 40,
  45. game.lang.game.toUpperCase() + ': ' + menuState.menuIcons,
  46. textStyles.h4_brown
  47. );
  48. // Title : Customize the selected game
  49. game.add.text(
  50. context.canvas.width / 2,
  51. 80,
  52. game.lang.custom_game,
  53. textStyles.h1_green
  54. );
  55. // Loads navigation icons
  56. navigationIcons.add(true, false, false, true, true, 'menu', false);
  57. let infoIcon;
  58. const iconScale = 0.7;
  59. const curGame = info.all[gameType];
  60. this.menuIcons = [];
  61. let x = gameFrame().x;
  62. let y = gameFrame().y;
  63. let offsetW = game.math.getOffset(gameFrame().width, 5);
  64. let offsetH = game.math.getOffset(
  65. gameFrame().height,
  66. curGame.gameMode.length
  67. );
  68. const line_thickness = 5;
  69. // Label 'Game Modes'
  70. game.add.text(x + offsetW, y, game.lang.game_modes, textStyles.h2_blue);
  71. infoIcon = game.add.image(x + 2 * offsetW - 30, y - 20, 'info', 0.5, 0.4);
  72. infoIcon.anchor(0.5, 0.5);
  73. infoIcon.iconType = 'infoIcon';
  74. infoIcon.id = 'gameMode';
  75. this.menuIcons.push(infoIcon);
  76. // Label 'Operations'
  77. game.add.text(
  78. x + 3 * offsetW,
  79. y,
  80. game.lang.operations,
  81. textStyles.h2_blue
  82. );
  83. infoIcon = game.add.image(x + 4 * offsetW - 30, y - 20, 'info', 0.5, 0.4);
  84. infoIcon.anchor(0.5, 0.5);
  85. infoIcon.iconType = 'infoIcon';
  86. infoIcon.id = 'gameOperation';
  87. this.menuIcons.push(infoIcon);
  88. // Label 'Difficulties'
  89. game.add.text(
  90. x + 5 * offsetW,
  91. y,
  92. game.lang.difficulties,
  93. textStyles.h2_blue
  94. );
  95. infoIcon = game.add.image(x + 6 * offsetW - 30, y - 20, 'info', 0.5, 0.4);
  96. infoIcon.anchor(0.5, 0.5);
  97. infoIcon.iconType = 'infoIcon';
  98. infoIcon.id = 'gameDifficulty';
  99. this.menuIcons.push(infoIcon);
  100. // Horizontal line
  101. game.add.geom
  102. .rect(
  103. x - 25,
  104. y + 10,
  105. gameFrame().width,
  106. line_thickness,
  107. undefined,
  108. 0,
  109. colors.blueMenuLine
  110. )
  111. .anchor(0, 0.5);
  112. // Vertical lines
  113. game.add.geom
  114. .rect(
  115. x + 2 * offsetW,
  116. y - 25,
  117. line_thickness,
  118. gameFrame().height,
  119. undefined,
  120. 0,
  121. colors.blueMenuLine
  122. )
  123. .anchor(0.5, 0);
  124. game.add.geom
  125. .rect(
  126. x + 4 * offsetW,
  127. y - 25,
  128. line_thickness,
  129. gameFrame().height,
  130. undefined,
  131. 0,
  132. colors.blueMenuLine
  133. )
  134. .anchor(0.5, 0);
  135. // --------------------------- TURN ON/OFF FRACTION LABELS / RECTANGLE GUIDE
  136. // Horizontal line
  137. game.add.geom
  138. .rect(
  139. x + 4 * offsetW,
  140. y + offsetH,
  141. gameFrame().width / 3 - 4 * line_thickness,
  142. line_thickness,
  143. undefined,
  144. 0,
  145. colors.blueMenuLine
  146. )
  147. .anchor(0, 0.5);
  148. infoIcon = game.add.image(
  149. x + 6 * offsetW - 30,
  150. y + offsetH - 20,
  151. 'info',
  152. 0.5,
  153. 0.4
  154. );
  155. infoIcon.anchor(0.5, 0.5);
  156. infoIcon.iconType = 'infoIcon';
  157. infoIcon.id = 'gameMisc';
  158. this.menuIcons.push(infoIcon);
  159. // Label 'Show Fractions / Auxiliar rectangles'
  160. game.add.text(
  161. x + 5 * offsetW,
  162. y + offsetH - 48,
  163. game.lang.show,
  164. textStyles.h4_blue
  165. );
  166. let auxText;
  167. if (gameType == 'squareTwo') {
  168. auxText = game.lang.aux_rectangle;
  169. game.add.text(
  170. x + 5 * offsetW + 10,
  171. y + offsetH - 24,
  172. auxText,
  173. textStyles.h4_blue
  174. );
  175. } else {
  176. auxText = game.lang.title;
  177. game.add.text(
  178. x + 5 * offsetW,
  179. y + offsetH - 24,
  180. auxText,
  181. textStyles.h2_blue
  182. );
  183. }
  184. // Selection box
  185. y += 40;
  186. const frame = fractionLabel ? 1 : 0;
  187. const selectionBox = game.add.sprite(
  188. x + 5 * offsetW,
  189. y + offsetH,
  190. 'select',
  191. frame,
  192. 0.11
  193. );
  194. selectionBox.anchor(0.5, 0.5);
  195. selectionBox.iconType = 'selectionBox';
  196. this.menuIcons.push(selectionBox);
  197. // --------------------------- GAME MODE ICONS
  198. x = gameFrame().x + offsetW;
  199. y = gameFrame().y + offsetH / 2;
  200. for (let i = 0; i < curGame.gameModeUrl.length; i++, y += offsetH) {
  201. const icon = game.add.sprite(
  202. x,
  203. y,
  204. curGame.gameModeUrl[i],
  205. 0,
  206. iconScale,
  207. 1
  208. );
  209. icon.anchor(0.5, 0.5);
  210. icon.gameMode = curGame.gameMode[i];
  211. icon.iconType = 'gameMode';
  212. if (i == 0) {
  213. gameMode = icon.gameMode;
  214. icon.curFrame = 1;
  215. }
  216. this.menuIcons.push(icon);
  217. }
  218. // --------------------------- GAME OPERATION ICONS
  219. x += 2 * offsetW;
  220. y = gameFrame().y + offsetH / 2;
  221. offsetH = game.math.getOffset(
  222. gameFrame().height,
  223. curGame.gameOperation.length
  224. );
  225. let icon;
  226. // Placing math operation icons
  227. for (let i = 0; i < curGame.gameOperation.length; i++, y += offsetH) {
  228. icon = game.add.sprite(
  229. x,
  230. y,
  231. curGame.gameOperationUrl[i],
  232. 0,
  233. iconScale,
  234. 1
  235. );
  236. icon.anchor(0.5, 0.5);
  237. icon.gameOperation = curGame.gameOperation[i];
  238. icon.iconType = 'gameOperation';
  239. if (i == 0) {
  240. gameOperation = icon.gameOperation;
  241. icon.curFrame = 1;
  242. }
  243. this.menuIcons.push(icon);
  244. }
  245. // --------------------------- DIFFICULTY ICONS
  246. x = gameFrame().x - 50 + 5 * offsetW;
  247. offsetH = game.math.getOffset(
  248. gameFrame().height,
  249. curGame.gameMode.length
  250. );
  251. y = gameFrame().y + offsetH / 3;
  252. if (gameType != 'squareOne') x -= 40;
  253. for (let i = 0; i < curGame.gameDifficulty; i++) {
  254. // Parameters
  255. const curX = x + (30 + 10) * i;
  256. // Difficulty menuIcons
  257. const icon = game.add.geom.rect(
  258. curX,
  259. y,
  260. 30,
  261. 30,
  262. undefined,
  263. 0,
  264. colors.gray,
  265. 1
  266. );
  267. icon.anchor(0.5, 0.5);
  268. icon.difficulty = i + 1;
  269. icon.iconType = 'difficulty';
  270. if (i == 0) {
  271. gameDifficulty = icon.difficulty;
  272. icon.fillColor = colors.blue;
  273. }
  274. this.menuIcons.push(icon);
  275. // Difficulty numbers
  276. game.add.text(curX, y + 7, i + 1, textStyles.h4_white);
  277. }
  278. // --------------------------- ENTER ICON
  279. // FOR MOODLE
  280. if (!moodle) {
  281. x = context.canvas.width - 100;
  282. y = context.canvas.height - 110;
  283. const enterIcon = game.add.image(x, y, 'bush');
  284. enterIcon.anchor(0.5, 0.5);
  285. enterIcon.iconType = 'enter';
  286. this.menuIcons.push(enterIcon);
  287. this.enterText = game.add.text(
  288. x,
  289. y,
  290. game.lang.continue,
  291. textStyles.h4_white
  292. );
  293. }
  294. // --------------------------- INFO BOX
  295. this.infoBox = document.getElementById('my-modal');
  296. // When the user clicks on the 'x', close the modal
  297. document.getElementsByClassName('close')[0].onclick = function () {
  298. self.infoBox.style.display = 'none';
  299. };
  300. // When the user clicks anywhere outside of the modal, close it
  301. window.onclick = function (event) {
  302. if (event.target == self.infoBox) {
  303. self.infoBox.style.display = 'none';
  304. }
  305. };
  306. this.infoBoxContent = {
  307. gameMode: {
  308. squareOne: {
  309. title: '<b>' + game.lang.game_modes + '</b>',
  310. body: game.lang.infoBox_mode,
  311. img:
  312. '<table> <tr> <td> <b>A)</b> ' +
  313. game.lang.infoBox_mode_s1_A +
  314. ' </td> <td> <b>B)</b> ' +
  315. game.lang.infoBox_mode_s1_B +
  316. ' </td> </tr> <tr> <td> <img width=100% src="' +
  317. game.image['s1-A-h'].src +
  318. '"> ' +
  319. ' </td> <td> <img width=100% src="' +
  320. game.image['s1-B-h'].src +
  321. '"> </td> </tr> <table>',
  322. },
  323. circleOne: {
  324. title: '<b>' + game.lang.game_modes + '</b>',
  325. body: game.lang.infoBox_mode,
  326. img:
  327. '<table> <tr style="border-bottom: 5px solid white"> <td width=70%> <img width=100% src="' +
  328. game.image['c1-A-h'].src +
  329. '">' +
  330. ' </td> <td> &nbsp; <b>A)</b> ' +
  331. game.lang.infoBox_mode_c1_A +
  332. ' </td> </tr> </tr> <td> <img width=100% src="' +
  333. game.image['c1-B-h'].src +
  334. '"> ' +
  335. ' </td> <td> &nbsp; <b>B)</b> ' +
  336. game.lang.infoBox_mode_c1_B +
  337. '</td> </tr> <table>',
  338. },
  339. squareTwo: {
  340. title: '<b>' + game.lang.game_modes + '</b>',
  341. body: game.lang.infoBox_mode,
  342. img:
  343. '<table> <tr> <td> <b>A)</b> ' +
  344. game.lang.infoBox_mode_s2_A +
  345. ' </td> <td> <b>B)</b> ' +
  346. game.lang.infoBox_mode_s2_B +
  347. ' </td> </tr> <tr> <td> <img width=98% src="' +
  348. game.image['s2-A-h'].src +
  349. '"> ' +
  350. ' </td> <td> <img width=98% src="' +
  351. game.image['s2-B-h'].src +
  352. '"> </td> </tr> <table>',
  353. },
  354. },
  355. gameOperation: {
  356. title: '<b>' + game.lang.operation_math + '</b>',
  357. body: game.lang.infoBox_oper,
  358. img:
  359. '<table class="table">' +
  360. '<tr>' +
  361. '<td> <img width=50 src="' +
  362. game.image['operation_plus'].src +
  363. '"> </td>' +
  364. '<td> <img width=50 src="' +
  365. game.image['operation_mixed'].src +
  366. '"> </td>' +
  367. '<td> <img width=50 src="' +
  368. game.image['operation_minus'].src +
  369. '"> </td>' +
  370. '<td> <img width=50 src="' +
  371. game.image['operation_equals'].src +
  372. '"> </td>' +
  373. '</tr> <tr>' +
  374. '<td class="text-center">' +
  375. game.lang.plus +
  376. '</td>' +
  377. '<td class="text-center">' +
  378. game.lang.mixed +
  379. '</td>' +
  380. '<td class="text-center">' +
  381. game.lang.minus +
  382. '</td>' +
  383. '<td class="text-center">' +
  384. game.lang.equals +
  385. '</td>' +
  386. '</tr>' +
  387. '</table>',
  388. },
  389. gameDifficulty: {
  390. squareOne: {
  391. title: '<b>' + game.lang.difficulties + '</b>',
  392. body: game.lang.infoBox_diff + ' ' + game.lang.infoBox_diff_obs,
  393. img:
  394. '<table> <tr> <td> <b>' +
  395. game.lang.difficulty +
  396. ':</b> 1' +
  397. ' </td> <td> <b>' +
  398. game.lang.difficulty +
  399. ':</b> 3' +
  400. ' </td> </tr> <tr> <td> <img width=100% src="' +
  401. game.image['s1-diff-1'].src +
  402. '"> ' +
  403. ' </td> <td style="border-left: 4px solid white"> <img width=100% src="' +
  404. game.image['s1-diff-3'].src +
  405. '"> </td> </tr> </table> <br>' +
  406. game.lang.infoBox_diff_aux +
  407. '<center> <img width=50% src="' +
  408. game.image['map-s1'].src +
  409. '"> </center>',
  410. },
  411. circleOne: {
  412. title: '<b>' + game.lang.difficulties + '</b>',
  413. body: game.lang.infoBox_diff + ' ' + game.lang.infoBox_diff_obs,
  414. img:
  415. '<table> <tr> <td style="border-right: 4px solid white"> <b>' +
  416. game.lang.difficulty +
  417. ':</b> 1' +
  418. ' </td> <td> <b>' +
  419. game.lang.difficulty +
  420. ':</b> 5' +
  421. ' </td> </tr> <tr> <td> <img width=100% src="' +
  422. game.image['c1-diff-1'].src +
  423. '"> ' +
  424. ' </td> <td style="border-left: 4px solid white"> <img width=100% src="' +
  425. game.image['c1-diff-5'].src +
  426. '"> </td> </tr> </table> <center> <br>' +
  427. game.lang.infoBox_diff_aux +
  428. '<center> <img width=50% src="' +
  429. game.image['map-c1s2'].src +
  430. '"> </center>',
  431. },
  432. squareTwo: {
  433. title: '<b>' + game.lang.difficulties + '</b>',
  434. body: game.lang.infoBox_diff,
  435. img:
  436. '<table> <tr> <td> <b>' +
  437. game.lang.difficulty +
  438. ':</b> 1' +
  439. ' </td> <td> <b>' +
  440. game.lang.difficulty +
  441. ':</b> 5' +
  442. ' </td> </tr> <tr> <td> <img width=100% src="' +
  443. game.image['s2-diff-1'].src +
  444. '"> ' +
  445. ' </td> <td style="border-left: 4px solid white"> <img width=100% src="' +
  446. game.image['s2-diff-5'].src +
  447. '"> </td> </tr> </table> <br>' +
  448. game.lang.infoBox_diff_aux +
  449. '<center> <img width=50% src="' +
  450. game.image['map-c1s2'].src +
  451. '"> </center>',
  452. },
  453. },
  454. gameMisc: {
  455. squareOne: {
  456. title: '<b>' + game.lang.show + ' ' + auxText + '</b>',
  457. body: game.lang.infoBox_misc_label,
  458. img:
  459. '<img class="mx-auto" width=80% src="' +
  460. game.image['s1-label'].src +
  461. '">',
  462. },
  463. circleOne: {
  464. title: '<b>' + game.lang.show + ' ' + auxText + '</b>',
  465. body: game.lang.infoBox_misc_label,
  466. img:
  467. '<img class="mx-auto" width=60% src="' +
  468. game.image['c1-label'].src +
  469. '">',
  470. },
  471. squareTwo: {
  472. title: '<b>' + game.lang.show + ' ' + auxText + '</b>',
  473. body: game.lang.infoBox_misc_rect,
  474. img:
  475. '<img class="mx-auto" width=100% src="' +
  476. game.image['s2-label'].src +
  477. '">',
  478. },
  479. },
  480. };
  481. // ------------- EVENTS
  482. game.event.add('click', this.onInputDown);
  483. game.event.add('mousemove', this.onInputOver);
  484. }
  485. },
  486. /**
  487. * Displays game menu information boxes.
  488. */
  489. showInfoBox: function (icon) {
  490. self.infoBox.style.display = 'block';
  491. const element =
  492. icon.id == 'gameOperation'
  493. ? self.infoBoxContent[icon.id]
  494. : self.infoBoxContent[icon.id][gameType];
  495. let msg =
  496. '<h3>' +
  497. element.title +
  498. '</h3>' +
  499. '<p align=justify>' +
  500. element.body +
  501. '</p>' +
  502. element.img;
  503. document.getElementById('infobox-content').innerHTML = msg;
  504. },
  505. /**
  506. * Saves information selected by the player
  507. *
  508. * @param {object} icon selected icon
  509. */
  510. load: function (icon) {
  511. const type = icon.iconType;
  512. if (audioStatus) game.audio.popSound.play();
  513. switch (type) {
  514. case 'gameMode':
  515. gameMode = icon.gameMode;
  516. break;
  517. case 'gameOperation':
  518. gameOperation = icon.gameOperation;
  519. break;
  520. case 'difficulty':
  521. gameDifficulty = icon.difficulty;
  522. break;
  523. case 'infoIcon':
  524. self.showInfoBox(icon);
  525. break;
  526. case 'selectionBox':
  527. if (icon.curFrame == 0) {
  528. icon.curFrame = 1;
  529. fractionLabel = true;
  530. } else {
  531. icon.curFrame = 0;
  532. fractionLabel = false;
  533. }
  534. game.render.all();
  535. break;
  536. case 'enter':
  537. if (debugMode) {
  538. console.log(
  539. '------------------------------' +
  540. '\nGame State: ' +
  541. gameType +
  542. '\nGame Mode: ' +
  543. gameMode +
  544. '\n------------------------------'
  545. );
  546. }
  547. mapPosition = 0; // Map position
  548. mapMove = true; // Move no next point
  549. completedLevels = 0; // Reset the game progress when entering a new level
  550. game.state.start('map');
  551. break;
  552. }
  553. },
  554. /**
  555. * Called by mouse click event
  556. *
  557. * @param {object} mouseEvent contains the mouse click coordinates
  558. */
  559. onInputDown: function (mouseEvent) {
  560. const x = game.math.getMouse(mouseEvent).x;
  561. const y = game.math.getMouse(mouseEvent).y;
  562. let overIcon;
  563. // Check if clicked on an icon
  564. for (let i in self.menuIcons) {
  565. if (game.math.isOverIcon(x, y, self.menuIcons[i])) {
  566. overIcon = i;
  567. break;
  568. }
  569. }
  570. // Update gui
  571. if (overIcon) {
  572. // If has clicked on an icon
  573. document.body.style.cursor = 'pointer';
  574. self.menuIcons.forEach((cur) => {
  575. if (cur.iconType == self.menuIcons[overIcon].iconType) {
  576. // If its in the same icon category
  577. if (cur == self.menuIcons[overIcon]) {
  578. // If its the clicked icon
  579. if (cur.iconType == 'gameMode' || cur.iconType == 'gameOperation')
  580. cur.curFrame = 1;
  581. else if (cur.iconType == 'difficulty') cur.fillColor = colors.blue;
  582. } else {
  583. if (cur.iconType == 'gameMode' || cur.iconType == 'gameOperation')
  584. cur.curFrame = 0;
  585. else if (cur.iconType == 'difficulty') cur.fillColor = colors.gray;
  586. }
  587. }
  588. });
  589. self.load(self.menuIcons[overIcon]);
  590. } else document.body.style.cursor = 'auto';
  591. navigationIcons.onInputDown(x, y);
  592. game.render.all();
  593. },
  594. /**
  595. * Called by mouse move event
  596. *
  597. * @param {object} mouseEvent contains the mouse move coordinates
  598. */
  599. onInputOver: function (mouseEvent) {
  600. const x = game.math.getMouse(mouseEvent).x;
  601. const y = game.math.getMouse(mouseEvent).y;
  602. let overIcon;
  603. // Check if pointer is over an icon
  604. for (let i in self.menuIcons) {
  605. if (game.math.isOverIcon(x, y, self.menuIcons[i])) {
  606. overIcon = i;
  607. break;
  608. }
  609. }
  610. // Update gui
  611. if (overIcon) {
  612. // If pointer is over icon
  613. document.body.style.cursor = 'pointer';
  614. self.menuIcons.forEach((cur) => {
  615. if (cur.iconType == self.menuIcons[overIcon].iconType) {
  616. // If its in the same icon category
  617. if (cur == self.menuIcons[overIcon]) {
  618. // If its the icon the pointer is over
  619. if (cur.iconType == 'enter')
  620. self.enterText.style = textStyles.h3__white;
  621. cur.scale = cur.originalScale * 1.1;
  622. } else {
  623. cur.scale = cur.originalScale;
  624. }
  625. }
  626. });
  627. } else {
  628. // If pointer is not over icon
  629. if (self.enterText) self.enterText.style = textStyles.h4_white;
  630. self.menuIcons.forEach((cur) => {
  631. cur.scale = cur.originalScale;
  632. });
  633. document.body.style.cursor = 'auto';
  634. }
  635. // Check navigation icons
  636. navigationIcons.onInputOver(x, y);
  637. game.render.all();
  638. },
  639. };