게임 제작 기록/AI 게임 개발 일지

[AI로 모바일 게임 개발 - 5] 기반 코드 생성, 플레이어 이동 구현

가을고양이 2026. 3. 7. 22:53

서론

명세를 정말 오래도 짰다. 이제, 진짜 프로토타입 개발을 시작해보자.


Phase 1 — 기반 (다른 모든 것이 여기에 의존)

 

먼저, 자신은 의존하지 않지만 다른 코드가 의존하는 코드들을 생성한다.

 

1. ServiceLocator

ServiceLocator는 디자인 패턴 중 하나인 ServiceLocator 패턴이다.

유니티에서 개발하다보면, 흔히 Manager로 명명한 전역 시스템이 늘어난다. 그리고 보통, 이걸 전부 Singleton화 시킨다.

ServiceLocator는, 쉽게 말해 모든 전역 시스템 인스턴스를 한 곳에 모은 저장소다. 여러 Singleton이 분산되어 있는 것을 한 곳에 모아, 관리가 용이하고 스크립트에서 호출도 편해진다.

 

오죽하면 이런 경고 문구도 적어놨다.

 

여기서 궁금한 점이 생겼다. 결국 코드 상에서, 타입이 명시되는 건 싱글톤과 같지 않나? 그래서 블로그를 몇 개 참고하고, 또 제미나이에게 개념을 물으며 공부를 시작했다. 그에 따라, 싱글톤을 사용할 때와 달라지는 건 아래처럼 정리할 수 있었다.

 

1-1. Class가 아닌, Interface를 바라본다.

겉보기엔 똑같아보일 수 있다. SoundManager를 호출하는 것과, IAudioService를 호출하는 건, 결국 사운드를 관리하는 클래스를 호출한다는 점에서 비슷하다.

 

하지만, SoundManager는 구체화된 클래스다. 만약, 플랫폼 별로 다른 SoundManager를 갖는다면? 어디선 #if로 나눠서 관리하기엔 너무 번거롭다.

인터페이스로 구현했다면, 구현된 클래스가 무엇이든, 인터페이스만 붙어 있으면 제대로 동작한다. 그런 면에서, 아주 약간은 더 느슨한 결합을 갖고 있다.

 

1-2. 찾는 방식 통일

싱글톤은 누가 뭐라하든, 결국 각각의 인스턴스다. 다양한 싱글톤이 있는 만큼, 다양한 클래스를 호출해야 한다. 이는 곧, 의존성을 가진 객체가 많아진다는 뜻이다.

그렇지만 ServiceLocator는, 일단 ServiceLocator를 호출하고 이후 코드를 작성하면 된다. 모든 의존성을 ServiceLocator가 담당한다. 그러니, 어떻게보면, 의존되는 클래스간의 관계가 확 줄어든다고 볼 수도 있겠다.

 

1-3. 생명 주기 분리

사실 유니티에서 쓰는 이유는 이게 제일 커보였다.

유니티는 씬이 여럿 존재하고, 각 씬의 데이터는 공유되지 않는다. 그러니 전역 시스템을 개발할 때, 일반적으로 싱글톤은 DontDestroyOnLoad로 삭제되지 않는 클래스로 만들곤 한다.

 

그런데 이 경우, 문제가 발생한다. 만약, A씬에선 전역 시스템으로 기능하지만 B씬에선 사용되지 않는 기능이라면? (그게 진짜 전역 시스템인지는 둘째치고) DontDestroyOnLoad가 붙은, B씬에서도 쓰진 않지만 메모리를 점유하는 싱글톤으로 둘 것인가? 혹은, 싱글톤을 쓰지 않는 대신 A씬에서 매번 Find를 호출할 것인가?

 

ServiceLocator는 C# 클래스로, 유니티의 생명 주기에 영향받지 않는다. 정말로, 원할 때 등록하고, 안 쓸 땐 잠시 해제해두는 게 가능하다. 이는 MVP 패턴을 채택하고, 직접 의존성을 주입하는 입장에선 꼭 필요한 기능이다.

 

2. InputState enum

이게 다다!

