본문 바로가기
프로젝트/퍼즐 게임

운동하면서 즐기는 퍼즐 게임 만들기 - 개발일지 #3

by 루까(Luka) 2026. 1. 26.
반응형

걸으면 풀리는 퍼즐 게임 — 개발 일지 #3: 구현

이번에 한 것

기술 스택을 정한 뒤 약 일주일 동안 핵심 기능을 구현했다. 프로젝트 세팅부터 걸음 수 연동까지 진행한 내용을 정리한다.


1. 프로젝트 초기 설정

flutter create . --org com.lukaplayground --project-name walking_puzzle_game

패키지 설치:

dependencies:
  geolocator: ^13.0.2
  pedometer: ^4.0.2
  google_maps_flutter: ^2.10.0
  permission_handler: ^11.3.1
  provider: ^6.1.2

권한 설정은 iOS와 Android를 각각 해줘야 한다. Flutter가 크로스 플랫폼이라고 해서 이 부분까지 통일되지는 않는다.

<!-- iOS: Info.plist -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>위치 기반 퍼즐 기능을 사용하기 위해 현재 위치 정보가 필요합니다.</string>

<key>NSMotionUsageDescription</key>
<string>걸음 수를 측정하여 퍼즐 힌트와 스테이지를 잠금 해제하기 위해 모션 센서 접근이 필요합니다.</string>
<!-- Android: AndroidManifest.xml -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

2. 앱 아키텍처

lib/
├── models/         # PuzzleModel, UserProgressModel, LocationModel
├── services/       # Permission, Location, Pedometer, Storage
├── providers/      # 상태 관리 (Provider)
├── screens/        # 화면 UI
├── widgets/        # 재사용 위젯
└── utils/          # 유틸리티

서비스 레이어를 분리한 게 나중에 도움이 됐다. 특히 PedometerServiceHealthService로 교체할 때, 서비스 인터페이스만 맞추면 나머지 코드는 건드릴 필요가 없었다.


3. Water Sort Puzzle 구현

퍼즐 게임으로 Water Sort Puzzle을 선택했다. 이유는 단순하다 — 저작권 문제가 없다. 게임 메커니즘 자체는 퍼블릭 도메인이다.

난이도 설계

난이도 튜브 수 이동 제한 해금 조건
쉬움 5개 30회 없음
보통 6개 40회 스테이지 3 클리어
어려움 7개 50회 5,000보
지옥 8개 60회 13,000보

별점 평가도 넣었다. 이동 제한의 70% 이하로 클리어하면 ⭐⭐⭐을 받는다.

힌트 시스템

3가지 힌트를 구현했다:

  1. 같은 색상 합치기 (완성 우선)
  2. 빈 튜브로 이동 (공간 확보)
  3. 가능한 이동 중 최선의 수 제안

힌트를 무한으로 주면 게임이 무의미해진다. 여기서 걸음 수 연동이 들어온다.


4. pedometer에서 health 패키지로 전환

처음에는 pedometer 패키지를 사용했다. 실시간 걸음 수를 직접 센서에서 읽는 방식이다.

문제가 생겼다. 앱을 끄면 카운트가 리셋된다. 백그라운드에서 지속 추적하려면 별도 서비스를 구현해야 하는데, 이미 iOS의 건강 앱이 그 역할을 하고 있다.

그래서 health 패키지로 전환했다.

class HealthService {
    final Health health = Health();

    Future<int> getTodaySteps() async {
        final now = DateTime.now();
        final midnight = DateTime(now.year, now.month, now.day);

        final steps = await health.getTotalStepsInInterval(midnight, now);
        return steps ?? 0;
    }
}

iOS HealthKit / Android Health Connect에서 걸음 수를 읽어오는 방식이다. 이미 OS 레벨에서 걸음 수를 추적하고 있으니, 우리는 그냥 가져다 쓰면 된다.

전환하고 나서 좋아진 점

항목 pedometer health
백그라운드 직접 구현 필요 OS가 알아서
정확도 센서 직접 읽기 OS 보정 적용
배터리 센서 상시 가동 OS 최적화
웨어러블 미지원 Apple Watch 등 통합

추가 권한 설정이 필요하다:

<!-- iOS: Info.plist -->
<key>NSHealthShareUsageDescription</key>
<string>건강 앱의 걸음 수 데이터를 읽어와 퍼즐 힌트와 스테이지를 잠금 해제하기 위해 필요합니다.</string>

HealthKit Entitlement도 Xcode에서 켜줘야 한다. 이걸 빠뜨리면 빌드는 되는데 권한 요청 팝업이 안 뜬다.


5. 걸음 수 보상 시스템

핵심 로직은 단순하다. 2,000보마다 힌트 1개.

int getTotalHintsFromSteps(int todaySteps) {
    return todaySteps ~/ 2000;
}

int getStepsUntilNextHint(int todaySteps) {
    return 2000 - (todaySteps % 2000);
}

30초마다 HealthKit에서 걸음 수를 동기화한다:

Timer.periodic(Duration(seconds: 30), (timer) async {
    final steps = await healthService.getTodaySteps();
    // 상태 업데이트
});

스테이지 해금 기준

스테이지 필요 걸음 수 거리 환산
3 2,620보 ~2km
6 6,562보 ~5km
8 13,123보 ~10km

걸음 수로만 해금 가능한 스테이지는 전체의 30% 정도다. 나머지는 실력으로 풀 수 있다. 운동을 강제하면 게임이 재미없어진다.


삽질 기록

크로스 플랫폼의 현실

Flutter로 한 번 짜면 양쪽 다 된다고 했지만, 권한 설정은 iOS/Android 각각 따로 해야 한다. HealthKit은 iOS 전용이고, Health Connect는 Android 전용이다. 서비스 레이어에서 플랫폼 분기를 태워야 한다.

실기기 테스트의 고됨

걸음 수 센서는 에뮬레이터에서 테스트할 수 없다. 실제로 스마트폰 들고 걸어다녀야 한다. 코드 수정하고 빌드하고 밖에 나가서 100보 걸어보고, 다시 들어와서 로그 확인하고. 디버깅 루프가 길다.

패키지 선택은 신중하게

처음부터 health 패키지를 썼으면 3일은 아꼈다. pedometer로 시작해서 백그라운드 문제에 부딪히고, 결국 health로 전환하면서 서비스 레이어를 다시 짰다. 초기 리서치가 중요하다는 걸 다시 한번 느꼈다.


현재 상태

  • ✅ 프로젝트 세팅 + 아키텍처
  • ✅ Water Sort Puzzle 게임 (10개 스테이지)
  • ✅ HealthKit / Health Connect 연동
  • ✅ 걸음 수 → 힌트 지급
  • ✅ 걸음 수 → 스테이지 해금

다음 개발 일지에서는 위치 기반 특별 보상앱스토어 등록 준비를 다룰 예정이다.


기술 스택: Flutter 3.x, Dart, HealthKit, Health Connect, Provider
소스 코드: GitHub
시리즈: 퍼즐 게임 개발 일지 #3 / 4

반응형