본문 바로가기
개발 언어/Java, Javascript

React + Tailwind로 만드는 웹 테트리스 게임

by 주호파파 2025. 4. 24.
728x90
반응형

🧱 1. 블럭 데이터 구조 정의

const TETROMINOS = {
  I: { shape: [[1, 1, 1, 1]], color: 'cyan-500' },
  J: { shape: [[1, 0, 0], [1, 1, 1]], color: 'blue-500' },
  L: { shape: [[0, 0, 1], [1, 1, 1]], color: 'orange-500' },
  O: { shape: [[1, 1], [1, 1]], color: 'yellow-500' },
  S: { shape: [[0, 1, 1], [1, 1, 0]], color: 'green-500' },
  T: { shape: [[0, 1, 0], [1, 1, 1]], color: 'purple-500' },
  Z: { shape: [[1, 1, 0], [0, 1, 1]], color: 'red-500' },
};

블럭 모양은 2차원 배열로 표현되고 색상은 Tailwind 클래스 문자열로 지정됩니다.

📀 2. 게임 보드 설정

const BOARD_WIDTH = 10;
const BOARD_HEIGHT = 20;
const createEmptyBoard = () => Array.from({ length: BOARD_HEIGHT }, () => Array(BOARD_WIDTH).fill(0));

10x20 크기의 보드이며, 초기에는 모두 0으로 채워져 있습니다.

🔄 3. 게임 상태 관리

const [board, setBoard] = useState(createEmptyBoard());
const [currentPiece, setCurrentPiece] = useState(null);
const [score, setScore] = useState(0);
const [gameOver, setGameOver] = useState(false);

React의 useState를 이용해 게임 상태(보드, 현재 블럭, 점수, 게임 종료 상태 등)를 관리합니다.

🔀 4. 블럭 생성 및 랜덤 선택

const randomTetromino = () => {
  const keys = Object.keys(TETROMINOS);
  const randKey = keys[Math.floor(Math.random() * keys.length)];
  return TETROMINOS[randKey];
};

새 블럭은 TETROMINOS 객체에서 무작위로 선택됩니다.

🎯 5. 충돌 검사 및 유효성 체크

const checkCollision = (x, y, shape) => {...};
const isValidMove = (x, y, shape) => !checkCollision(x, y, shape);

보드의 경계나 이미 존재하는 블럭과의 충돌 여부를 판단합니다.

🕹️ 6. 키보드 조작 처리

useEffect(() => {
  const handleKeyPress = (e) => {
    if (gameOver) return;
    switch (e.key) {
      case 'ArrowLeft': moveLeft(); break;
      case 'ArrowRight': moveRight(); break;
      case 'ArrowDown': moveDown(); break;
      case 'ArrowUp': rotate(); break;
    }
  };
  window.addEventListener('keydown', handleKeyPress);
  return () => window.removeEventListener('keydown', handleKeyPress);
}, [moveLeft, moveRight, moveDown, rotate, gameOver]);

키보드 방향키를 통해 블럭을 이동하고 회전시킵니다.

📦 7. 블럭 고정 및 줄 제거

const placePiece = () => {...};
const clearLines = (newBoard) => {...};

블럭이 더 이상 아래로 이동할 수 없을 경우 고정하고, 줄이 가득 찬 경우 해당 줄을 삭제합니다.

📉 8. 레벨과 속도 조절

if (Math.floor(newScore / 500) > level - 1) {
  setLevel(prev => prev + 1);
  setDropTime(prev => prev * SPEED_INCREASE_FACTOR);
}

점수가 증가하면 레벨이 오르고, 블럭의 낙하 속도가 빨라집니다.

🎵 9. 음악 기능 추가

<audio ref={audioRef} src="https://hebbkx1anhila5yf.public.blob.vercel-storage.com/Tetris-kxnh5j7hpNEcFspAndlU2huV5n6dvk.mp3" />

게임에 배경 음악을 추가하고, 버튼으로 재생/정지할 수 있도록 구성했습니다.

🧱 10. 보드 렌더링

<div style={{ gridTemplateColumns: `repeat(${BOARD_WIDTH}, 1fr)` }}>
  {board.map((row, y) =>
    row.map((_, x) => (
      <motion.div className={...} />
    )))}
</div>

각 셀을 Tailwind 스타일의 motion.div로 렌더링하여 애니메이션 효과를 줍니다.

🔁 11. 게임 리셋 기능

const resetGame = () => {
  setBoard(createEmptyBoard());
  setCurrentPiece(null);
  setScore(0);
  setGameOver(false);
  setDropTime(INITIAL_DROP_TIME);
  setLevel(1);
}

게임을 초기 상태로 재시작합니다.

✅ 정리

이 테트리스 프로젝트는 React 학습에 아주 좋은 실습 예제입니다. Tailwind와 framer-motion을 통해 시각적으로도 높은 완성도를 보여줄 수 있습니다.

 

소스 코드

tetris-game-source.zip
201.1 kB

728x90
반응형