선을 그어 칸 위의 유닛을 한 칸씩 회전시키는 그리드 기반 모바일 퍼즐 게임입니다. “꽃을 흙 위로 옮긴다”는 단순한 목표에서 출발하지만, 타일과 유닛을 조합하면서 난이도가 차근차근 올라갑니다. 처음에는 엔트리로 프로토타입을 만들어 게임성을 검증한 뒤 Unity로 옮겼습니다.

한눈에 보기

항목내용
장르캐주얼 퍼즐 (선 잇기 / 순환 이동)
엔진Unity 6 (6000.3.9f1), 2D URP
플랫폼Android (세로 모드), com.GDH.ChainPuzzle
버전1.0.2 (최종 제출 versionCode 7)
상태Google Play 출시 확인 (2026.10.08), 최종 소스 보관 완료
분량기본 캠페인 144레벨 (12레벨 × 12페이지) + 사용자 제작 맵
언어한국어 / 영어 / 일본어 (런타임 전환)

실행 화면

메인 메뉴캠페인 플레이
빙글정원 메인 메뉴와 캠페인 진행 표시40레벨의 꽃과 두 칸 이동 타일, 경로 비용 HUD
인게임 맵 에디터힌트 구매
타일과 유닛 팔레트를 갖춘 맵 에디터필요한 코인과 잔액을 구분한 힌트 구매 팝업

2026년 9월 29일 당시 작업본을 Unity Play Mode에서 직접 캡처했습니다. 720×1560 해상도이며, 별도 테스트 저장과 오프라인 설정을 사용했습니다. 에디터 화면은 도구가 해제된 테스트 진행 상태입니다.

역할 분담

개발 2명·아트 1명으로 시작한 프로젝트입니다. 초기 공동 개발의 역할 분담은 다음과 같습니다.

본인 (이영호) 담당

협업

2026년 9~10월 — 캠페인·사용성 개선과 출시

초기 공동 개발 이후 진행 구조·화면·저장·온라인 연결을 점검했습니다. 실제 Android에서 발견한 입력 문제도 수정한 뒤 다시 검사했습니다.

144레벨 캠페인과 저장 호환성

기존 24레벨을 보존하면서 120레벨을 추가해 144레벨 캠페인을 적용했습니다. 화면에서는 12레벨씩 12페이지로 보여 주고, 학습은 기본 규칙·두 칸 이동·역방향·쓰레기·돌꽃·얼음의 6구간으로 구성했습니다. 레벨 선택·제작 도구 해금·다음 레벨 이동은 공통 진행 정책을 따릅니다.

저장 형식을 바꿀 때는 기존 진도와 제작 권한을 보존했습니다. 신규 권한은 1레벨부터 연속으로 클리어한 수에 따라 열립니다. 해금 소개가 중간에 끊기면 다시 보여 줍니다. 연출이 실제 버튼에 도착한 뒤 표시 완료를 저장합니다.

도자기풍 아트와 화면 개선

꽃·돌·화분 타일을 도자기풍 아트로 통일하고, 스프라이트 리그와 이동·착지 연출을 연결했습니다. 두 칸 이동 타일에는 ×2 표시를 넣어 규칙을 읽기 쉽게 했습니다. 메인 메뉴는 플레이를 중심으로 정리하고, 제작 화면에는 타일과 유닛을 고르는 두 줄 팔레트를 배치했습니다.

플레이 HUD에는 경로 비용과 보유 코인을 함께 표시했습니다. 힌트·정답 팝업은 취소와 구매 버튼의 위치를 통일하고, 필요한 코인과 잔액을 나눠 보여 줍니다. 한국어·영어·일본어에서 글자가 넘치지 않는지 확인하고, 작은 화면과 Safe Area도 검증했습니다. BGM은 화면 전환 시 교차 페이드하며 재생 위치를 유지하고, 효과음 19개도 게임 분위기에 맞게 재제작했습니다.

온라인 맵과 계정 연결

최신순·별점순·플레이 횟수순 정렬에 제목/제작자 검색, 기믹 필터, 내 맵 조건을 조합했습니다. 목록을 기다리다 화면을 나가거나 조건을 바꾸면 이전 요청의 응답을 버립니다. 오프라인에서도 로컬 슬롯과 맵 제작을 사용할 수 있습니다.

실기기에서 발생한 Firebase Auth/UserMismatch를 조사하고, 기존 계정을 보존하는 취소 흐름과 동의를 받은 계정 변경을 구현했습니다. 운영 목록의 색인과 기존 공개 맵 필드도 보완했습니다. 중복 업로드 방지, 사용자별 평점과 트랜잭션 집계, 신고·차단도 구현했습니다. 운영 검증이 남은 항목은 따로 관리합니다.

Android 입력과 출시 절차

