reactjstypescriptreact-hooksreact-custom-hooks

A value increments twice onKeyDown


I am trying to make a Tetris game, I have added move functionality where onKeyDown a block would either move left or right.

<StyledTetrisBoard role='button' tabIndex={0} onKeyDown={move} >
    some game components
</StyledTetrisBoard>

The move function would then identify key and assign value:

  const move = ({ keyCode, repeat}: {keyCode: number, repeat: boolean}): void => {
    if(keyCode === 37) {
      movePlayer(-1);
    } else if(keyCode === 39)  {
      movePlayer(1);
  };

Move player would then call custom hook:

const { updatePlayerPosition } = usePlayer();

 const movePlayer = (direction: number) => {
      updatePlayerPosition({ x: direction, y: 0, collided: false});
  };

And the usePlayer looks like this:

export type PLAYER = {
  position: {
    x: number;
    y: number;
  };
  block: any[][]; // TODO: find better way of assigning type to this one. (string | number) doesn't seem to work.
  collided: boolean;
};

export const usePlayer = () => {
  const [player, setPlayer] = useState({} as PLAYER);

  const updatePlayerPosition = ({x, y, collided,}: {x: number; y: number; collided: boolean;}): void => {
    setPlayer((previous) => ({
      ...previous,
      position: {
        x: (previous.position.x += x),
        y: (previous.position.y += y),
      },
      collided,
    }));
  };

  const resetPlayer = useCallback(
    (): void =>
      setPlayer({
        position: { x: BOARD_WIDTH / 2 - 2, y: 0 },
        block: randomBlock().shape,
        collided: false,
      }),
    []
    );
  return { player, updatePlayerPosition, resetPlayer };
};

However the x value seems to increment by 2 rather than 1. It doesn't come with any errors.

So overall the App file looks like this:

import React, { useRef } from "react";

// Custom Hooks
import { usePlayer } from "../../hooks/usePlayer";

// Styles
import { StyledTetrisBoard } from "./StyledTetrisBoard ";

const BlockGame: React.FC = () => {

  const { updatePlayerPosition } = usePlayer();

  const movePlayer = (direction: number) => {
      updatePlayerPosition({ x: direction, y: 0, collided: false});
  };

  const move = ({ keyCode, repeat}: {keyCode: number, repeat: boolean}): void => {
    if(keyCode === 37) {
      movePlayer(-1);
    } else if(keyCode === 39)  {
      movePlayer(1);
    }
  };


  return (
      <StyledTetrisBoard role='button' tabIndex={0} onKeyDown={move} ref={gameArea}>
      <StyledBlocks>
        <Board board={board} />
        <div className="blockgame__side">
          {gameOver ? (
            <>
              <Display gameOver={gameOver} text="game over" />
              <StartButton callback={handleStartGame} />
            </>
          ) : (
            <>
              <Display text={`Score: `} />
              <Display text={`Rows: `} />
              <Display text={`Level: `} />
            </>
          )}
        </div>
      </StyledBlocks>
    </StyledTetrisBoard >
  );
};

export default BlockGame;

Solution

  • Try changing

    x: (previous.position.x += x),
    y: (previous.position.y += y),
    

    To:

    x: previous.position.x + x,
    y: previous.position.y + y,
    

    The += operator will also modify the prev variable which is not allowed.