다행히, 이젠 쉬운 것들로 넘어온다. 내가 건네준 기획서엔 탭, 드래그, 홀드, 스와이프가 존재했고, 그에 맞춘 enum을 생성했다.

JustDodge는 적의 공격 타이밍에 맞춰 회피했을 때 발동하는 건데, 왜 얘까지 InputState로 있는 걸까. 나중에 물어봐야겠다.

 

3. GestureRecognizer

제스쳐를 입력받는 클래스다. 모든 입력을 담당하며, 각 입력당 이벤트를 들고 있는 친구다.

 

클로드가 위 3개 스크립트를 전부 생성한 후, 테스트도 요청하였다.

 

더보기

알겠습니다. 앞으로 그 방식으로 진행하겠습니다.

그리고 좋은 포인트입니다. Android 플랫폼에서 Game 뷰 마우스 입력이 안 되니, Device Simulator가 테스트 환경이 되겠네요. 이건 GestureRecognizer 설계에 영향을 줍니다.

Device Simulator는 터치 입력을 실제 UnityEngine.InputSystem.EnhancedTouch로 전달하므로, Mouse 바인딩 대신 Touch 바인딩 하나만 잡으면 Device Simulator와 실제 기기 모두 동일하게 동작합니다. PC 마우스 에뮬레이션은 Device Simulator가 알아서 처리해줍니다.

이 전제로 Phase 1을 시작합니다.


생성 순서: InputState → ServiceLocator → GestureRecognizer

컴파일 확인합니다.에러 없음. 이제 씬에 테스트용 디버그 오브젝트를 만들겠습니다.

GestureDebugger — Device Simulator에서 현재 InputState를 화면에 표시하는 임시 스크립트입니다.씬에 InputManager 오브젝트를 만들고 두 컴포넌트를 붙입니다.아직 컴파일이 안 끝났을 수 있습니다. 콘솔을 확인합니다.Game.Debug 네임스페이스가 UnityEngine.Debug를 가리고 있습니다. ServiceLocator.cs에서 Debug 호출을 UnityEngine.Debug로 명시합니다.Game.Debug 네임스페이스가 GuidelinesSync.cs의 Debug.Log도 가리고 있습니다. GuidelinesSync.cs에 using Debug = UnityEngine.Debug; 별칭을 추가해 해결합니다.별칭이 적용되지 않았습니다. 근본 원인은 Game.Debug 네임스페이스 자체입니다. GestureDebugger.cs의 네임스페이스를 Game.Debug에서 Game.UI.Debug로 변경하는 것이 깔끔한 해결책입니다.에러 제로. 이제 씬에 InputManager를 생성합니다.씬을 저장합니다.---

작업 완료 보고

Phase 1 구현 완료. 생성된 파일 3종:

  • 10_Scripts/Core/ServiceLocator.cs — Register/Get/Unregister/Clear
  • 10_Scripts/Input/InputState.cs — None/Drag/Tap/Swipe/Hold/JustDodge
  • 10_Scripts/Input/GestureRecognizer.cs — Touch 기반 제스처 판별, 저스트 회피 윈도우 포함
  • 10_Scripts/Input/GestureDebugger.cs — 테스트용 (Phase 2 전 제거 예정)

이슈 하나 발생 및 해결: Game.Debug 네임스페이스가 UnityEngine.Debug를 가림 → GestureDebugger 네임스페이스를 Game.UI.Debug로 변경. 이 내용은 세션 종료 시 AI_CONTEXT [6] 이슈에 기록하겠습니다.

테스트 방법:

  1. Device Simulator를 열고 Play
  2. 화면 하단 40% 영역에서 터치 입력
  3. 화면 좌상단에 현재 InputState, 콘솔에 Tap/Swipe/JustDodge 로그 확인

테스트 후 결과 알려주시면 Phase 2로 넘어가겠습니다.

 

중간에 Game.Debug와 UnityEngine.Denug가 충돌하는 일이 있었는데, 스스로 네임스페이스명을 바꾸며 살아남았다.

 

테스트 및 수정

이제 테스트해보자.

 