Android에서 짧은 뒤로가기 입력이 빠지거나, 키보드를 닫으려다 화면까지 나가는 문제를 추적했습니다. 네이티브 Back 전달과 키보드 가장자리 입력 처리를 보완하고, LG V50에서 재검증했습니다. 맵 제목은 3~15자, 힌트는 3코인, 정답은 10코인으로 표시·차감·취소 동작을 맞췄습니다.

2026년 9월 21일, 빙글정원 1.0.2/code6를 대한민국·일본·미국 대상으로 Google Play 심사에 제출했습니다. Play Games 서비스의 인증 설정과 업적 게시도 완료했습니다.

Google Play 출시와 최종 보관

10월 2일 심사에서 스토어 이름과 기기에 설치된 앱 이름의 불일치가 지적됐습니다. 패키지 ID와 기존 저장 경로는 유지하면서 Android 표시 이름을 빙글정원으로 맞췄습니다. 최신 메인 화면·플레이 HUD·힌트 안내 개선을 포함한 1.0.2/versionCode 7을 검증한 뒤 10월 3일 다시 제출했습니다.

2026년 10월 8일, Google Play 공개 페이지에서 빙글정원과 설치 버튼을 확인했습니다. 10월 8일은 출시 확인일입니다. 최종 소스와 출시·검증 기록은 Unity Version Control의 /main(cs268)과 GitHub의 main(6e8f99f)에 반영해 보관했습니다.

검증 기록

아래는 각 작업 당시 남긴 실행 결과입니다. 서로 다른 버전과 환경의 수치를 합산하지 않았습니다.

검증 범위확인한 결과남은 확인
9월 23일 UI 개선Unity 화면·레이아웃 985개, Safe Area·입력 23개, 구매·Back·입력 회귀 131개 검사 통과10월 3일 code7에서 주요 흐름 재검증, IME·일부 편집 동작은 남음
같은 UI 변경본 Android 빌드Unity 6000.3.9f1, 오류 0·경고 3, 로컬 비개발 APK 생성디버그 서명 검증본으로, 스토어 제출본과 구별
9월 20일 Android Back 수정LG V50에서 케이스 묶음 34개 통과·4개 미실행사람 손/OS IME 대조와 일부 편집 동작
9월 21일 계정·목록 수정LG V50에서 계정 변경·취소·재실행·온라인 목록 등 14개 검사 통과평점·강화 rules 등 온라인 후속 인수
10월 3일 최종 제출본Unity UI 회귀 131개 검사 통과, Release AAB 오류 0·경고 7616KB 메모리 페이지 크기 실제 기기 검사
10월 3일 Play 업데이트LG V50(Android 12)에서 code6→7 업데이트 후 저장 파일 3개 동일·기존 계정 재연결 확인신규 설치 인증·다른 기기·IME와 일부 구매 동작

144레벨 데이터 통합을 완료했고, 기존 QA의 잔여 항목도 보관했습니다. 남은 범위는 125레벨 전수 실기기 플레이, 신규 설치 인증, 다른 기기와 16KB 메모리 페이지 크기 환경, 일부 IME·구매 동작 및 온라인 운영 검증입니다.

게임 소개

플레이어는 격자 위에서 상하좌우로 인접한 칸을 이어 시작 칸으로 돌아오는 고리를 그립니다. 고리가 닫히면 경로 위의 유닛들이 순환 이동합니다. 꽃과 돌꽃으로 흙 타일을 모두 채우고 얼음의 이동 제한을 지키면 클리어입니다.

고리 위에 놓인 유닛만 이동합니다. 고리 안쪽 영역 전체가 움직이는 방식은 아니며, 닫기 전에 손을 떼면 경로를 취소합니다.

규칙은 한 문장이지만, 타일과 유닛 속성이 더해지면 경로를 거꾸로 돌려야 하거나 두 칸씩 밀어야 하는 상황이, 또 같은 유닛을 너무 많이 건드리면 안 되는 상황이 생깁니다.

핵심 게임플레이

타일 (바닥 속성)

타일설명
흙 (Dirt)목표 칸. 위에 꽃 / 돌꽃이 있어야 정답
일반 (Normal)아무 제약 없는 기본 칸
쓰레기 (Trash)꽃이 올라가면 실패 → 자동으로 이동 취소. 단, 돌꽃은 허용
더블 (Double)이 칸을 지나는 경로는 2칸씩 이동
역방향 (Reverse)이 칸을 지나는 경로는 반대 방향으로 이동 (더블과 겹치면 반대로 2칸)

유닛 (칸 위의 말)

유닛설명
꽃 (Flower)흙 위로 옮겨야 하는 주인공. 현재 버전은 도자기풍 스프라이트 리그로 표현
돌 (Stone)장애물 겸 채움 유닛. 클리어 시 화면 밖으로 튕겨 나가는 연출
돌꽃 (StoneFlower)여분의 꽃. 흙·쓰레기 모두 허용되는 예비 정답 유닛
얼음 (Ice)이동 횟수가 3회 미만이어야 클리어 가능. 이동·취소·리셋에 따라 카운트와 이미지를 갱신

