$

케이스 06 · 디버깅

Skyward — "연습하기"를 눌러도 빈 하늘만 뜨던 이유, 그리고 그 뒤에 숨어 있던 두 개의 버그

연습하기를 눌러도 아무 일도 없었다. 씬은 로드되는데 비행기가 끝내 안 나타났다. 실행 경로를 따라가니 네트워크 소유권 버그가 나왔고, 그걸 고치자 이번엔 비행기가 스폰되자마자 즉사하는 두 번째 버그가 드러났다. 이 글은 그 진단 과정이다. 무엇을 배제했고, 근본 원인 두 개가 무엇이었고, 어떻게 고쳤고, 살아 있는 Unity 에디터를 MCP로 직접 조종해 결과를 어떻게 검증했는지.

  • Unity 6
  • Netcode for GameObjects
  • Debugging
  • MCP

$

문제의식

메인 메뉴에서 "연습하기(PRACTICE)"를 눌러도 게임이 시작되지 않았다. 씬은 바뀌는데 비행기가 스폰되지 않아 빈 월드만 남았다. 사용자 입장에선 그냥 "게임이 실행 안 됨"이었다.

먼저 배제한 것들

추측 전에 범위부터 좁혔다. 버튼 와이어링은 멀쩡했고(씬에서 onClick 참조가 전부 연결돼 있었다), 빌드 세팅도 정상이었다(SampleScene이 등록돼 있어 LoadScene이 조용히 실패할 수 없었다). 죽은 버튼이 원인이 아니라, 씬 로드 이후 "게임이 실제로 시작되는" 단계가 문제였다.

근본 원인 ① — 네트워크 소유권

플레이어는 네트워크 오브젝트라, 호스트(서버)가 떠야만 스폰된다. 두 가지가 잘못돼 있었다. 첫째, 연습하기 핸들러는 씬만 로드하고 호스트를 아예 시작하지 않았다. 그러니 플레이어가 스폰될 수가 없었다. 둘째, 작동하던 호스트 경로들은 메인 메뉴에서 NetworkManager를 만들었는데, 플레이어 프리팹만 갖고 네트워크 프리팹 목록은 없는 불완전한 상태였다. 이게 씬 전환에서 살아남아 SampleScene의 완비된 NetworkManager를 밀어내고 싱글톤을 차지했고, 이후 총알·아이템·적 스폰을 깨뜨릴 수 있었다.

수정 ① — 제대로 된 NetworkManager가 호스트하게

메뉴에서 반쪽짜리 NetworkManager를 즉석으로 만드는 대신, 호스트 경로는 이제 "호스트 시작" 플래그만 켜고 씬을 로드한다. SampleScene엔 플레이어 프리팹과 전체 프리팹 목록을 모두 갖춘 NetworkManager가 이미 있어서, 씬 로드 후 부트스트래퍼가 그 NM으로 호스트를 시작한다. 연습·싱글·호스트가 이제 같은 경로를 공유하고, 연습하기가 드디어 플레이어를 스폰한다.

수정된 실행 흐름

  1. Press Practice

    메인 메뉴 버튼

  2. PendingHost + LoadScene

    메뉴에선 NM 안 만듦

  3. SampleScene NetworkManager

    플레이어 + 전체 프리팹 목록

  4. StartHost

    씬 로드 후 부트스트래퍼

  5. Player on runway

    카메라·미니맵 추적

근본 원인 ② — 검증하다 발견

실행을 고치자 더 고약한 버그가 드러났다. 비행기가 이제 스폰은 되는데, 몇 초 만에 죽었다. 콘솔이 전말을 알려줬다. 충돌 데미지를 다섯 번 받고 HP가 0이 됐다. 비행기엔 스폰/택싱 무적 구간이 있는데, 그게 지형 충돌만 막고 있었다. 적과의 충돌은 무적을 전혀 확인하지 않는 별도 체력 경로로 처리됐다. 적은 플레이어 앞쪽에서 스폰돼 날아오니, 활주로에 멈춰 "무적"이어야 할 비행기가 그대로 죽고 있었다.

수정 ② — 무적이 진짜 무적이게

기존 무적 구간을 단일 진실 소스로 노출하고, 체력 시스템이 그걸 따르게 했다. 스폰/택싱 구간 동안엔 모든 데미지(지형뿐 아니라 적 충돌·총알까지)를 무시한다. 가는 길에 작은 에러도 하나 잡았다. 사망 처리 루틴이 kinematic 바디에 velocity를 설정해 Unity가 거부하고 있었는데, 이제 비-kinematic일 때만 실행한다.

검증 — 살아 있는 에디터를 MCP로 직접 조종

고쳤다고 단언하는 대신, MCP 브리지로 구동 중인 Unity 에디터를 직접 조종해 검증했다. 메인 메뉴를 로드하고, 플레이 모드에 진입하고, 실제 연습하기 버튼을 호출한 뒤, 콘솔을 되읽었다. 로그가 깨끗하게 나왔다. "StartHost 완료", "활주로에 플레이어 스폰", 카메라·미니맵 연결, 그리고 결정적으로 사망 로그도 velocity 에러도 없었다. 비행기는 무적 구간이 끝난 뒤에도 풀피로 계속 비행했다. 컴파일된다는 말이 아니라 직접 관찰한 동작으로 확인하고 싶었다.

동작 화면 — 플레이 모드에서 캡처

Skyward gameplay: a Spitfire flying in third person with a full HUD — compass, minimap, HP and MP bars at 100/100, and weapon buttons
두 수정 이후의 연습 모드: Spitfire가 공중에서 HP 100/100으로 살아 있고, 전투 HUD(나침반·미니맵·체력/마나 바·무기 버튼)가 전부 떠 있다. 구동 중인 게임 뷰에서 MCP로 바로 뽑은 스크린샷.

배운 것

두 가지를 배웠다. 첫째, "실행이 안 된다"는 사실 후보 원인이 셋이었고, 값싼 것들(와이어링·빌드세팅)부터 배제하니 소유권 문제로 바로 좁혀졌다. 둘째, 보이는 버그를 고치자 진짜 버그가 드러났다. 스폰은 되는데 죽는 비행기는 사용자에겐 여전히 "게임이 안 되는" 것이다. 그래서 검증은 "컴파일된다"가 아니라 관찰된 동작까지 가야 한다. 무적은 두 시스템에 쪼개져 있던 하나의 개념이었고, 그걸 합친 게 진짜 수정이었다.

$

근거 · 깃·위키 인용

  • MainMenuNetworkUI — 호스트 경로가 SampleScene NM에 위임 · Assets/Scripts/Network/MainMenuNetworkUI.cs
  • NetworkBootstrapper — 씬 로드 후 StartHost · Assets/Scripts/Network/NetworkBootstrapper.cs
  • PlayerHealth — 스폰 무적 적용·kinematic velocity 수정 · Assets/Scripts/Player/PlayerHealth.cs
  • ArcadeFlightController — IsCrashInvincible 공개 · Assets/Scripts/Player/ArcadeFlightController.cs