Drag는 Release 뒤에 나온다.

 

테스트 결과, 입력이 잘 들어가는 것을 확인했다.

시스템 자체는 잘 작동했지만, 한가지 아쉬운 점이라면, 여기에 사실 디버그 UI가 있다는 점이다. 화면 좌상단에 나타나야 할 UI가 나타나지 않았고, 이는 클로드의 UI 생성에 문제가 있다는 말이었다.

 

 

Input은 잘 되는데, 몇 가지 문제가 있어서 수정 요청을 할게.
  1. 생성되는 Debug Canvas의 UI Scale Mode가 Constant Pixel Size여서, Device Simulator의 기준인 Apple iPhone 12에선 글자가 상당히 작게 나와.
  2. UI가 생성될 때, Pivot이 X 0.5 Y 0.5로 고정되어서, Anchor와 Pos는 잘 잡았지만 화면 밖으로 넘어가 보이지 않았어. 그 외 화면 영역, Console 창에 나타나는 로그는 정상적이고 잘 작동해. 따라서 위 내용을 한번 수정 시도해봐.

 

더보기

두 가지 문제 모두 BuildDebugUI() 코드에서 수정합니다.

  1. CanvasScaler → ScaleWithScreenSize, 기준 해상도 1080x1920
  2. RectTransform pivot → 앵커에 맞게 (0, 1) (좌상단)로 설정

CreateText 시그니처에 pivot 파라미터가 없으니 추가합니다.

에러 없음. Play 후 Device Simulator에서 확인해주세요. 글자 크기와 위치가 잡혀서 나올 겁니다.

 

이제 디버그 로그도 잘 나온다.

 

제대로 수정되었고, 이 역시 Context에 추가되었다.

 


Phase 2 — 캐릭터 기반 클래스

 

캐릭터를 만들어보자

이번엔 만들 스크립트가 꽤 많다. 본격적으로 Character의 기반을 다질 차례다.

프롬프트는 길지 않았다. 그저 Phase 2의 실행을 요청했다.

 

더보기

GestureDebugger를 씬과 파일에서 동시에 정리합니다.DebugCanvas는 런타임 생성이라 Play 중 아니면 씬에 없습니다. InputManager에서 GestureDebugger 컴포넌트만 제거합니다.컴포넌트 제거 완료. 스크립트는 batch_execute에서 delete_script가 미지원(MCP-04)이라 직접 호출합니다.에러 없음. 씬을 저장하고 Phase 2 계획을 말씀드리겠습니다.정리 완료. Phase 2 계획입니다.


Phase 2 구현 계획

생성 순서는 의존성 기준입니다.

