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