조작과 이동

진행 구조

맵 에디터 & 커스텀 맵 공유 (대표 기능)

단순 플레이를 넘어, 유저가 직접 맵을 만들고 공유할 수 있는 파이프라인을 구현했습니다.

  1. 인게임 에디터: 그리드에 타일/유닛을 찍어 맵을 만듭니다. 기존 레벨을 불러와 수정하는 모드(Edit)도 지원합니다.
  2. 제작 검증: 빈 칸 위 유닛 금지, 모든 칸 채우기, 꽃 수 ≤ 흙 수 ≤ 꽃 + 돌꽃 균형, 최소 1송이 필요 등 보드 형식과 배치 조건을 코드로 검증합니다. 풀이 여부는 이어지는 플레이테스트에서 확인합니다.
  3. 플레이테스트 → 정답 자동 생성: 제작자가 자기 맵을 직접 풀면, 그 풀이 경로를 정답으로, 경로 길이 합계를 기준 비용으로 기록합니다. 이 값은 최단 해법을 증명한 결과와 구별합니다. “클리어해야 업로드 가능”이라는 규칙이 곧 정답 데이터 검증인 셈입니다.
  4. 공유: 완성한 맵을 Firebase Firestore에 업로드합니다. 다른 유저는 최신순 / 별점순 / 플레이 횟수순에 제목·제작자 검색과 기믹 필터를 조합해 맵을 찾아 플레이합니다.

게임 모드는 Normal / PlayTest / Custom / Edit 4종으로 나뉘며, 같은 게임 씬이 모드에 따라 다르게 동작합니다.

기술 구조

혼자 처음 만들었던 이전 프로젝트들의 시행착오를 정리해, 확장 가능한 구조 설계에 집중한 프로젝트입니다.

매니저 허브 패턴

Managers 싱글톤 하나가 DontDestroyOnLoad로 살아남아 10개 하위 매니저(Data·Firebase·Input·Localization·Level·Resource·Scene·Setting·Sound·UI)에 정적 프로퍼티로 접근합니다. 어디서든 Managers.Sound.Play(...) 식으로 일관되게 호출합니다.

유한 상태 머신(FSM)으로 게임 흐름 관리

게임 진행을 GameState(Idle·Draw·Move·Result·UndoMove·GameWin·ResetLevel·Hint·Answer) 열거형으로 정의하고, SetState() 한 곳에서 상태 전이와 부작용을 통제했습니다. 입력·이동·판정·연출이 상태별 함수로 나뉘어 흐름을 따라가기 쉽습니다.

데이터 기반 레벨

레벨을 압축 문자열로 표현했습니다. 예를 들어 tile_data: "111111112000121", unit_data: "000110000000000"처럼 한 칸을 한 글자로 인코딩해 width × height 격자로 복원합니다. 레벨은 JSON으로 관리하고 ILoader 제네릭 패턴으로 로드해 Dictionary<int, Level>로 변환합니다(Newtonsoft.Json).

UI 프레임워크

UI_Base에서 열거형 이름으로 자식 오브젝트를 자동 바인딩(Bind<T>)하고, 버튼은 바인딩할 때 클릭 사운드를 자동으로 연결합니다. 팝업은 스택으로 관리하며 sortingOrder를 자동으로 올려 중첩 순서를 보장합니다(UI_Scene / UI_Popup).

저장 시스템

Easy Save 3를 제네릭 + 열거형 키로 감싸 타입 안전한 Save<TKey,TValue> / Load API로 추상화했습니다. 키 충돌 없이 코인·레벨 상태·세팅을 저장합니다.

연출

DOTween으로 순환 이동·2단 이동·착지·장면 전환을 연결했습니다. 현재 도자기풍 유닛은 CeramicUnitAnimator의 스프라이트 리그로 대기·이동·승리를 표현하고, 중단된 트윈과 자세를 복구합니다. 초기 버전의 Spine 연동 경험은 이 작업의 바탕이 됐습니다.

현지화 & 입력

백엔드 (Firebase)

익명 인증과 Google Play Games 계정 연결, Firestore 기반 커스텀 맵 업로드·조회·평점을 구현했습니다. 맵 본문은 payloadJson, 목록 정보는 별도 필드로 저장합니다. 서버 정렬과 문서 커서를 유지하며 제목·제작자 접두어와 기믹 조건을 검사하고, 한 번에 읽는 문서 수를 제한해 더 찾기로 이어갑니다. 소유권은 Firebase UID를 기준으로 판단합니다.

기억에 남는 구현

사용 기술 스택

Unity 6 · C# · 2D URP · DOTween · Spine (초기 버전) · Easy Save 3 · Newtonsoft.Json · TextMesh Pro · Firebase (Auth · Firestore) · Google Play Games