1. ICharacterView          (Interface) — View 계약 정의
2. CharacterStatData       (ScriptableObject) — 스탯 데이터
3. CharacterModel          (순수 C# 클래스) — 런타임 상태
4. CharacterPresenterBase  (추상 MonoBehaviour) — 입력 수신 + 로직 중재
5. CharacterView           (MonoBehaviour) — 플레이스홀더 스프라이트 표현

설계 포인트 두 가지 미리 확인:

첫째, CharacterPresenterBase가 GestureRecognizer 이벤트를 구독할 텐데, ServiceLocator로 가져올지 아니면 Inspector에서 직접 참조할지 결정이 필요합니다.

둘째, 플레이스홀더 스프라이트는 Unity 기본 Sprite(흰 사각형)로 시작하는 게 가장 빠릅니다. 별도 아트 없이 색상으로 캐릭터를 구분하면 됩니다.

두 가지 모두 기본 방향으로 잡겠습니다만, 이견 있으시면 말씀해주세요. 승인되면 바로 시작합니다.

 

인스펙터에서 일일이 할당하는 방식과, ServiceLocator를 통해 입력 이벤트를 가져오는 것. 굳이 물어본다는 건 장단점이 있다는 것. 다만, 기본 방향이 무엇인지 물어보았다.

 

 

1번 항목의 기본 방향은 둘 중 어떤 거지? 2번 항목은 그대로 진행하면 될 것 같아.

 

더보기

기본 방향을 말씀드리지 않았네요. ServiceLocator로 가져오는 방향입니다.

이유는 두 가지입니다. CharacterPresenterBase는 추상 베이스 클래스라 Inspector 참조를 잡으려면 자식 클래스마다 설정해줘야 합니다. 반면 ServiceLocator로 가져오면 Awake()에서 한 번만 호출하면 모든 캐릭터가 동일하게 동작합니다. 또한 GestureRecognizer는 이미 ServiceLocator에 등록하도록 설계되어 있어 일관성도 유지됩니다.

이 방향으로 진행할까요?

딱히 흠잡을 게 없다. 그대로 요청했다.

 

더보기

순서대로 진행합니다.컴파일 확인합니다.

에러 없음. 이제 씬에 플레이어 오브젝트를 만들고, CharacterStatData SO를 생성합니다.

플레이어 색상을 흰색으로 설정하고, CharacterStatData SO를 생성합니다.씬 저장 후 에러 최종 확인합니다.---

작업 완료 보고

Phase 2 구현 완료. 생성된 파일 5종:

파일 위치 역할
ICharacterView.cs Core/ View 계약 인터페이스
CharacterStatData.cs Data/ 스탯 SO 정의
CharacterModel.cs Characters/ 런타임 상태 (HP, 차지, 무적)
CharacterPresenterBase.cs Characters/ 입력 수신 + 공통 로직 추상 베이스
CharacterView.cs Characters/ 플레이스홀더 시각 표현

씬 및 에셋:

  • Player 오브젝트 생성 (SpriteRenderer + CharacterView, 하늘색)
  • PlayerStatData.asset 생성 (30_ScriptableObjects/Characters/)

현재 상태: CharacterPresenterBase는 추상 클래스라 Player에 직접 붙일 수 없습니다. Phase 3에서 PlayerPresenter(구체 자식 클래스)를 만들어 붙이고, Init 호출 및 이동 테스트를 진행하겠습니다.

Phase 3으로 바로 넘어갈까요?

 

테스트 및 수정

 

스크립트는 잘 만들어진 것 같은데, 테스트하기도 전에 Player의 Sprite가 비어 있는 에러가 발생했다.

그냥 넣을 수도 있지만, 앞으로도 같은 일이 발생할 수 있기에. 클로드에게 수정 요청을 보냈다.

 

  그전에, Player가 현재 Sprite가 None으로 설정되어 있는데, 이건 의도한 거야?

 

더보기

의도하지 않은 겁니다. URP 2D 프로젝트에서 SpriteRenderer를 코드로 추가하면 Sprite가 자동으로 할당되지 않습니다. Unity 기본 내장 스프라이트를 할당해드릴게요.

프로젝트에 스프라이트 에셋이 없습니다. 에디터 스크립트로 Unity 내장 기본 스프라이트를 할당하겠습니다.

성공/실패 로그가 없습니다. 스크립트가 아직 컴파일 중일 수 있습니다. 잠시 후 다시 실행합니다.

실행은 됐지만 로그가 안 찍히는 걸 보면, Edit 모드에서 GameObject.Find()가 씬의 Player를 못 찾고 있을 가능성이 높습니다. 직접 스프라이트를 지정하는 방식으로 바꾸겠습니다.

의도하지 않은 겁니다. 방금 에디터 스크립트로 할당을 시도했는데 아직 완료 로그가 확인되지 않은 상태였습니다. 다시 실행해보겠습니다.

할당 완료됐습니다. 임시 스크립트도 정리합니다.

Player에 UISprite(흰색 원형 사각형)가 할당됐습니다. Phase 3으로 넘어가도 될까요?

 

할당은 되었지만, 내가 원했던 Default-Sprite가 아닌, UISprite가 할당됐다.

확인해보니 Default-Sprite를 찾을 수 없었다.

 

우린 방법을 찾아낼 것이다. 늘 그랬듯이.

 

에셋 폴더와 패키지를 뒤지다가, Create - 2D - Sprite - Square로 생성해보니 제대로 사각형이 나왔다.

해당 경로를 복사해 클로드에게 알려주고, 앞으로 여기서 갖다 쓰라고 했다.

 

당연히 기록부터지.

 

Player가 성공적으로 Circle로 변경됐다. Character 관련 스크립트는 플레이 테스트가 불가능하니, cs가 잘 생성된 것만 보고 넘어갔다.


Phase 3 — 플레이어 동작 검증

이제 움직여보자

그리고, 다음 페이즈가 동작 검증이었기에. Character 관련 클래스가 잘못 만들어졌다면 여기서 문제가 생길 거라 판단한 것도 있다.

 

바로 클로드에게 실행 요청을 했다.

 

 

좋아. 이제 Phase 3로 넘어가보자. 그리고, 앞으로는 다음 페이즈로 넘어갈지 물을 때, 남은 Phase를 알려주면 더 좋을 것 같아.

 

그리고, 채팅 도중 다음 페이즈가 무엇인지 알기 어려워서, 매 페이즈 시작 전 알려달라고 추가로 요청했다.

 

더보기

알겠습니다, 앞으로 남은 Phase도 함께 안내하겠습니다.

현재 상태와 콘솔을 먼저 확인합니다.에러 없음. Phase 3 계획입니다.


Phase 3 구현 계획

목표: 플레이어가 Drag 입력으로 실제로 움직이고, 카메라가 따라오는 것을 Device Simulator에서 확인.

생성할 것:

  1. PlayerPresenter.cs — CharacterPresenterBase의 첫 번째 구체 구현체
    • Awake에서 Init(statData, view) 호출
    • CharacterStatData(PlayerStatData.asset)를 Inspector에서 참조
    • 이동은 베이스 클래스의 HandleDrag가 처리하므로, 추가 override 불필요
  2. CameraFollow.cs — 카메라가 Player를 부드럽게 추적
    • 2D 고정 Z축, Lerp 기반 추적
    • 추적 대상을 Inspector에서 지정

씬 작업:

  • Player에 PlayerPresenter 추가 + PlayerStatData.asset 연결
  • Main Camera에 CameraFollow 추가 + Player 연결

테스트 기준: Device Simulator에서 하단 40% Drag → Player 이동 + 카메라 추적 확인

진행할까요?


남은 Phase:

  • Phase 4 — CombatSystem + 일반 적 + 웨이브 매니저
  • Phase 5 — UI (HP바, 차지 게이지, Debug 패널)
  • Phase 6 — 첫 번째 캐릭터 고유 메커니즘 + 저스트 회피 슬로우

 

Phase 3의 구현 기능은 단순했다.

  1. 플레이어가 제대로 움직이고
  2. 카메라가 플레이어를 잘 따라간다.

카메라가 따라가게 할 생각은 없었는데, 화면을 고정해두면 플레이어의 활동 범위가 너무 크게 제한될 것 같아, 아무 말 않고 수용했다.

 

더보기

순서대로 진행합니다.에러 없음. 씬 작업을 진행합니다. Player에 PlayerPresenter 추가, Main Camera에 CameraFollow 추가를 한 번에 처리합니다.

이제 PlayerPresenter에 PlayerStatData.asset을 연결하고, CameraFollow에 Player Transform을 연결합니다. 둘 다 Inspector 참조라 에디터 스크립트로 처리합니다.

두 참조 모두 연결 완료. 임시 스크립트 정리하고 씬을 저장합니다.---

작업 완료 보고

Phase 3 구현 완료. 생성 파일 2종:

  • Characters/PlayerPresenter.cs — CharacterPresenterBase 구체 구현체, ServiceLocator 등록
  • Core/CameraFollow.cs — LateUpdate Lerp 기반 2D 카메라 추적

씬 연결:

  • Player → PlayerPresenter + PlayerStatData.asset 연결
  • Main Camera → CameraFollow + Player Transform 연결

테스트 방법: Device Simulator에서 Play → 하단 40% 영역을 Drag → Player(Circle)가 이동하고 카메라가 따라오는 것을 확인

테스트 후 결과 알려주시면 Phase 4로 넘어가겠습니다.

남은 Phase:

  • Phase 4 — CombatSystem + 일반 적 + 웨이브 매니저
  • Phase 5 — UI (HP바, 차지 게이지, Debug 패널)
  • Phase 6 — 첫 번째 캐릭터 고유 메커니즘 + 저스트 회피 슬로우

 

작업 완료 후 에러가 하나 나타났다. 콘솔 에러고, 꽤나 명확했기에 그대로 수정 요청을 보냈다.

 

[PlayerPresenter] GestureRecognizer가 ServiceLocator에 등록되지 않음 에러가 발생했어. 확인 후 수정 부탁해.

 

더보기

원인이 명확합니다. GestureRecognizer를 ServiceLocator에 등록하는 코드가 GestureDebugger에 있었는데, Phase 2 정리 시 삭제해버렸습니다. 지금은 등록하는 주체가 없는 상태입니다.

InputManager 오브젝트에 등록 역할을 직접 부여하겠습니다.컴파일 완료. InputManager에 컴포넌트를 추가합니다.---

작업 완료 보고

원인: GestureRecognizer의 ServiceLocator 등록이 GestureDebugger 안에 있었는데, Phase 2 정리 때 함께 삭제됐습니다.

수정: InputSystemInitializer.cs 생성 → InputManager에 추가. Awake에서 등록, OnDestroy에서 해제하는 명확한 책임 분리 구조로 재설계했습니다.

이 패턴이 앞으로도 기준이 됩니다. 등록 책임은 항상 전용 초기화 컴포넌트가 갖습니다. 다시 Play해서 에러 없이 이동되는지 확인해주세요.

 

임시 코드로 만들었던 GestureDebugger에 중요한 코드가 있었다. 새 스크립트가 생성되었고, 추가되었다.

 

테스트 및 수정

C# 시스템은 스스로 테스트를 실행하고, 오류가 있으면 스스로 고쳤다. 하지만 Play를 누르고 플레이어가 입력을 해야 하는 경우는, 내가 테스트를 해줘야 했다.

 

움직이고 있는 거 맞지?

 

원이 아주 살짝 움직이고, Position이 변하는 것은 확인했다. 하지만 이게 정말, 제대로 움직이고 있는 건지, 얼마나 빨리 움직이고 있는지는 알 수 없었기에, 추가 요청을 보냈다.

 

테스트 결과를 알려줄게.

  1. Drag 시 Player의 Position이 변하는 것을 확인, 그러나 배경이 없어 속도감이 느껴지지 않고, 얼마나 이동하는지 알 수 없음. 이에 패턴이 있는 배경 생성을 요청함. 배경은 유한하며, 끝(벽)이 존재.
  2. 드래그 시, 일정 거리 이동 후 멈춤을 확인. 스와이프의 로직이 드래그에 들어간 것으로 추정.
  3. 스와이프 시 캐릭터가 움직이지 않음.
  4. 홀드 시 차지하며 색이 변하는 것을 확인
  5. 캐릭터의 크기가 화면에 비해 너무 큼. 현재 크기의 0.6 정도가 비율 상 적절해보임. 그러나 Player의 Scale을 조정하지 말고, Camera의 Size를 조절해 구현 요망
  6. Tap, Drag, Hold, Swipe 등의 수행을 하지만, 테스트 로그가 나타나지 않아 테스트하는 입장에서 제대로 반응 중인지 즉각적으로 알기 어려움.

 

더보기

6가지 이슈를 분석합니다.

  • 2번 (Drag 중 멈춤) / 3번 (Swipe 미이동): GestureRecognizer에서 HandleFingerMove가 _touchDuration >= SWIPE_MAX_DURATION 조건을 만족해야 Drag로 판별하는데, 그 전까지는 아무 이동도 없습니다. 즉 0.3초 이전엔 이동이 안 됩니다. Drag 이동은 OnFingerMove에서 즉시 처리해야 합니다.
  • 1번 (배경): 격자 패턴 배경 + 벽 생성
  • 5번 (카메라 Size): Camera.orthographicSize 조정
  • 6번 (테스트 로그): 간단한 온스크린 로그 재도입

코드부터 수정합니다.

구조를 파악했습니다. HandleFingerMove와 HandleFingerUp의 판별 로직을 수정합니다. Drag는 거리 조건만으로 즉시 발행하고, Swipe는 FingerUp 시 시간으로 구분합니다.

이제 이동 로직을 수정합니다. CharacterPresenterBase의 HandleDrag가 스크린 델타를 월드 이동량으로 변환하는 방식이 잘못됐습니다. 픽셀 단위 델타를 월드 좌표로 변환해야 합니다.

다음으로 배경 + 벽, 카메라 Size, 온스크린 로그 3가지를 스크립트로 처리합니다.

UnityEditor 네임스페이스는 런타임에서 사용 불가합니다. 에디터/런타임 모두 동작하도록 수정합니다.

이제 플레이어 이동 경계 클램프를 CharacterPresenterBase에 추가하고, 온스크린 로그 스크립트를 만듭니다.

StageBuilder를 사용하려면 using Game.Core;가 필요합니다. CharacterPresenterBase에 추가합니다.

이미 있습니다. 이제 온스크린 로그 스크립트를 만듭니다.

컴파일 확인 후 씬 오브젝트를 구성합니다.

씬에 Stage와 UILogger 오브젝트를 추가하고 카메라 Size를 조정합니다.

StageBuilder를 ServiceLocator에 등록하고, 카메라 Size를 조정합니다.

using Game.Core;를 StageBuilder에 추가합니다.

StageBuilder가 이미 Game.Core 네임스페이스 안에 있으므로 별도 using 불필요합니다. 카메라 orthographicSize를 조정합니다. 현재 기본값 5에서 약 0.6배인 8 정도로 설정합니다 (더 큰 값 = 더 작게 보임).

최종 컴파일 및 씬 저장합니다.---

작업 완료 보고

6가지 이슈에 대한 수정 내용입니다.

1. 배경 + 벽 → StageBuilder.cs 생성. 격자 패턴 배경(20×30 월드), 상하좌우 벽(BoxCollider2D) 포함. Stage 오브젝트로 씬에 추가.

2. Drag 즉시 이동 / 3. Swipe 미동작 → GestureRecognizer의 핵심 버그 수정. 기존엔 0.3초 이후에만 Drag가 발행됐는데, 거리 조건만 충족되면 즉시 발행하도록 변경. Swipe/Drag 구분은 FingerUp 시 지속 시간으로 판정.

4. Hold 차지 → 정상 확인, 변경 없음.

5. 캐릭터 크기 → Camera orthographicSize 5 → 8로 조정 (캐릭터 Scale 미변경).

6. 테스트 로그 → OnScreenLog.cs 생성. 우상단 반투명 패널에 최근 10줄 입력 로그 표시. UILogger 오브젝트로 씬에 추가.

추가로 HandleDrag의 스크린→월드 좌표 변환 버그도 함께 수정했습니다. 다시 테스트해주세요!

 

 

배경이 생기자 움직임 알아보긴 훨씬 쉬워졌다.

 

그럼에도 Drag 이슈가 고쳐지지 않았고, 이에 아예 명세를 다르게, 새로운 요청을 보내보았다.

 

배경 및 카메라, Swipe가 동작하는 것을 확인했고, 테스트 로그 역시 잘 나타나. 다만 한 가지 수정 요청을 할게.

현재 Drag 시, 계속해서 이동 중 멈추는 현상이 있어서, 로직 자체를 수정해야할 것 같아.

기획서에 적힌 Drag는, 마치 가상 조이스틱처럼, 누른 시점에 조이스틱이 생성되고, 손가락을 움직여 특정 방향을 향하면, 그쪽으로 계속해서, 쭉 걸어가는 로직이야.

이에 가상 조이스틱을 띄우되, Tap과 Hold, Swipe 시엔 나타나지 않게 하고, 드래그 중엔 계속해서, 일정한 속도로 해당 방향으로 움직이게 해줘.

반대로, Swipe는 특정 방향으로 Swipe 시, 평소 이동 속도보다 빠르게, 일정 거리만큼 이동하는 대시를 수행해야 해.

추가로, 기획자 및 테스터가 플레이어의 속도 및 대시 거리 등을 쉽게 변경할 수 있어야 할 텐데, 이건 어디서 조정하면 될지도 알려줘.

 

더보기

로직을 완전히 재설계해야 하는 수정입니다. 정리하고 진행합니다.

변경 사항:

  1. GestureRecognizer — Drag 판별 제거. Move(조이스틱)와 Swipe를 명확히 분리
  2. CharacterPresenterBase — 조이스틱 방향 기반 Update 이동으로 변경
  3. CharacterStatData — 대시 거리/속도 배율 필드 추가 (조정 포인트)
  4. 가상 조이스틱 UI 추가

먼저 GestureRecognizer를 재설계합니다.

이제 CharacterStatData에 대시 관련 필드를 추가합니다.

이제 CharacterPresenterBase의 이동 로직을 조이스틱 방식으로 전면 교체합니다.

이제 이벤트 구독 부분에 OnMoveDirection/OnMoveEnd 구독을 추가하고, OnEnable/OnDisable을 수정합니다.

이동/대시 핸들러를 추가하고, 기존 HandleDrag를 교체합니다.

Swipe 핸들러를 대시로 변경합니다.

이제 가상 조이스틱 UI 스크립트를 만듭니다.

OnScreenLog에서 OnDragDelta → OnMoveDirection으로 수정합니다.

씬에 VirtualJoystick 오브젝트를 추가하고 저장합니다.---

작업 완료 보고

이동/대시 로직 전면 재설계 완료.

핵심 변경:

  • GestureRecognizer — OnDragDelta 제거. OnMoveDirection(dir) (매 프레임, 조이스틱 방향)과 OnMoveEnd 추가. Swipe는 SWIPE_MIN_DISTANCE 60px + 0.25초 이내의 빠른 플릭으로 명확히 구분.
  • CharacterPresenterBase — Update()에서 _moveDirection * moveSpeed로 매 프레임 일정 속도 이동. Swipe 시 dashDistance / dashSpeed로 대시 처리.
  • VirtualJoystick.cs — Move 중에만 원형 조이스틱 표시, 나머지 입력 시 숨김.

밸런스 조정 위치 (기획자/테스터용):

PlayerStatData.asset을 Inspector에서 선택하면 다음 수치를 바로 조정할 수 있습니다.

항목 필드명 기본값
이동 속도 moveSpeed 5
대시 거리 dashDistance 4 (월드 단위)
대시 속도 dashSpeed 20 (높을수록 빠름)
회피 무적 시간 dodgeInvincibleDuration 0.2초

테스트 후 결과 알려주시면 Phase 4로 넘어가겠습니다.

남은 Phase:

  • Phase 4 — CombatSystem + 일반 적 + 웨이브 매니저
  • Phase 5 — UI (HP바, 차지 게이지)
  • Phase 6 — 첫 번째 캐릭터 고유 메커니즘 + 저스트 회피 슬로우

 

 

 

아쉽게도, 드래그하면 계속 움직이게는 바꼈으나, 이번엔 Swipe가 잘 인식되지 않았다. 그뿐만 아니라, Drag로 움직이는 중에도 계속 버벅거렸다.

 

이에 수정 요청을 보내려 했지만 토큰이 모두 소모되었고, 오후 7:00까지 기다리란 말이 무색하게, 7시가 지나도 토큰이 회복되지 않았다.

 

그래서, 아쉽지만 이번 회차는 여기서 마무리하고, 클로드가 회복되면 다시 프롬프트를 보내며 작업을 이어가야 할 것 같다.


마무리

드디어 진짜 코딩의 시작, 프로토타입 개발에 들어섰지만, 금방 한도에 걸리며 많이 진행하지 못했다. 차라리 기능이 완성되고 한도가 끝났으면 좋았을 텐데, 수정 도중에 끝난 게 더 아쉬웠다.

 

계속 해보고 싶지만 밀린 일이 많아, 다음 시도가 언제가 될진 모르겠다. 클로드가 빨리 한도를 풀어주길 바랄 뿐이다.