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

한눈에 보기

항목내용
장르캐주얼 퍼즐 (선 잇기 / 순환 이동)
엔진Unity 6 (6000.3.2f1), 2D URP
플랫폼Android (세로 모드, 1080×2280), com.GDH.ChainPuzzle
버전1.0.2
분량2개 월드 × 12레벨 = 기본 레벨 24종 + 유저 제작 맵 무제한
언어한국어 / 영어 (런타임 전환)

역할 분담

3인 협업 프로젝트입니다. 제가 맡은 부분과 협업 내용은 다음과 같습니다.

본인 (이영호) 담당

협업

게임 소개

플레이어는 격자 위에서 인접한 칸을 이어 선(체인)을 그립니다. 시작 칸으로 돌아와 닫힌 도형을 만들거나 선만 이어도, 경로 위의 유닛들이 한 칸씩 순환 이동합니다. 이 회전을 이용해 꽃을 흙 타일 위로 모두 올리면 클리어입니다.

튜토리얼 문구

  • “꽃을 흙으로 옮기세요! 사각형을 그려서 옮기세요.”
  • “사각형이 아니여도 선만 이어지면 이동합니다.”

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

핵심 게임플레이

타일 (바닥 속성)

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

유닛 (칸 위의 말)

유닛설명
꽃 (Flower)흙 위로 옮겨야 하는 주인공. Spine 스켈레톤 애니메이션
돌 (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단 이동, 돌 폭발 낙하 연출 등). 꽃·돌꽃은 Spine 2D 스켈레톤 애니메이션(Idle/Move/Win)으로 표현합니다.

현지화 & 입력

백엔드 (Firebase)

익명 인증 + Google Play Games 로그인, Firestore로 커스텀 맵 CRUD를 처리합니다. 맵 본문은 JSON 문자열(payloadJson)로 저장하고, 정렬·검색용 메타데이터(제목·제작자·별점·생성시각)는 필드로 분리해 접두어 검색과 페이지네이션을 구현했습니다.

기억에 남는 구현

사용 기술 스택

Unity 6 · C# · 2D URP · DOTween · Spine (2D 스켈레톤) · Easy Save 3 · Newtonsoft.Json · TextMesh Pro · Firebase (Auth · Firestore) · Google Play Games