Переглянути джерело

Merge branch 'fix/c1-theme' of LInE/Ifractions-web into develop

laira 7 місяців тому
батько
коміт
f32a3f9c30

assets/img/characters/balloon/balloon.png → assets/img/NOT-USED/balloon.png


assets/img/characters/balloon/balloon_basket.png → assets/img/NOT-USED/balloon_basket.png


BIN
assets/img/NOT-USED/c1-A-h.png


BIN
assets/img/NOT-USED/c1-A.png


BIN
assets/img/NOT-USED/c1-B-h.png


BIN
assets/img/NOT-USED/c1-diff-1.png


assets/img/info_box/c1-diff-5.png → assets/img/NOT-USED/c1-diff-5.png


BIN
assets/img/NOT-USED/c1-label.png


BIN
assets/img/NOT-USED/circleOne.png


BIN
assets/img/NOT-USED/circleOne_1.png


BIN
assets/img/NOT-USED/circleOne_2.png


BIN
assets/img/characters/kite/kite.png


BIN
assets/img/characters/kite/kite_line.png


BIN
assets/img/characters/kite/kite_reverse.png


BIN
assets/img/icons_menu/circleOne.png


BIN
assets/img/icons_menu/circleOne_1.png


BIN
assets/img/icons_menu/circleOne_2.png


BIN
assets/img/info_box/c1-A-h.png


BIN
assets/img/info_box/c1-A.png


BIN
assets/img/info_box/c1-B-h.png


BIN
assets/img/info_box/c1-diff-1.png


BIN
assets/img/info_box/c1-diff-3.png


BIN
assets/img/info_box/c1-label.png


+ 25 - 5
assets/lang/en_US

@@ -2,8 +2,8 @@ audio=AUDIO
 aux_rectangle=Auxiliar Rectangles
 back_to_menu=Go back to main menu
 circle=Circles
-circleOne_intro_a=Where should the balloon be placed so the boy\ncan get to it?
-circleOne_intro_b=How many arcs must we select so that\nthe boy can reach the balloon?
+circleOne_intro_a=Where should the kite be placed so the boy\ncan get to it?
+circleOne_intro_b=How many arcs must we select so that\nthe boy can reach the kite?
 squareOne_intro_a=What size hole must be opened in the ground so that\nall the blocks that the tractor will take can fit?
 squareOne_intro_b=How many blocks must the tractor push to\nfill the hole in the ground?
 squareTwo_intro=Select portions in the two figures so that\none is equivalent to the other
@@ -19,14 +19,14 @@ game=Game
 game_mode=Game Mode
 game_modes=Game Modes
 good_job=Good Job
-infoBox_circleOne=<li>Flight themed, in this game the character is a child who wants to fly in a balloon to get to school.</li><li>This game represents a fraction like portion of a circle (arc). Thus, the selected arcs must be proportional to the path to be traversed.</li><li>The mathematical operations with fractions represented in this game are: addition (child going to the right) and subtraction (child going to the left), besides of both operations at the same level.</li>
+infoBox_circleOne=<li>Kite themed, in this game the character is a child who wants to fly a kite going to school.</li><li>This game represents a fraction like portion of a circle (arc). Thus, the selected arcs must be proportional to the path to be traversed.</li><li>The mathematical operations with fractions represented in this game are: addition (child going to the right) and subtraction (child going to the left), besides of both operations at the same level.</li>
 infoBox_diff=Choose game difficulty. When <b>higher value</b>, <b>higher overall difficulty</b> of the levels in the level map.
 infoBox_diff_aux=<b>About the level map:</b> Each game created generates 4 levels (illustrated as positions on a map) in ascending order of difficulty, based on that choice of difficulty.
 infoBox_diff_obs=<i>Note: Difficulty 1 only uses integers.</i>
 infoBox_misc_label=Choose whether or not the game should display fraction value.
 infoBox_misc_rect=Choose whether or not the game should show auxiliary blocks.
 infoBox_mode=Choose a variation of the current game:
-infoBox_mode_c1_A=Select the balloon position.
+infoBox_mode_c1_A=Select the kite position.
 infoBox_mode_c1_B=Select the arcs.
 infoBox_mode_s1_A=Select a portion of the soil.
 infoBox_mode_s1_B=Select a portion of the blocks.
