입문

미니게임 (별 잡기)

StatefulWidget, setState, Timer, Stack을 사용해 별을 잡는 간단한 게임을 만듭니다.

동작

미니게임 (별 잡기) 실행 화면

화면에 나타나는 별을 제한 시간 안에 눌러 점수를 얻습니다. 별을 누르면 점수가 올라가고 별 위치가 바뀝니다. 시간이 끝나면 게임이 멈추고 다시 시작 버튼으로 초기화합니다.

예제 코드

별 잡기 게임

별 잡기 게임
점수 0 시간 15
게임 시작을 누르고 별을 잡아보세요.

예제 코드 기능별 설명

코드를 나누어 읽기

import

dart:async은 제한 시간을 줄이는 Timer에 필요하고, material.dart는 버튼, 텍스트, Stack, Positioned 같은 화면 위젯을 제공합니다.

import 'dart:async';
import 'package:flutter/material.dart';

StatefulWidget 클래스

별 위치, 점수, 남은 시간이 계속 바뀌므로 StatefulWidget으로 만듭니다. 바뀌는 값은 _StarCatcherGameState 안에서 관리합니다.

class StarCatcherGame extends StatefulWidget {
  const StarCatcherGame({super.key});
}

상태값

점수, 남은 시간, 별의 좌표를 State 안에 둡니다. 사용자가 별을 누르거나 시간이 흐를 때 이 값들이 바뀌고 화면이 다시 그려집니다.

int score = 0;
int seconds = 15;
double starX = 120;
double starY = 90;

게임 시작

기존 타이머를 멈춘 뒤 점수와 시간을 초기값으로 되돌립니다. Timer.periodic으로 1초마다 남은 시간을 줄입니다.

void startGame() {
  timer?.cancel();
  setState(() {
    score = 0;
    seconds = 15;
  });
}

별 잡기

별을 누르면 점수를 올리고 다음 위치를 계산합니다. setState 안에서 좌표를 바꾸기 때문에 Stack 안의 버튼 위치가 바뀝니다.

void catchStar() {
  if (seconds == 0) return;
  setState(() {
    score += 1;
    starX = (score * 47 % 220).toDouble();
  });
}

타이머 종료

seconds가 0이 되면 타이머를 cancel해서 더 이상 시간이 줄지 않게 합니다. 타이머를 멈추지 않으면 게임이 끝난 뒤에도 콜백이 계속 실행될 수 있습니다.

if (seconds == 0) {
  timer.cancel();
  return;
}

Stack과 Positioned

별은 고정된 목록 아이템이 아니라 화면 안에서 위치가 바뀌는 대상입니다. Stack은 자식 위젯을 겹쳐 놓을 수 있고, Positioned는 starX와 starY 좌표에 맞춰 별 버튼을 배치합니다.

Stack(children: [
  Positioned(
    left: starX,
    top: starY,
    child: ElevatedButton(...),
  ),
]);

dispose

State 객체가 사라질 때 timer를 cancel합니다. 화면을 벗어난 뒤에도 타이머가 살아 있으면 setState가 이미 사라진 위젯을 다시 그리려고 해 오류가 날 수 있습니다.

@override
void dispose() {
  timer?.cancel();
  super.dispose();
}