[MINI_TETRIS] FLUTTER 이용해서 테트리스 개발

안녕하세요! 오늘은 제가 Flutter를 이용해 미니 테트리스를 개발한 구체적인 과정을 공유하려고 합니다. 이 글에서는 테트리스의 핵심 로직 구현부터 UI 설계까지의 전 과정을 자세히 설명합니다. 특히, Flutter를 처음 접하시는 분들에게도 도움이 되도록 코드와 설명을 포함했습니다.


1. 테트리스의 기본 로직 설계

1-1. 블록 생성 및 이동

테트리스의 기본은 블록 생성과 이를 자유롭게 이동시키는 기능입니다. Flutter의 setState를 사용하여 블록의 상태를 업데이트하고, Timer를 활용해 자동으로 블록이 내려오도록 구현했습니다.

class TetrisGame extends StatefulWidget {
  @override
  _TetrisGameState createState() => _TetrisGameState();
}

class _TetrisGameState extends State<TetrisGame> {
  List<List<int>> board = List.generate(20, (_) => List.filled(10, 0));
  // 현재 블록의 좌표
  List<List<int>> currentBlock = [[0, 4], [1, 4], [1, 5], [0, 5]]; // 기본 사각형 블록

  void moveBlock(String direction) {
    setState(() {
      // 방향에 따라 블록의 좌표 변경
      if (direction == 'left') {
        currentBlock = currentBlock.map((pos) => [pos[0], pos[1] - 1]).toList();
      } else if (direction == 'right') {
        currentBlock = currentBlock.map((pos) => [pos[0], pos[1] + 1]).toList();
      } else if (direction == 'down') {
        currentBlock = currentBlock.map((pos) => [pos[0] + 1, pos[1]]).toList();
      }
    });
  }
}

구현 포인트

  • 2D 배열로 테트리스 보드 상태를 관리했습니다.
  • 키 입력 및 타이머를 통해 블록이 내려오고, 좌우 이동이 가능하게 설정했습니다.

1-2. 충돌 감지 및 블록 고정

블록이 보드의 아래쪽 끝이나 다른 블록과 충돌했을 때, 해당 블록이 고정되도록 설정했습니다.

bool checkCollision(List<List<int>> block) {
  for (var pos in block) {
    int row = pos[0];
    int col = pos[1];
    if (row >= 20 || col < 0 || col >= 10 || board[row][col] == 1) {
      return true;
    }
  }
  return false;
}

void fixBlock() {
  for (var pos in currentBlock) {
    board[pos[0]][pos[1]] = 1;
  }
  // 새로운 블록 생성
  currentBlock = generateNewBlock();
}

구현 포인트

  • 충돌 감지 함수: 블록이 경계를 넘거나 다른 블록과 겹치는지 확인합니다.
  • 고정 처리: 충돌이 감지되면 블록을 보드에 고정하고 새로운 블록을 생성합니다.

1-3. 라인 제거 및 점수 계산

완성된 가로 라인은 제거되고, 플레이어의 점수를 증가시키는 로직을 구현했습니다.

void clearLines() {
  setState(() {
    board = board.where((row) => row.contains(0)).toList();
    int clearedLines = 20 - board.length;
    for (int i = 0; i < clearedLines; i++) {
      board.insert(0, List.filled(10, 0));
    }
    // 점수 계산
    score += clearedLines * 10;
  });
}

구현 포인트

  • 라인 제거: 비어 있지 않은 라인을 찾아 제거합니다.
  • 점수 계산: 제거된 라인 수에 따라 점수를 추가합니다.

2. Flutter UI 설계

2-1. 게임 화면 구성

Flutter의 위젯 트리를 활용하여 게임 화면을 구성했습니다. 간단한 테트리스 보드와 점수를 표시하는 UI를 작성했습니다.

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: Text('Mini Tetris')),
    body: Column(
      children: [
        Expanded(
          child: GridView.builder(
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 10),
            itemCount: 200,
            itemBuilder: (context, index) {
              int row = index ~/ 10;
              int col = index % 10;
              return Container(
                margin: EdgeInsets.all(1),
                color: board[row][col] == 1 ? Colors.blue : Colors.grey[300],
              );
            },
          ),
        ),
        Text('Score: $score', style: TextStyle(fontSize: 24)),
      ],
    ),
  );
}

구현 포인트

  • GridView: 테트리스 보드를 표시하기 위해 사용했습니다.
  • Container 색상 변경: 블록의 유무에 따라 색상을 다르게 설정했습니다.
  • 점수 표시: 화면 하단에 현재 점수를 표시했습니다.

3. Flutter에서 배운 점

3-1. 상태 관리

Flutter의 setState를 통해 게임 상태를 실시간으로 업데이트하는 방법을 배웠습니다. 이후에는 더 복잡한 상태 관리 도구(예: Provider, Riverpod)로 확장할 계획입니다.

3-2. UI 구성의 유연성

Flutter는 UI 구성의 유연성이 뛰어났습니다. 게임 화면을 그리드 형태로 표현하는 작업이 간단하면서도 직관적이었습니다.

3-3. 애니메이션 처리

기본 타이머를 활용해 블록이 내려오는 애니메이션을 구현했지만, Flutter의 AnimationController를 활용하면 더 자연스러운 애니메이션을 추가할 수 있을 것 같습니다.


4. 마무리

Flutter를 이용해 테트리스를 개발하면서 많은 것을 배울 수 있었습니다. 특히, 게임 개발이라는 재미있는 주제를 통해 Flutter의 주요 기능을 체험할 수 있었던 점이 큰 장점이었습니다.