@@ -63,4 +63,24 @@ results=RESULTS
 student=Student
 submit=Submit your assignment below
 professor=Professor
-scale=Scale
+scale=Scale
+s1_a_description=Select the ground
+s1_b_description=Select the blocks
+s2_a_description=The upper rectangle has more subdivisions
+s2_b_description=The lower rectangle has more subdivisions
+c1_a_description=Select the kite
+c1_b_description=Select the arcs
+op_plus_description=Addition of fractions
+op_minus_description=Subtraction of fractions
+op_mixed_description=Addition and subtraction of fractions
+op_equals_description=Equality of fractions
+diff_1_description=Fractions of type 1/1
+diff_2_description=Fractions of type 1/1 and 1/2
+diff_3_description=Fractions of type 1/1, 1/2, and 1/4
+s2_diff_1_description=The higher the difficulty, the more subdivisions
+s2_diff_2_description=The higher the difficulty, the more subdivisions
+s2_diff_3_description=The higher the difficulty, the more subdivisions
+s2_diff_4_description=The higher the difficulty, the more subdivisions
+s2_diff_5_description=The higher the difficulty, the more subdivisions
+label_description=Show fractions next to the figures
+info_description=Learn more

Різницю між файлами не показано, бо вона завелика
+ 25 - 5
assets/lang/es_ES


Різницю між файлами не показано, бо вона завелика
+ 25 - 5
assets/lang/fr_FR


Різницю між файлами не показано, бо вона завелика
+ 25 - 5
assets/lang/it_IT


Різницю між файлами не показано, бо вона завелика
+ 25 - 5
assets/lang/pt_BR


+ 82 - 68
js/games/circleOne.js

@@ -15,17 +15,17 @@
  * ........|.........
  * ......1,2,3....... = gameDifficulty
  *
- * Character : kid/balloon
- * Theme : flying in a balloon
- * Concept : 'How much the kid has to walk to get to the balloon?'
+ * Character : kid/kite
+ * Theme : getting the kite on the floor
+ * Concept : 'How much the kid has to walk to get to the kite?'
  * Represent fractions as : circles/arcs
  *
  * Game modes can be :
  *
- *   a : Player can place balloon position
- *       Place balloon in position (so the kid can get to it)
+ *   a : Player can place kite position
+ *       Place kite in position (so the kid can get to it)
  *   b : Player can select # of circles
- *       Selects number of circles (that represent distance kid needs to walk to get to the balloon)
+ *       Selects number of circles (that represent distance kid needs to walk to get to the kite)
  *
  * Operations can be :
  *
