How can i solve a touch event bug in my mobile game

84 views Asked by At

I'm building a match 3 game for mobile with ionic/angular. For that i studied how touch gestures work.

I have a problem i'm trying to solve since a few days ago without success.

If i swipe move a tile to the left or to the right i can only move it across one tile.

If i move one tile up or down i can move it over as many tiles as i want.

I need to be able to move a tile left or right across as many tiles as i want.

Each tile has a with of 50px, therefore the sensitivity is equal to 50.

One strange thing i noticed and i'm not able to solve is that the onTouchEnd only fires if i swipe up or down. That maybe one of the causes of the problem because this.selectedTile = null does not happens and the touchmove does not have a new reference to swipe across path with more than 2 tiles.

I attached the relevant code and a picture of the game board.

Can somebody help me?

LOGIC (creating game board, touch gestures):

generateGameBoard(): void {
        this.startTimer();
        const rows = 6;
        const cols = 6;
        const board: Cell[][] = [];

    // Calculate the total number of tiles needed for pairs of 3
    const totalPairsOf3 = Math.floor((rows * cols) / 3);
    let generatedPairsOf3 = 0;

    // Shuffle the Egyptian hieroglyphs array to ensure randomness
    const shuffledHieroglyphs = this.shuffleArray(this.symbols);

    for (let i = 0; i < rows; i++) {
      const row: Cell[] = [];
      for (let j = 0; j < cols; j++) {
        // Check if we have generated enough pairs of 3
        if (generatedPairsOf3 < totalPairsOf3) {
          // Generate pairs of 3
          const pairIndex = generatedPairsOf3 % shuffledHieroglyphs.length;
          const pairHieroglyph = shuffledHieroglyphs[pairIndex];
          row.push({
            symbol: pairHieroglyph?.symbol,
            color: pairHieroglyph?.color,
          });
          generatedPairsOf3++;
        } else {
          // Fill the remaining tiles with random tiles
          const randomIndex = Math.floor(Math.random() * this.symbols.length);
          const randomHieroglyph = this.symbols[randomIndex];
          row.push({
            symbol: randomHieroglyph?.symbol,
            color: randomHieroglyph?.color,
          });
        }
      }
      board.push(row);
    }

    this.gameBoard = board;
    this.checkAdjacentTiles();
  }


shuffleArray(array: any[]): any[] {
    for (let i = array.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [array[i], array[j]] = [array[j], array[i]];
    }
    return array;
  }

onTouchStart(event: TouchEvent) {
    event.preventDefault();

    const touchedElement = event.touches[0].target as HTMLElement;
    if (!touchedElement || !touchedElement.dataset) return;

    const touchedRow = parseInt(touchedElement.dataset['row'] || '0', 10);
    const touchedCol = parseInt(touchedElement.dataset['col'] || '0', 10);

    console.log('Touched row:', touchedRow, 'Touched col:', touchedCol);

    this.selectedTile = { row: touchedRow, col: touchedCol };
    this.startX = event.touches[0].clientX;
    this.startY = event.touches[0].clientY;
  }


onTouchMove(event: TouchEvent) {
    event.preventDefault();

    if (!this.selectedTile) return;

    const currentX = event.touches[0].clientX;
    const currentY = event.touches[0].clientY;

    const deltaX = currentX - this.startX;
    const deltaY = currentY - this.startY;

    const sensitivity = 50;

    // Check if movement is primarily horizontal or vertical

    const absDeltaX = Math.abs(deltaX);
    const absDeltaY = Math.abs(deltaY);

    const numTilesToMoveX = Math.floor(absDeltaX / 50);
    const numTilesToMoveY = Math.floor(absDeltaY / 50);

    let newRow = this.selectedTile.row;
    let newCol = this.selectedTile.col;

    if (Math.abs(deltaX) > Math.abs(deltaY)) {
      // Horizontal movement
      if (deltaX > sensitivity) {
        // Swipe right
        console.log('Swiped right');
        newRow += numTilesToMoveX;
      } else if (deltaX < -sensitivity) {
        // Swipe left
        console.log('Swiped left');
        newRow -= numTilesToMoveX;
      }
    } else {
      // Vertical movement
      if (deltaY > sensitivity) {
        // Swipe down
        console.log('Swiped down');
        newCol += numTilesToMoveY;
      } else if (deltaY < -sensitivity) {
        // Swipe up
        console.log('Swiped up');
        newCol -= numTilesToMoveY;
      }
    }

    newRow = Math.max(0, Math.min(newRow, this.gameBoard[0].length - 1));
    newCol = Math.max(0, Math.min(newCol, this.gameBoard[0].length - 1));

    if (newRow !== this.selectedTile.row || newCol !== this.selectedTile.col) {
      // Swap the tiles
      [
        this.gameBoard[newRow][newCol],
        this.gameBoard[this.selectedTile.row][this.selectedTile.col],
      ] = [
        this.gameBoard[this.selectedTile.row][this.selectedTile.col],
        this.gameBoard[newRow][newCol],
      ];

      // Update the selected tile's position
      this.selectedTile.row = newRow;
      this.selectedTile.col = newCol;

      // Update the start position for the next calculation
      this.startX = currentX;
      this.startY = currentY;
    }
  }

  onTouchCancel(event: TouchEvent) {
    this.onTouchEnd(event);
  }

  onTouchEnd(event: TouchEvent) {
    console.log('touchend');
    this.soundService.playSfx();
    this.checkAdjacentTiles();
    event.preventDefault();
    this.selectedTile = null;
  }

MARKUP:

  <div
    class="game-board"
    (touchstart)="onTouchStart($event)"
    (touchmove)="onTouchMove($event)"
    (touchcancel)="onTouchCancel($event)"
    (touchend)="onTouchEnd($event)"
  >
    <div class="row" *ngFor="let row of gameBoard; let i = index">
      <div
        class="cell"
        *ngFor="let cell of row; let j = index"
        [attr.data-row]="i"
        [attr.data-col]="j"
        [style.color]="cell.color"
        [class.glow]="cell.glow"
      >
        {{ cell.symbol }}
      </div>
    </div>
  </div>

enter image description here

0

There are 0 answers