Browse Source

feature: c1 - set floor block behaviour in minus operation (reverse)

lairaalmas 2 months ago
parent
commit
56d315c6d1
1 changed files with 357 additions and 308 deletions
  1. 357 308
      js/games/circleOne.js

+ 357 - 308
js/games/circleOne.js

@@ -88,7 +88,8 @@ const circleOne = {
     this.road = roadMapper();
 
     const blocksMapper = () => {
-      const width = this.road.width / this.road.numberOfBlocks;
+      let width = this.road.width / this.road.numberOfBlocks;
+      if (gameOperation === 'minus') width = -width;
       const height = 50;
       return { width, height, list: [], cur: undefined };
     };
@@ -111,6 +112,8 @@ const circleOne = {
     };
 
     this.control = {
+      directionModifier: gameOperation === 'minus' ? -1 : 1,
+
       correctX: x0, // Correct position (accumulative)
       nextX: undefined, // Next point position
       divisorsList: '', // used in postScore (Accumulative)
@@ -199,7 +202,7 @@ const circleOne = {
         const block = game.add.geom.rect(
           self.road.x + i * self.blocks.width,
           self.road.y,
-          self.blocks.width,
+          self.blocks.width, // If gameOperation is minus, block width is negative
           self.blocks.height,
           'transparent',
           0.5,
@@ -213,13 +216,14 @@ const circleOne = {
     // RENDERS
     renderRoad: function (validPath) {
       const offset = 40;
-      const directionModifier = gameOperation === 'minus' ? -1 : 1;
       for (let i = 0; i <= 5; i++) {
         // Gray place
         game.add
           .sprite(
             validPath.x0 +
-              i * validPath.distanceBetweenPoints * directionModifier,
+              i *
+                validPath.distanceBetweenPoints *
+                self.control.directionModifier,
             validPath.y0,
             'map_place',
             0,
@@ -229,7 +233,7 @@ const circleOne = {
         // White circle behind number
         const curX =
           validPath.x0 +
-          i * validPath.distanceBetweenPoints * directionModifier;
+          i * validPath.distanceBetweenPoints * self.control.directionModifier;
         game.add.geom
           .circle(
             curX,
@@ -252,11 +256,16 @@ const circleOne = {
           0
         );
         // Number
-        game.add.text(curX, validPath.y0 + 60 + offset, i * directionModifier, {
-          ...textStyles.h2_,
-          font: 'bold ' + textStyles.h2_.font,
-          fill: directionModifier === 1 ? colors.green : colors.red,
-        });
+        game.add.text(
+          curX,
+          validPath.y0 + 60 + offset,
+          i * self.control.directionModifier,
+          {
+            ...textStyles.h2_,
+            font: 'bold ' + textStyles.h2_.font,
+            fill: gameOperation === 'minus' ? colors.red : colors.green,
+          }
+        );
       }
 
       self.utils.renderWalkedPath(
@@ -275,9 +284,9 @@ const circleOne = {
       let hasBaseDifficulty = false;
       let balloonX = context.canvas.width / 2;
 
-      const directionModifier = gameOperation === 'minus' ? -1 : 1;
       const fractionX =
-        validPath.x0 - (self.circles.diameter - 10) * directionModifier;
+        validPath.x0 -
+        (self.circles.diameter - 10) * self.control.directionModifier;
       const font = {
         ...textStyles.h2_,
         font: 'bold ' + textStyles.h2_.font,
@@ -292,7 +301,7 @@ const circleOne = {
 
       const total = game.math.randomInRange(min, max); // Total number of circles
 
-      // for mode 'b'
+      // For mode 'b'
       self.control.numberOfPlusFractions = game.math.randomInRange(
         1,
         total - 1
@@ -793,279 +802,279 @@ const circleOne = {
 
       return endSignX;
     },
-    // renderOperationUI_new: () => {
-    //   /**
-    //    * if game mode A:
-    //    * - left: selected balloon position (user selection)
-    //    * - right: correct sum of stack of arcs (pre-set)
-    //    *
-    //    * if game mode B:
-    //    * - left: line created from the stack of arcs (user selection)
-    //    * - right: baloon position (pre-set)
-    //    */
-
-    //   const divisor = gameDifficulty == 3 ? 4 : gameDifficulty;
-
-    //   // const renderFloorFractions = (lastIndex, divisor) => {
-    //   //   const operator = gameOperation === 'minus' ? '-' : '+';
-    //   //   const index = lastIndex;
-    //   //   const blocks = index + 1;
-
-    //   //   const valueReal = blocks / divisor;
-    //   //   const valueFloor = Math.floor(valueReal);
-    //   //   const valueRest = valueReal - valueFloor;
-
-    //   //   let fracNomin = (fracDenomin = fracLine = '');
-    //   //   // adds sign on the left of the equation
-    //   //   if (gameOperation === 'minus') {
-    //   //     fracNomin += ' ';
-    //   //     fracDenomin += ' ';
-    //   //     fracLine += operator;
-    //   //   }
-    //   //   // 1 _ _
-    //   //   if (valueFloor) {
-    //   //     fracNomin += ' ';
-    //   //     fracDenomin += ' ';
-    //   //     fracLine += valueFloor;
-    //   //   }
-    //   //   // _ + _
-    //   //   if (valueFloor && valueRest) {
-    //   //     fracNomin += ' ';
-    //   //     fracDenomin += ' ';
-    //   //     fracLine += operator;
-    //   //   }
-    //   //   // _ _ 1/5
-    //   //   if (valueRest) {
-    //   //     fracNomin += `${valueRest * divisor}`;
-    //   //     fracDenomin += `${divisor}`;
-    //   //     fracLine += '-';
-    //   //   }
-
-    //   //   return [fracNomin, fracDenomin, fracLine, valueReal];
-    //   // };
-
-    //   const renderStackFractions = (lastIndex) => {
-    //     const operator = gameOperation === 'minus' ? '-' : '+';
-    //     const index = lastIndex;
-    //     const blocks = index + 1;
-
-    //     const nominators = [];
-    //     const denominators = [];
-    //     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 nm = n / m;
-    //       nominators[i] = n + 0;
-    //       denominators[i] = m + 0;
-    //       values[i] = nm;
-    //       valueReal += nm;
-    //     }
-
-    //     for (let i = 0; i < blocks; i++) {
-    //       const valueReal = values[i];
-    //       const valueFloor = Math.floor(valueReal);
-    //       const valueRest = valueReal - valueFloor;
-
-    //       if (i > 0 || gameOperation === 'minus') {
-    //         fracNomin += ' ';
-    //         fracDenomin += ' ';
-    //         fracLine += operator;
-    //       }
-    //       if (valueFloor && !valueRest) {
-    //         fracNomin += ' ';
-    //         fracDenomin += ' ';
-    //         fracLine += valueFloor;
-    //       }
-    //       if (valueRest) {
-    //         fracNomin += `${nominators[i]}`;
-    //         fracDenomin += `${denominators[i]}`;
-    //         fracLine += '-';
-    //       }
-    //     }
-
-    //     console.log(fracNomin, fracDenomin, fracLine, valueReal);
-    //     return [fracNomin, fracDenomin, fracLine, valueReal];
-    //   };
-
-    //   const xyz = () => {
-    //     const x0 = +self.road.x;
-    //     // console.log(x0);
-    //     const xEnd = +self.road.width;
-    //     // console.log(xEnd);
-    //     const blockWidth = +xEnd / 5;
-    //     // console.log(blockWidth);
-    //     const selectedX = +self.balloon.x;
-    //     // console.log(selectedX);
-
-    //     let count = (selectedX - x0) / blockWidth;
-    //     count = Math.floor(count);
-    //     // console.log(count);
-    //     return count;
-    //   };
-
-    //   // Initial setup
-    //   const font = textStyles.fraction;
-    //   font.fill = colors.black;
-
-    //   const padding = 100;
-    //   const offsetX = 100;
-    //   const widthOfChar = 35;
-
-    //   const x0 = padding;
-    //   const y0 = context.canvas.height / 3;
-    //   let nextX = x0;
-
-    //   const cardHeight = 400;
-    //   const cardX = x0 - padding;
-    //   const cardY = y0;
-
-    //   const renderList = [];
-
-    //   // Render Card
-    //   const card = game.add.geom.rect(
-    //     cardX,
-    //     cardY,
-    //     0,
-    //     cardHeight,
-    //     colors.blueLight,
-    //     0.5,
-    //     colors.blueDark,
-    //     8
-    //   );
-    //   card.id = 'card';
-    //   card.anchor(0, 0.5);
-    //   renderList.push(card);
-
-    //   // Fraction setup
-    //   // console.clear();
-    //   // const [floorNominators, floorDenominators, floorLines, floorValue] =
-    //   //   renderFloorFractions(self.floor.selectedIndex, divisor);
-    //   console.log(self);
-    //   const [stackNominators, stackDenominators, stackLines, stackValue] =
-    //     renderStackFractions(self.circles.cur - 1);
-
-    //   const renderFloorOperationLine = (x) => {
-    //     font.fill = colors.black;
-    //     const floorNom = game.add.text(x + offsetX / 2, y0, '', font, 60);
-    //     const floorDenom = game.add.text(
-    //       x + offsetX / 2,
-    //       y0 + 70,
-    //       '',
-    //       font,
-    //       60
-    //     );
-    //     const floorLin = game.add.text(
-    //       x + offsetX / 2,
-    //       y0 + 35,
-    //       xyz(),
-    //       font,
-    //       60
-    //     );
-    //     renderList.push(floorNom);
-    //     renderList.push(floorDenom);
-    //     renderList.push(floorLin);
-    //     return;
-    //     // font.fill = colors.black;
-    //     // const floorNom = game.add.text(
-    //     //   x + offsetX / 2,
-    //     //   y0,
-    //     //   floorNominators,
-    //     //   font,
-    //     //   60
-    //     // );
-    //     // const floorDenom = game.add.text(
-    //     //   x + offsetX / 2,
-    //     //   y0 + 70,
-    //     //   floorDenominators,
-    //     //   font,
-    //     //   60
-    //     // );
-    //     // const floorLin = game.add.text(
-    //     //   x + offsetX / 2,
-    //     //   y0 + 35,
-    //     //   floorLines,
-    //     //   font,
-    //     //   60
-    //     // );
-    //     // renderList.push(floorNom);
-    //     // renderList.push(floorDenom);
-    //     // renderList.push(floorLin);
-    //   };
-    //   const renderStackOperationLine = (x) => {
-    //     font.fill = colors.black;
-    //     const stackNom = game.add.text(
-    //       x + offsetX / 2,
-    //       y0,
-    //       stackNominators,
-    //       font,
-    //       60
-    //     );
-    //     const stackDenom = game.add.text(
-    //       x + offsetX / 2,
-    //       y0 + 70,
-    //       stackDenominators,
-    //       font,
-    //       60
-    //     );
-    //     const stackLin = game.add.text(
-    //       x + offsetX / 2,
-    //       y0 + 35,
-    //       stackLines,
-    //       font,
-    //       60
-    //     );
-    //     renderList.push(stackNom);
-    //     renderList.push(stackDenom);
-    //     renderList.push(stackLin);
-    //   };
-
-    //   // Render LEFT part of the operation
-    //   // if (gameMode === 'a') renderFloorOperationLine(x0);
-    //   // else renderStackOperationLine(x0);
-    //   renderFloorOperationLine(x0);
-
-    //   // let curNominators = gameMode === 'a' ? floorNominators : stackNominators;
-    //   let curNominators = '1';
-    //   nextX = x0 + (curNominators.length + 2) * widthOfChar;
-
-    //   // Render middle sign - equal by default
-    //   font.fill = colors.green;
-    //   let comparisonSign = '=';
-    //   // Render middle sign - if not equal
-    //   // if (floorValue != stackValue) {
-    //   //   font.fill = colors.red;
-    //   //   let leftSideIsLarger = floorValue > stackValue;
-    //   //   if (gameMode === 'b') leftSideIsLarger = !leftSideIsLarger;
-    //   //   if (gameOperation === 'minus') leftSideIsLarger = !leftSideIsLarger;
-    //   //   comparisonSign = leftSideIsLarger ? '>' : '<';
-    //   // }
-    //   renderList.push(game.add.text(nextX, y0 + 35, comparisonSign, font));
-
-    //   // Render RIGHT part of the operationf
-    //   // if (gameMode === 'a')
-    //   renderStackOperationLine(nextX);
-    //   // else renderFloorOperationLine(nextX);
-
-    //   curNominators = gameMode === 'a' ? stackNominators : floorNominators;
-    //   const resultWidth = (curNominators.length + 2) * widthOfChar;
-
-    //   const cardWidth = nextX - x0 + resultWidth + padding * 2;
-    //   card.width = cardWidth;
-
-    //   const endSignX = (context.canvas.width - cardWidth) / 2 + cardWidth;
-
-    //   // Center Card
-    //   moveList(renderList, (context.canvas.width - cardWidth) / 2, 0);
-
-    //   self.fractionOperationUI = renderList;
-
-    //   return endSignX;
-    // },
+    renderOperationUI_new: () => {
+      /**
+       * if game mode A:
+       * - left: selected balloon position (user selection)
+       * - right: correct sum of stack of arcs (pre-set)
+       *
+       * if game mode B:
+       * - left: line created from the stack of arcs (user selection)
+       * - right: baloon position (pre-set)
+       */
+
+      const divisor = gameDifficulty == 3 ? 4 : gameDifficulty;
+
+      // const renderFloorFractions = (lastIndex, divisor) => {
+      //   const operator = gameOperation === 'minus' ? '-' : '+';
+      //   const index = lastIndex;
+      //   const blocks = index + 1;
+
+      //   const valueReal = blocks / divisor;
+      //   const valueFloor = Math.floor(valueReal);
+      //   const valueRest = valueReal - valueFloor;
+
+      //   let fracNomin = (fracDenomin = fracLine = '');
+      //   // adds sign on the left of the equation
+      //   if (gameOperation === 'minus') {
+      //     fracNomin += ' ';
+      //     fracDenomin += ' ';
+      //     fracLine += operator;
+      //   }
+      //   // 1 _ _
+      //   if (valueFloor) {
+      //     fracNomin += ' ';
+      //     fracDenomin += ' ';
+      //     fracLine += valueFloor;
+      //   }
+      //   // _ + _
+      //   if (valueFloor && valueRest) {
+      //     fracNomin += ' ';
+      //     fracDenomin += ' ';
+      //     fracLine += operator;
+      //   }
+      //   // _ _ 1/5
+      //   if (valueRest) {
+      //     fracNomin += `${valueRest * divisor}`;
+      //     fracDenomin += `${divisor}`;
+      //     fracLine += '-';
+      //   }
+
+      //   return [fracNomin, fracDenomin, fracLine, valueReal];
+      // };
+
+      const renderStackFractions = (lastIndex) => {
+        const operator = gameOperation === 'minus' ? '-' : '+';
+        const index = lastIndex;
+        const blocks = index + 1;
+
+        const nominators = [];
+        const denominators = [];
+        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 nm = n / m;
+          nominators[i] = n + 0;
+          denominators[i] = m + 0;
+          values[i] = nm;
+          valueReal += nm;
+        }
+
+        for (let i = 0; i < blocks; i++) {
+          const valueReal = values[i];
+          const valueFloor = Math.floor(valueReal);
+          const valueRest = valueReal - valueFloor;
+
+          if (i > 0 || gameOperation === 'minus') {
+            fracNomin += ' ';
+            fracDenomin += ' ';
+            fracLine += operator;
+          }
+          if (valueFloor && !valueRest) {
+            fracNomin += ' ';
+            fracDenomin += ' ';
+            fracLine += valueFloor;
+          }
+          if (valueRest) {
+            fracNomin += `${nominators[i]}`;
+            fracDenomin += `${denominators[i]}`;
+            fracLine += '-';
+          }
+        }
+
+        console.log(fracNomin, fracDenomin, fracLine, valueReal);
+        return [fracNomin, fracDenomin, fracLine, valueReal];
+      };
+
+      const xyz = () => {
+        const x0 = +self.road.x;
+        // console.log(x0);
+        const xEnd = +self.road.width;
+        // console.log(xEnd);
+        const blockWidth = +xEnd / 5;
+        // console.log(blockWidth);
+        const selectedX = +self.balloon.x;
+        // console.log(selectedX);
+
+        let count = (selectedX - x0) / blockWidth;
+        count = Math.floor(count);
+        // console.log(count);
+        return count;
+      };
+
+      // Initial setup
+      const font = textStyles.fraction;
+      font.fill = colors.black;
+
+      const padding = 100;
+      const offsetX = 100;
+      const widthOfChar = 35;
+
+      const x0 = padding;
+      const y0 = context.canvas.height / 3;
+      let nextX = x0;
+
+      const cardHeight = 400;
+      const cardX = x0 - padding;
+      const cardY = y0;
+
+      const renderList = [];
+
+      // Render Card
+      const card = game.add.geom.rect(
+        cardX,
+        cardY,
+        0,
+        cardHeight,
+        colors.blueLight,
+        0.5,
+        colors.blueDark,
+        8
+      );
+      card.id = 'card';
+      card.anchor(0, 0.5);
+      renderList.push(card);
+
+      // Fraction setup
+      // console.clear();
+      // const [floorNominators, floorDenominators, floorLines, floorValue] =
+      //   renderFloorFractions(self.floor.selectedIndex, divisor);
+      console.log(self);
+      const [stackNominators, stackDenominators, stackLines, stackValue] =
+        renderStackFractions(self.circles.cur - 1);
+
+      const renderFloorOperationLine = (x) => {
+        font.fill = colors.black;
+        const floorNom = game.add.text(x + offsetX / 2, y0, '', font, 60);
+        const floorDenom = game.add.text(
+          x + offsetX / 2,
+          y0 + 70,
+          '',
+          font,
+          60
+        );
+        const floorLin = game.add.text(
+          x + offsetX / 2,
+          y0 + 35,
+          xyz(),
+          font,
+          60
+        );
+        renderList.push(floorNom);
+        renderList.push(floorDenom);
+        renderList.push(floorLin);
+        return;
+        // font.fill = colors.black;
+        // const floorNom = game.add.text(
+        //   x + offsetX / 2,
+        //   y0,
+        //   floorNominators,
+        //   font,
+        //   60
+        // );
+        // const floorDenom = game.add.text(
+        //   x + offsetX / 2,
+        //   y0 + 70,
+        //   floorDenominators,
+        //   font,
+        //   60
+        // );
+        // const floorLin = game.add.text(
+        //   x + offsetX / 2,
+        //   y0 + 35,
+        //   floorLines,
+        //   font,
+        //   60
+        // );
+        // renderList.push(floorNom);
+        // renderList.push(floorDenom);
+        // renderList.push(floorLin);
+      };
+      const renderStackOperationLine = (x) => {
+        font.fill = colors.black;
+        const stackNom = game.add.text(
+          x + offsetX / 2,
+          y0,
+          stackNominators,
+          font,
+          60
+        );
+        const stackDenom = game.add.text(
+          x + offsetX / 2,
+          y0 + 70,
+          stackDenominators,
+          font,
+          60
+        );
+        const stackLin = game.add.text(
+          x + offsetX / 2,
+          y0 + 35,
+          stackLines,
+          font,
+          60
+        );
+        renderList.push(stackNom);
+        renderList.push(stackDenom);
+        renderList.push(stackLin);
+      };
+
+      // Render LEFT part of the operation
+      // if (gameMode === 'a') renderFloorOperationLine(x0);
+      // else renderStackOperationLine(x0);
+      renderFloorOperationLine(x0);
+
+      // let curNominators = gameMode === 'a' ? floorNominators : stackNominators;
+      let curNominators = '1';
+      nextX = x0 + (curNominators.length + 2) * widthOfChar;
+
+      // Render middle sign - equal by default
+      font.fill = colors.green;
+      let comparisonSign = '=';
+      // Render middle sign - if not equal
+      // if (floorValue != stackValue) {
+      //   font.fill = colors.red;
+      //   let leftSideIsLarger = floorValue > stackValue;
+      //   if (gameMode === 'b') leftSideIsLarger = !leftSideIsLarger;
+      //   if (gameOperation === 'minus') leftSideIsLarger = !leftSideIsLarger;
+      //   comparisonSign = leftSideIsLarger ? '>' : '<';
+      // }
+      renderList.push(game.add.text(nextX, y0 + 35, comparisonSign, font));
+
+      // Render RIGHT part of the operationf
+      // if (gameMode === 'a')
+      renderStackOperationLine(nextX);
+      // else renderFloorOperationLine(nextX);
+
+      curNominators = gameMode === 'a' ? stackNominators : floorNominators;
+      const resultWidth = (curNominators.length + 2) * widthOfChar;
+
+      const cardWidth = nextX - x0 + resultWidth + padding * 2;
+      card.width = cardWidth;
+
+      const endSignX = (context.canvas.width - cardWidth) / 2 + cardWidth;
+
+      // Center Card
+      moveList(renderList, (context.canvas.width - cardWidth) / 2, 0);
+
+      self.fractionOperationUI = renderList;
+
+      return endSignX;
+    },
     renderEndUI: () => {
       let btnColor = colors.green;
       let btnText = game.lang.continue;
@@ -1178,6 +1187,7 @@ const circleOne = {
       self.control.isCorrect = game.math.isOverlap(self.basket, self.kid);
 
       const x = self.utils.renderOperationUI();
+      // const x = self.utils.renderOperationUI_new();
 
       if (self.control.isCorrect) {
         completedLevels++;
@@ -1332,6 +1342,36 @@ const circleOne = {
         });
       }
     },
+    /** TODO */
+    isOverBlock: function (x, blockX, blockWidth) {
+      if (
+        (gameOperation === 'plus' && x >= blockX && x < blockX + blockWidth) ||
+        (gameOperation === 'minus' && x <= blockX && x > blockX + blockWidth)
+      )
+        return true;
+      return false;
+    },
+    /** TODO */
+    isOverRoad: function (x, y, roadX, roadWidth) {
+      if (y > 150) {
+        if (
+          (gameOperation === 'plus' && x >= roadX && x < roadX + roadWidth) ||
+          (gameOperation === 'minus' &&
+            x <= roadX &&
+            x > roadX + roadWidth * self.control.directionModifier)
+        )
+          return true;
+      }
+      return false;
+    },
+    /** TODO */
+    fillCurrentBlock: function (x, blockX, block) {
+      block.fillColor =
+        (gameOperation === 'plus' && x > blockX) ||
+        (gameOperation === 'minus' && x < blockX)
+          ? colors.red
+          : 'transparent';
+    },
   },
 
   events: {
@@ -1344,15 +1384,19 @@ const circleOne = {
       const x = game.math.getMouse(mouseEvent).x;
       const y = game.math.getMouse(mouseEvent).y;
 
-      const isValidX =
-        y > 150 && x >= self.road.x && x < self.road.x + self.road.width;
-
       // GAME MODE A : click road
-      if (gameMode === 'a' && isValidX) {
-        self.utils.clickCircleHandler(
-          // self.blocks.cur.x + self.blocks.cur.width / 2
-          self.blocks.cur.x + self.blocks.cur.width
+      if (gameMode === 'a') {
+        const isValidX = self.utils.isOverRoad(
+          x,
+          y,
+          self.road.x,
+          self.road.width
         );
+        if (isValidX) {
+          self.utils.clickCircleHandler(
+            self.blocks.cur.x + self.blocks.cur.width
+          );
+        }
       }
 
       // GAME MODE B : click circle
@@ -1382,7 +1426,6 @@ const circleOne = {
 
       game.render.all();
     },
-
     /**
      * Called by mouse move event
      *
@@ -1393,21 +1436,27 @@ const circleOne = {
       const y = game.math.getMouse(mouseEvent).y;
       let isOverCircle = false;
 
-      const isValidX = x >= self.road.x && x < self.road.x + self.road.width;
-
-      // GAME MODE A : balloon follow mouse
-      if (gameMode === 'a' && !self.control.hasClicked && isValidX) {
-        self.blocks.cur = self.blocks.list[0];
-        self.blocks.list.forEach((cur) => {
-          cur.fillColor = cur.x < x ? colors.red : 'transparent';
-          if (x >= cur.x && x < cur.x + cur.width) self.blocks.cur = cur;
-        });
-        // const newX = self.blocks.cur.x + self.blocks.cur.width / 2;
-        const newX = self.blocks.cur.x + self.blocks.cur.width;
-        self.balloon.x = newX;
-        self.basket.x = newX;
+      if (gameMode === 'a' && !self.control.hasClicked) {
+        const isValidX = self.utils.isOverRoad(
+          x,
+          y,
+          self.road.x,
+          self.road.width
+        );
+        if (isValidX) {
+          // GAME MODE A : balloon follow mouse
+          self.blocks.cur = self.blocks.list[0];
+          self.blocks.list.forEach((cur) => {
+            self.utils.fillCurrentBlock(x, cur.x, cur);
+            if (self.utils.isOverBlock(x, cur.x, cur.width, cur))
+              self.blocks.cur = cur;
+          });
+          const newX = self.blocks.cur.x + self.blocks.cur.width;
+          self.balloon.x = newX;
+          self.basket.x = newX;
 
-        document.body.style.cursor = 'auto';
+          document.body.style.cursor = 'auto';
+        }
       }
 
       // GAME MODE B : hover circle