@@ -46,8 +46,8 @@ const circleOne = {
 
   circles: undefined,
   kid: undefined,
-  balloon: undefined,
-  basket: undefined,
+  kite: undefined,
+  kite_line: undefined,
   walkedPath: undefined,
 
   /**
@@ -72,7 +72,7 @@ const circleOne = {
         context.canvas.height - game.image['floor_grass'].width * 1.5;
       const defaultWidth = 1620;
 
-      // Initial 'x' coordinate for the kid and the baloon
+      // Initial 'x' coordinate for the kid and the kite
       const x =
         gameOperation === 'minus'
           ? context.canvas.width - defaultX - _pointWidth / 2
@@ -119,7 +119,7 @@ const circleOne = {
       divisorsList: '', // used in postScore (Accumulative)
 
       hasClicked: false, // Checks if user has clicked
-      checkAnswer: false, // Check kid inside ballon's basket
+      checkAnswer: false, // Check kid on top of kiteline
       isCorrect: false, // Informs answer is correct
       showEndInfo: false,
       endSignX: undefined,
@@ -139,7 +139,7 @@ const circleOne = {
       },
       invertDirection: undefined,
       animateKid: false,
-      animateBalloon: false,
+      animateKite: false, // TODO
       counter: undefined,
       walkOffsetX,
       angleOffset: 360 / walksPerDistanceBetweenPoints,
@@ -161,10 +161,10 @@ const circleOne = {
     this.utils.renderRoadBlocks();
     this.utils.renderRoad(validPath);
 
-    const [restart, balloonX] = this.utils.renderCircles(validPath);
+    const [restart, kiteX] = this.utils.renderCircles(validPath);
     this.restart = restart;
 
-    this.utils.renderCharacters(validPath, balloonX);
+    this.utils.renderCharacters(validPath, kiteX);
     this.utils.renderMainUI();
 
     if (!this.restart) {
@@ -183,14 +183,14 @@ const circleOne = {
       self.utils.animateKidHandler();
     }
 
-    // Check if kid is inside the basket
+    // Check if kid is on top of kite line
     if (self.control.checkAnswer) {
       self.utils.checkAnswerHandler();
     }
 
-    // Starts balloon flying animation
-    if (self.animation.animateBalloon) {
-      self.utils.animateBalloonHandler();
+    // Starts kite moving animation
+    if (self.animation.animateKite) {
+      self.utils.animateKiteHandler();
     }
 
     game.render.all();
@@ -282,7 +282,7 @@ const circleOne = {
     renderCircles: function (validPath) {
       let restart = false;
       let hasBaseDifficulty = false;
-      let balloonX = context.canvas.width / 2;
+      let kiteX = context.canvas.width / 2;
 
       const fractionX =
         validPath.x0 -
@@ -502,7 +502,7 @@ const circleOne = {
       let isBeforeMin = (isAfterMax = false);
       let finalPosition = self.control.correctX;
       // Restart if
-      // In Game mode 'a' and 'b' : Balloon position is out of bounds
+      // In Game mode 'a' and 'b' : Kite position is out of bounds
       if (gameOperation === 'minus') {
         isBeforeMin = finalPosition > validPath.x0;
         isAfterMax =
@@ -515,8 +515,8 @@ const circleOne = {
       if (isBeforeMin || isAfterMax) restart = true;
 
       if (gameMode === 'b') {
-        // If game is type (b), select a random balloon place
-        balloonX = validPath.x0;
+        // If game is type (b), select a random kite place
+        kiteX = validPath.x0;
 
         self.control.correctIndex = game.math.randomInRange(
           self.control.numberOfPlusFractions,
@@ -524,16 +524,16 @@ const circleOne = {
         );
 
         for (let i = 0; i < self.control.correctIndex; i++) {
-          balloonX +=
+          kiteX +=
             self.circles.list[i].info.distance *
             self.circles.list[i].info.direc;
         }
 
-        finalPosition = balloonX;
+        finalPosition = kiteX;
 
         self.blocks.list.forEach((cur) => {
-          self.utils.fillCurrentBlock(balloonX, cur.x, cur);
-          if (self.utils.isOverBlock(balloonX, cur.x, cur.width, cur))
+          self.utils.fillCurrentBlock(kiteX, cur.x, cur);
+          if (self.utils.isOverBlock(kiteX, cur.x, cur.width, cur))
             self.blocks.cur = cur;
         });
 
@@ -551,9 +551,9 @@ const circleOne = {
         if (isBeforeMin || isAfterMax) restart = true;
       }
 
-      return [restart, balloonX];
+      return [restart, kiteX];
     },
-    renderCharacters: function (validPath, balloonX) {
+    renderCharacters: function (validPath, kiteX) {
       // KID
       self.kid = game.add.sprite(
         validPath.x0,
@@ -582,25 +582,19 @@ const circleOne = {
         self.kid.animation = self.animation.list.right;
       }
 
-      // BALLOON
-      self.balloon = game.add.image(
-        balloonX,
-        validPath.y0 - 295,
-        'balloon',
-        1.5,
-        0.5
-      );
-      self.balloon.alpha = 0.5;
-      self.balloon.anchor(0.5, 0.5);
-
-      self.basket = game.add.image(
-        balloonX,
-        validPath.y0 - 95,
-        'balloon_basket',
-        1.5
-      );
-      self.basket.alpha = 0.8;
-      self.basket.anchor(0.5, 0.5);
+      // KITE
+      self.kite = game.add.image(kiteX, validPath.y0 - 295, 'kite', 1.8, 0.5);
+      self.kite.alpha = 0.5;
+      self.kite.anchor(0, 0.5);
+
+      self.kite_line = game.add.image(kiteX, validPath.y0 - 30, 'kite_line', 2);
+      self.kite_line.alpha = 0.8;
+      self.kite_line.anchor(0.5, 0);
+
+      if (gameMode === 'b') {
+        self.kite_line.alpha = 1;
+        self.kite.alpha = 1;
+      }
     },
     renderMainUI: function () {
       // Help pointer
@@ -625,7 +619,7 @@ const circleOne = {
     renderOperationUI: function () {
       /**
        * if game mode A:
-       * - left: selected balloon position (user selection)
+       * - left: selected kite position (user selection)
        * - right: correct sum of stack of arcs (pre-set)
        *
        * if game mode B:
@@ -674,7 +668,6 @@ const circleOne = {
       };
 
       const renderStackFractions = (lastIndex) => {
-        const operator = gameOperation === 'minus' ? '-' : '+';
         const index = lastIndex;
         const blocks = index + 1;
 
@@ -683,11 +676,10 @@ const circleOne = {
         const values = [];
         let valueReal = 0;
         let fracNomin = (fracDenomin = fracLine = '');
-
         for (let i = 0; i < blocks; i++) {
           const m = self.circles.list[i].info.fraction.denominator || 1;
           const temp = self.circles.list[i].info.fraction.nominator || 0;
-          const n = gameOperation === 'minus' ? -temp : +temp;
+          const n = temp < 0 ? -temp : +temp;
           const nm = n / m;
           nominators[i] = n + 0;
           denominators[i] = m + 0;
@@ -699,6 +691,8 @@ const circleOne = {
           const valueReal = values[i];
           const valueFloor = Math.floor(valueReal);
           const valueRest = valueReal - valueFloor;
+          const operator =
+            self.circles.list[i].info.fraction.nominator < 0 ? '-' : '+';
 
           if (i > 0 || gameOperation === 'minus') {
             fracNomin += ' ';
@@ -963,12 +957,29 @@ const circleOne = {
 
       game.animation.stop(self.kid.animation[0]);
 
-      self.control.isCorrect = game.math.isOverlap(self.basket, self.kid);
+      self.control.isCorrect = game.math.isOverlap(self.kite_line, self.kid);
 
       const x = self.utils.renderOperationUI();
       if (self.control.isCorrect) {
         completedLevels++;
-        self.kid.curFrame = self.kid.curFrame < 12 ? 24 : 25;
+        // self.kid.curFrame = self.kid.curFrame < 12 ? 24 : 25;
+        // console.log(self.kid);
+        self.kid.alpha = 0;
+        const kidStanding = game.add.sprite(
+          self.kid.x,
+          self.kid.y,
+          'kid_standing',
+          5,
+          1.2
+        );
+        kidStanding.anchor(0.5, 0.8);
+        self.kid = kidStanding;
+        self.kid.alpha = 1;
+
+        self.kite_line.alpha = 0;
+        self.kite.x += 25;
+        self.kite.y -= 40;
+
         if (audioStatus) game.audio.okSound.play();
         game.add
           .image(x + 50, context.canvas.height / 3, 'answer_correct')
@@ -986,19 +997,22 @@ const circleOne = {
       self.control.checkAnswer = false;
       self.animation.counter = 0;
 
-      self.animation.animateBalloon = true;
+      self.animation.animateKite = true;
     },
-    animateBalloonHandler: function () {
+    animateKiteHandler: function () {
       self.animation.counter++;
-      self.balloon.y -= 2;
-      self.basket.y -= 2;
-
-      if (self.control.isCorrect) self.kid.y -= 2;
 
+      if (!self.control.isCorrect) {
+        self.kite.y -= 2;
+        self.kite_line.y -= 2;
+      }
+      if (self.animation.counter % 40 === 0) {
+        const kiteMovement = self.animation.counter % 80 === 0 ? -3 : 3;
+        self.kite.y += kiteMovement;
+      }
       if (self.animation.counter === 100) {
         self.utils.renderEndUI();
         self.control.showEndInfo = true;
-
         if (self.control.isCorrect) canGoToNextMapPosition = true;
         else canGoToNextMapPosition = false;
       }
@@ -1036,8 +1050,8 @@ const circleOne = {
       if (!self.control.hasClicked) {
         // On gameMode (a)
         if (gameMode === 'a') {
-          self.balloon.x = cur;
-          self.basket.x = cur;
+          self.kite.x = cur;
+          self.kite_line.x = cur;
         }
 
         // On gameMode (b)
@@ -1073,8 +1087,8 @@ const circleOne = {
 
         navigation.disableIcon(navigation.showAnswerIcon);
 
-        self.balloon.alpha = 1;
-        self.basket.alpha = 1;
+        self.kite.alpha = 1;
+        self.kite_line.alpha = 1;
         self.walkedPath[self.control.curWalkedPath].alpha = 1;
 
         self.control.hasClicked = true;
@@ -1227,7 +1241,7 @@ const circleOne = {
           self.road.width
         );
         if (isValidX) {
-          // GAME MODE A : balloon follow mouse
+          // GAME MODE A : kite follow mouse
           self.blocks.cur = self.blocks.list[0];
           self.blocks.list.forEach((cur) => {
             self.utils.fillCurrentBlock(x, cur.x, cur);
@@ -1235,8 +1249,8 @@ const circleOne = {
               self.blocks.cur = cur;
           });
           const newX = self.blocks.cur.x + self.blocks.cur.width;
-          self.balloon.x = newX;
-          self.basket.x = newX;
+          self.kite.x = newX;
+          self.kite_line.x = newX;
 
           document.body.style.cursor = 'pointer';
         } else {
@@ -1316,8 +1330,8 @@ const circleOne = {
         self.circles.list.length +
         ', valCircles: ' +
         self.control.divisorsList +
-        ' balloonX: ' +
-        self.basket.x +
+        ' kiteX: ' +
+        self.kite_line.x +
         ', selIndex: ' +
         self.control.selectedIndex;
 

+ 41 - 2
js/globals/globals_control.js

@@ -170,6 +170,17 @@ const gameList = [
       customMenu: {
         gameModeBtn: ['mode_0', 'mode_1'],
         gameOperationBtn: ['operation_plus', 'operation_minus'],
+        gameModeDescription: ['s1_a_description', 's1_b_description'],
+        gameOperationDescription: [
+          'op_plus_description',
+          'op_minus_description',
+        ],
+        gameDifficultyDescription: [
+          'diff_1_description',
+          'diff_2_description',
+          'diff_3_description',
+        ],
+        gameLabelDescription: 'label_description',
         auxiliarTitle: (x, y, offsetW, offsetH) => {
           game.add.text(
             x + 5 * offsetW,
@@ -312,6 +323,18 @@ const gameList = [
       },
       customMenu: {
         gameModeBtn: ['mode_2', 'mode_3'],
+        gameModeDescription: ['c1_a_description', 'c1_b_description'],
+        gameOperationDescription: [
+          'op_plus_description',
+          'op_minus_description',
+          'op_mixed_description',
+        ],
+        gameDifficultyDescription: [
+          'diff_1_description',
+          'diff_2_description',
+          'diff_3_description',
+        ],
+        gameLabelDescription: 'label_description',
         gameOperationBtn: [
           'operation_plus',
           'operation_minus',
@@ -359,7 +382,7 @@ const gameList = [
                 <img width=100% src="${game.image['c1-diff-1'].src}">
               </td>
               <td style="border-left: 4px solid white">
-                <img width=100% src="${game.image['c1-diff-5'].src}">
+                <img width=100% src="${game.image['c1-diff-3'].src}">
               </td>
             </tr>
           </table>
@@ -413,7 +436,13 @@ const gameList = [
           3,
         ],
         character: () => {
-          const char = game.add.sprite(0, -152, 'kid_running', 0, 1.05);
+          const char = game.add.sprite(
+            0,
+            context.canvas.height - 240,
+            'kid_running',
+            0,
+            1.05
+          );
           char.anchor(0.5, 0.5);
           return char;
         },
@@ -448,6 +477,16 @@ const gameList = [
       customMenu: {
         gameModeBtn: ['mode_4', 'mode_5'],
         gameOperationBtn: ['operation_equals'],
+        gameModeDescription: ['s2_a_description', 's2_b_description'],
+        gameOperationDescription: ['op_equals_description'],
+        gameDifficultyDescription: [
+          's2_diff_1_description',
+          's2_diff_2_description',
+          's2_diff_3_description',
+          's2_diff_4_description',
+          's2_diff_5_description',
+        ],
+        gameLabelDescription: 'label_description',
         auxiliarTitle: (x, y, offsetW, offsetH) => {
           game.add.text(
             x + 5 * offsetW,

+ 5 - 3
js/globals/globals_tokens.js

@@ -173,7 +173,7 @@ const url = {
       ['c1-A-h', baseUrl + 'info_box/c1-A-h.png'],
       ['c1-B-h', baseUrl + 'info_box/c1-B-h.png'],
       ['c1-diff-1', baseUrl + 'info_box/c1-diff-1.png'],
-      ['c1-diff-5', baseUrl + 'info_box/c1-diff-5.png'],
+      ['c1-diff-3', baseUrl + 'info_box/c1-diff-3.png'],
       ['c1-label', baseUrl + 'info_box/c1-label.png'],
       ['map-c1s2', baseUrl + 'info_box/map-c1s2.png'],
       ['map-s1', baseUrl + 'info_box/map-s1.png'],
@@ -257,11 +257,13 @@ const url = {
       ['house', baseUrl + 'scene/building_house.png'],
       ['school', baseUrl + 'scene/building_school.png'],
       // Game images
-      ['balloon', baseUrl + 'characters/balloon/balloon.png'],
-      ['balloon_basket', baseUrl + 'characters/balloon/balloon_basket.png'],
+      ['kite', baseUrl + 'characters/kite/kite.png'],
+      ['kite_reverse', baseUrl + 'characters/kite/kite_reverse.png'],
+      ['kite_line', baseUrl + 'characters/kite/kite_line.png'],
     ],
     sprite: [
       // Game sprites
+      ['kid_standing', baseUrl + 'characters/kid/lost.png', 6],
       ['kid_running', baseUrl + 'characters/kid/running.png', 12],
     ],
     audio: [],

+ 33 - 2
js/menus/menu_custom.js

@@ -39,6 +39,13 @@ const customMenuState = {
         ...textStyles.h1_,
         fill: colors.green,
       });
+      // Subtitle : <game mode>
+      this.lbl_description = game.add.text(
+        context.canvas.width / 2,
+        170,
+        '',
+        textStyles.h2_
+      );
 
       // Loads navigation icons
       navigation.add.left(['back'], 'menu');
@@ -58,7 +65,7 @@ const customMenuState = {
       let y = getFrameInfo().y;
 
       this.renderSectionTitles(x, y, offsetW, offsetH);
-      this.renderCheckBox(x, y, offsetW, offsetH);
+      this.renderCheckBox(x, y, offsetW, offsetH, curGame);
       this.renderModeSection(x, y, offsetW, offsetH, curGame);
       this.renderOperationSection(x, y, offsetW, offsetH, curGame);
       this.renderDifficultySection(x, y, offsetW, offsetH, curGame);
@@ -213,6 +220,7 @@ const customMenuState = {
     if (overIcon) {
       // If pointer is over icon
       document.body.style.cursor = 'pointer';
+      self.showTitle(self.menuIcons[overIcon]);
       self.menuIcons.forEach((cur) => {
         if (cur.iconType == self.menuIcons[overIcon].iconType) {
           // If its in the same icon category
@@ -228,6 +236,7 @@ const customMenuState = {
       });
     } else {
       // If pointer is not over icon
+      self.clearTitle();
       if (self.enterText) self.enterText.style = textStyles.btn;
       self.menuIcons.forEach((cur) => {
         cur.scale = cur.initialScale;
@@ -275,7 +284,7 @@ const customMenuState = {
     gameList[gameId].assets.customMenu.auxiliarTitle(x, y, offsetW, offsetH);
   },
 
-  renderCheckBox: function (x, y, offsetW, offsetH) {
+  renderCheckBox: function (x, y, offsetW, offsetH, curGame) {
     y += 60;
     const frame = showFractions ? 1 : 0;
 
@@ -288,6 +297,8 @@ const customMenuState = {
     );
     selectionBox.anchor(0.5, 0.5);
     selectionBox.iconType = 'selectionBox';
+    selectionBox.description = curGame.assets.customMenu.gameLabelDescription;
+
     self.menuIcons.push(selectionBox);
   },
 
@@ -312,6 +323,7 @@ const customMenuState = {
       );
       icon.anchor(0.5, 0.5);
 
+      icon.description = curGame.assets.customMenu.gameModeDescription[i];
       icon.gameMode = curGame.gameMode[i];
       icon.iconType = 'gameMode';
 
@@ -347,6 +359,7 @@ const customMenuState = {
         1
       );
       icon.anchor(0.5, 0.5);
+      icon.description = curGame.assets.customMenu.gameOperationDescription[i];
 
       icon.gameOperation = curGame.gameOperation[i];
       icon.iconType = 'gameOperation';
@@ -379,6 +392,7 @@ const customMenuState = {
 
       const icon = game.add.sprite(curX, y - 5, 'btn_square', 1, 0.8);
       icon.anchor(0.5, 0.5);
+      icon.description = curGame.assets.customMenu.gameDifficultyDescription[i];
       icon.difficulty = i + 1;
       icon.iconType = 'difficulty';
 
@@ -462,4 +476,21 @@ const customMenuState = {
 
     document.querySelector('.ifr-modal__infobox').innerHTML = content;
   },
+
+  /**
+   * Display the description the game mode on screen
+   *
+   * @param {object} icon icon for the game mode
+   */
+  showTitle: function (icon) {
+    if (icon.iconType !== 'infoIcon' && icon.iconType !== 'enter')
+      self.lbl_description.name = game.lang[icon.description];
+  },
+
+  /**
+   * Remove the description the game mode from screen
+   */
+  clearTitle: function () {
+    self.lbl_description.name = '';
+  },
 };

