안녕하세요! 오늘은 제가 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의 주요 기능을 체험할 수 있었던 점이 큰 장점이었습니다.