+ 20 - 43
js/screens/end.js

@@ -11,8 +11,7 @@ const endState = {
   control: undefined,
 
   character: undefined,
-  balloon: undefined,
-  basket: undefined,
+  kite: undefined,
 
   /**
    * Main code
@@ -76,43 +75,24 @@ const endState = {
 
     self.control.counter++;
 
-    // Balloon falling
-    if (self.control.preAnimate) {
-      const speedY = 3,
-        speedX = 2;
-      if (self.basket.y < context.canvas.height - 240) {
-        self.balloon.y += speedY;
-        self.basket.y += speedY;
-        self.character.y += speedY;
-
-        self.balloon.x += speedX;
-        self.basket.x += speedX;
-        self.character.x += speedX;
-      } else {
-        self.control.preAnimate = false;
-        self.control.animate = true;
-        game.animation.play(self.character.animation[0]);
-      }
-    }
-
-    if (gameName == 'circleOne') {
-      if (self.control.counter % 40 === 0) {
-        self.balloon.x += 5 * self.control.direc;
-        self.control.direc *= -1;
-      }
-    }
-
     // Character running
     if (self.control.animate) {
       if (self.character.x <= 1550) {
         self.character.x += 4;
+        if (self.kite) self.kite.x += 4;
       } else {
         self.control.animate = false;
         game.animation.stop(self.character.animation[0]);
         self.character.alpha = 0;
+        if (self.kite) self.kite.alpha = 0;
         self.control.waitUserAction = true;
         self.utils.renderEndUI();
       }
+
+      if (self.kite && self.character.x % 40 === 0) {
+        const kiteMovement = self.character.x % 80 === 0 ? 3 : -3;
+        self.kite.y += kiteMovement;
+      }
     }
 
     if (!moodle && self.control.endLevel) {
@@ -149,7 +129,7 @@ const endState = {
         3
       );
 
-      // percentage label
+      // Percentage label
       game.add.text(
         context.canvas.width - x0 + 160,
         y0 + 33,
@@ -168,23 +148,20 @@ const endState = {
     renderCharacters: () => {
       gameList[gameId].assets.end.building();
 
+      if (gameName === 'circleOne') {
+        self.kite = game.add.image(
+          0 + 10,
+          context.canvas.height - 240 + 20,
+          'kite_reverse',
+          1.8,
+          1
+        );
+        self.kite.anchor(1, 1);
+      }
+
       self.character = gameList[gameId].assets.end.character();
       self.character.animation =
         gameList[gameId].assets.end.characterAnimation();
-
-      if (gameName === 'circleOne') {
-        self.control.preAnimate = true;
-        self.control.animate = false;
-
-        // Balloon
-        self.balloon = game.add.image(0, -350, 'balloon', 1.5);
-        self.balloon.anchor(0.5, 0.5);
-
-        self.basket = game.add.image(0, -150, 'balloon_basket', 1.5);
-        self.basket.anchor(0.5, 0.5);
-
-        self.character.curFrame = 6;
-      }
     },
     renderEndUI: () => {
       const btnY = context.canvas.height / 2;