01게임과 제 역할
야간 경비원이 되어 태블릿의 근무수칙을 지키며 5일 동안 학교를 순찰합니다. 하루는 출근 → 회사 문자 지시 → 점검 → 몬스터 조우 → 판정 → 퇴근 · 근무일지 순서로 흐릅니다.
INSTRUCTION 플레이 영상 · YouTube
수칙을 어기면 보이지 않는 청각 · 조도 · 배치 축이 오르고, 오를수록 학교의 소리 · 조명 · 배치가 변합니다. 한 축이라도 끝까지 오르면 붙잡혀 그 밤을 다시 시작합니다. 수칙을 잘 지키면 신뢰가 오릅니다. 신뢰가 높을수록 수칙서 글자가 바뀌는 변조, 수칙과 반대로 시키는 회사 문자(역설), 두 수칙이 부딪히는 딜레마가 늘어나, 잘하는 플레이어일수록 수칙 자체를 의심하게 됩니다.

팀과 역할
| 이름 | 역할 | 맡은 일 |
|---|---|---|
| 이성현 | 시스템 프로그래밍 시스템 기획 | 수칙 판정 · 공포 축 · 편성(수칙 덱 · 조우 · 문자) 규칙과 데이터, 판정 센서(문 · 손전등 · 응시 · 근접 · 공간 출입), 공포 디렉터, 판정 결과로 조명 · 정전 · CCTV · 조우 · 붙잡힘 흐름 · 경비실 · 사운드를 구동하는 코드, 게임 규칙 · 수칙 공동 기획 |
| 김진선 | 클라이언트 프로그래밍 | 게임 플로우 · 씬 전환, 1인칭 조작, 태블릿 · 결과창 UI, 공포 연출 프리셋, 축별 사망 컷신, 화면 효과, 개발자 모드, 형상관리 |
| 김현웅 | 기획 · 사운드 | 사운드 리소스 제작(VARCO Sound), 게임 수칙 공동 기획, 시나리오 |
| 박재은 | 아트 | 맵 구성, 소품, 몬스터 모델 · 디자인(VARCO 3D), 애니메이션, UI |
프로그래머 둘은 판정 · 런타임 연동(저)과 조작 · UI · 컷신(김진선 님)으로 나눴습니다. 김진선 님은 연출 프리셋, 컷신, 화면 효과, UI처럼 화면에 보이는 부분을 만들었고, 저는 판정, 언제 어디서 어떤 연출을 부를지 정하는 디렉터 · 편성, 그리고 판정 결과에 따라 조명 · CCTV · 조우 몬스터를 움직이는 코드를 맡았습니다. 서로의 파일은 고치지 않기로 정하고, 두 파트는 이벤트(EventBus)와 공개 API로 연결했습니다. 다만 디버깅 모드를 하나로 합칠 때는 제 결정으로 김진선 님의 개발자 모드 파일에 직접 합쳤습니다.
- 고치지 않고 확장하기. 김진선 님의 사망 컷신 Timeline은 그대로 둔 채 재생되는 인스턴스만 보정했습니다.
- 씬 충돌 줄이기. 근무 씬 전용 컴포넌트를 씬 파일에 넣지 않고 실행할 때 코드로 붙였습니다(
RuntimeInitializeOnLoadMethod). 덕분에 씬 병합 충돌과 Git LFS 잠금 대기가 줄었습니다. - 아트와 병렬로. 모델이 확정되기 전에는 대역(임시 모델, Stand-in)으로 조우를 먼저 만들고, 모델이 오면 파일만 교체했습니다.
02구조 — 규칙(Core)과 화면(Flow)
판정 로직은 Unity에 의존하지 않는 일반 C#으로, 화면에 그리는 부분은 MonoBehaviour로 나눴습니다. asmdef로 Core가 Flow를 참조하지 못하게 막았고, Core에서 Flow로는 EventBus 이벤트로만 알립니다.
구조는 AI에게 여러 안을 받은 뒤, 판정 시스템이 없어도 밖에서 축 값을 넣어 볼 수 있는 안으로 골라 달라고 했습니다. 근무 씬이 저장소에 처음 올라온 9월 17일보다 먼저, 축 값을 읽는 인터페이스(IFearAxisReader)를 인스펙터 슬라이더로 구현해 테스트 씬에서 조도 · 청각 변화를 확인했습니다(커밋). 테스트 씬과 슬라이더는 10월 3일에 지웠고(커밋), 지금은 실제 축 시스템이 같은 인터페이스를 구현합니다.
Send · Tick 두 호출, Core → Flow는 EventBus 이벤트뿐입니다.
Flow는 NightRun의 공개 정적 멤버로 밤을 시작 · 진행 · 종료하고 현재 상태를 읽습니다. 반대로 Core는 Flow를 직접 호출하지 않고, 구간 변화 같은 이벤트(BandChanged · DirectionEmitted · Captured)만 보냅니다. 연출은 축 수치가 아니라 구간을 보고 바뀝니다.
- 게임을 켜지 않고 검증. Core는
new만 하면 돌아가므로 자동 테스트와 밸런스 시뮬레이션을 에디터에서 바로 돌렸습니다. 테스트 폴더 - 의존 방향은 컴파일 단계에서 막기. asmdef로 Core가 Flow를 참조하지 못하게 해서, 축이 올랐다고 Core에서 바로 불을 끄는 코드는 아예 컴파일되지 않게 했습니다.
- 새 코드를 어디 둘지 정해 둠. 고르는 코드는 편성 · 디렉터, 판단하는 코드는 판정 · 점검, 수치를 올리는 코드는 축, 화면에 그리는 코드는 Flow에 둡니다.

03공포 디렉터 — 놀람을 배분하는 규칙
준비된 효과음과 연출이 많았습니다. 무작위로 내보내면 놀람이 너무 잦아져 금방 무뎌질 거라고 봤습니다. 따로 잰 것이 아니라 제 경험에 비춘 예상입니다. 그래서 규칙을 두고 간격을 조절해 내보내기로 했습니다. 아이디어는 레프트 4 데드 2의 좀비 호드 디렉터에서 얻었습니다.
공포 디렉터는 맵을 돌아다니는 몬스터가 아니라, 놀람의 간격을 조절하는 규칙 묶음으로 만들었습니다. 그날 나올 조우는 편성이 정하고, 디렉터는 언제 · 어디서 터뜨릴지를 고릅니다. 디렉터를 두자는 방향과 무엇을 기준으로 조절할지는 제가 정했습니다.
긴장도에 따라 놀람을 거른다
- 사건이 일어날 때마다 긴장도가 오르고(가짜 놀람 +10, 대면 +10 + 10 × 강도), 4초 뒤부터 초당 1.2씩 내려갑니다.
- 상태는 축적 → 절정(70) → 해소(35) → 휴식으로 돕니다. 이와 별도로, 높은 긴장이 오래 이어지면 45초 동안 강제로 쉽니다.
- 사물함 덜컹, 손전등 깜빡임, 스쳐 보이는 형체 같은 가짜 놀람은 긴장이 쌓이는 단계에서 긴장도가 50 미만일 때만 냅니다. 하룻밤에 1일차는 2번, 5일차는 7번까지 내고, 같은 놀람은 한 밤에 두 번까지만 냅니다.
조우 한 번의 진행
- 대기
- 전조
- 배치 후 목격 대기
- 대면 · 대응
- 끝 단서
- 끝
정해진 시간 안에 시작 조건이 채워지지 않으면 놓침으로 끝납니다. 상태 이름은 코드(EncounterRunState)의 상태와 하나씩 대응합니다.
- 전조는 강도 3 이상 조우에만 1–8초 붙고, 전조만 주고 물러나는 헛예고도 섞습니다. 헛예고는 조우마다 한 번까지입니다.
- 대면하면 그 조우에 걸린 수칙을 기준으로, 플레이어가 수칙대로 대응했는지 판정합니다.
- 앞 조우가 끝나야 다음 조우를 엽니다.
플레이어를 그 자리로 부른다
점검 지시를 바꿀 때 이렇게 요구했습니다. 「점검이 한번에 떠있는게 아니라, 조절해서 메시지로 계속 업데이트 … 플레이어의 동선이나 위치, 긴장도를 계속해서 계산해서」
- 점검 지시를 밤 시작에 한꺼번에 주지 않고 공간 단위 문자로 하나씩 보냅니다. 다음 공간은 거리, 조우가 걸린 공간인지, 같은 동인지로 점수를 매겨 고르고, 조우 중 · 직후나 긴장이 높을 때는 미룹니다.
- 최종판은 날짜별 고정 편성이라(07절) 날짜표에 정한 조우를 하나씩 진행합니다. 앞 조우가 끝나고 15초 뒤에 다음 조우를 준비하고, 플레이어가 오지 않아 시작되지 않으면 「1-3 교실을 순찰하십시오」 같은 문자로 그 공간으로 부릅니다.
- 조우가 남은 채 03:30이 되면 시계를 붙들어, 그날의 조우를 모두 보기 전에는 밤이 끝나지 않습니다. 「이월은 없어. 의도한 날짜에 무조건 목격해야 해」
TensionDirector · TensionPacer · SurpriseBudget · InspectionDispatcherTensionDirector.cs
04수칙 · 지시 · 편성
하룻밤은 태블릿 수칙, 회사 문자 지시, 조우 세 층으로 짜입니다. 셋 다 밤 시작에 정하고, 재시작해도 다시 뽑지 않습니다.
| 층 | 정하는 기준 | 하루 분량 |
|---|---|---|
| 수칙 | 조우에 묶인 수칙은 그 조우가 있는 날에만 넣고, 남는 칸은 감각 세 축(청각 · 조도 · 배치)이 한 장씩 들어가게 채웁니다. 넘치면 조우 수칙이 아닌 것부터 뺍니다. | 1일차 4장 · 2–4일차 6장 · 5일차 7장 |
| 지시 | 점검 지시와 근무 지시를 번갈아 보냅니다. 신뢰 구간이 오르면 역설 · 변조 · 회피 불가가 붙습니다. | 점검 4–6항목 · 근무 3–4통 |
| 조우 | 날짜표대로 나오고, 그날의 클라이맥스만 맨 뒤에 둡니다. | 1일차 없음 · 2–5일차 2–4개 |

수칙마다 판정기가 하나씩 붙어 센서 신호를 받고 준수 · 위반을 냅니다. 일반 수칙은 처음 어길 때 그 축이 +12(밤에 한 번), 위협 수칙은 조우마다 실패하면 +20이고, 단서가 왔는데 끝까지 지키면 밤 끝에 신뢰가 +2 오릅니다.
신뢰 구간(10 · 18 · 26 · 42)이 오를수록 수칙과 반대로 시키는 역설 문자, 수칙서 글자가 바뀌는 변조, 두 수칙이 부딪히는 회피 불가가 차례로 열립니다. 문자가 무엇을 시키든 판정은 늘 수칙서 원본으로 합니다.
수칙 수와 지시 비중은 제가 정했습니다. 경비실 수칙 K3를 매일 넣고, 장수가 넘치면 조우에 묶이지 않은 수칙부터 빼게 했으며, 점검 지시와 근무 지시의 비중을 맞추게 했습니다. 「물품 점검이 비중이 더 높은데, 지시 사항과 비중이 균일했으면」
난수와 시드
편성기가 난수를 밖에서 받도록 만들어, 게임에서는 회차마다 새 난수를 사용하고 테스트에서만 고정 시드를 넣습니다. 시드 값은 그대로 두었고, 개발 중에는 어떤 항목을 언제 뽑아 고정할지만 달라졌습니다.
테스트는 시드 30개로 4일차 편성을 만들어, 클라이맥스가 늘 맨 뒤에 오는지 확인합니다.
ProgramDirector · NightProgram · ParadoxPlanner · FinalRuleBookNightProgram.cs
05구현 하이라이트
판정 결과를 화면으로 옮기는 부분입니다. 화면에서 무엇이 바뀔지와 그 기준은 제가 정했습니다.
조우별 상태 패턴과 구현
조우는 제가 설계했습니다. 진행은 03절의 흐름을 공통으로 따르고, 시작 조건과 결과가 갈리는 조건은 조우마다 다릅니다.
화장실 소녀
목격 전까지 문이 잠긴다
3번 칸 지시가 오면 칸 앞에 서 있고, 화장실에 들어서면 출입문이 잠깁니다. 소녀를 목격해야 문이 풀리고, 가까이 다가가면 덮칩니다.
- 코루틴으로 문 잠금 · 고정 자리까지 걷기
- 수칙 T4 「변기는 정상입니다」 — 이상이 보여도 [정상] 보고가 정답
도서관 노란 얼굴
3초 이상 비추면 달아난다
책을 집으면 문간에서 고개로 따라보다가, 쳐다보면 다가옵니다. 손전등으로 3초 버티면 코앞에서 멈췄다 달아나고, 못 비추면 붙잡힙니다.
- 조우 직전 도서관 주변만 런타임 NavMesh 비동기 굽기 + NavMeshAgent
- 손전등 원뿔 판정 · 머리뼈만 돌리는 시선
교실 소년
교실을 나가려 하면 놀란다
화분을 보고하면, 자리가 시야 밖일 때 앉아 머리를 박기 시작합니다. 3초 넘게 바라보거나 교실을 나서면 덮치고, 아니면 잠시 뒤 사라집니다.
- 시야 밖 등장 판정(뷰포트 + 레이캐스트 가림)
- 바라볼수록 빨라지는 머리 박기(최대 ×3.2)
인체모형
빛을 받는 순간 급습한다
4일차엔 복도 끝에 서 있기만 하다가, 5일차에 손전등이 닿으면 고개를 돌려 돌진합니다. 불을 켜 두면 몸을 뚫고 넘어지고, 꺼 두면 어깨만 스칩니다.
- 손전등 원뿔 + Linecast 가림 판정
- 달리기 클립 없이 뼈를 직접 돌리는 절차적 달리기
사람나무
바라볼수록 끌려간다
보지 않는 사이 복도로 옮겨 오고, 가까이 갈수록 그쪽으로 끌려갑니다. 바라보면 화면이 울렁이고, 너무 다가가면 수칙 위반입니다.
- 복도 단면을 미리 스캔해 설 자리 탐색, 화면 밖에서만 이동
- 거리에 비례한 끌림(1.5m에서 멈춤) · 화면 울렁임은 팀원 작업
CCTV 검은 남자
CCTV 화면 속에 나타난다
정해진 채널을 보고 있으면 남자가 화면을 가로지릅니다. 3초 넘게 지켜보면 얼굴이 튀어나오고, 10초 안에 채널을 넘기면 위반입니다.
- 카메라별 렌더러 토글로 CCTV에서만 보이게
- 걷기 속도에 맞춘 애니메이션 재생 속도
달려오는 발소리
6초 안에 방으로 피해야 한다
복도를 한참 걸으면 등 뒤에서 발소리가 달려옵니다. 6초 안에 방으로 피해 지나갈 때까지 머물면 무사하고, 아니면 검은 사람이 옆을 스쳐 달려갑니다.
- 걸은 거리를 쌓아 방아쇠로
- 수칙 정산 이벤트를 받아 SphereCast로 트인 거리를 재고 질주 연출
멀리 보이는 몹
똑바로 보면 사각지대로 달아난다
곁눈에 멀리 서 있다가, 똑바로 보거나 다가가면 가려지는 곳으로 달려가 사라집니다.
- 24방향 고리로 사각지대 탐색 + 캡슐 가림 검사
- 수칙 · 판정 없이 긴장 조절에만 사용하는 놀람
구간이 오르면 화면에서 바뀌는 것
AmbiencePlayer ← BandChangedIlluminanceMapLayout*MapCaptureDirector ← Captured
조도와 배치 변화는 제가 요구했습니다. 「조도 구간 3 변화에 구간 4 효과처럼 일부 조명만 빨개지거나 깜빡이는 현상」, 「축이 오를 때마다 벽이나 천장에 오브젝트가 생긴다던가, 복도에 가짜 문들이 늘어난다던가 하는 기괴한 변화」(개발 후반).
안 볼 때만 바꾼다
설계 문서(CLAUDE.md)에 「시야 규약은 예외가 없습니다.」라고 적어 둔 규칙입니다. 배치 변화와 등장은 플레이어가 보고 있지 않을 때만 일어나고, 보이는지 판단할 수 없으면 보이는 것으로 처리해 움직이지 않습니다.
- 배치 소품 — 소품이 완전히 화면 밖에 가려졌을 때 등장합니다.
- 교실 소년 — 플레이어가 교실 안에 있고, 소년 자리가 보이지 않을 때 등장합니다.
- CCTV 속 사람 — CCTV 화면 밖에서 걸어 들어와 화면 밖으로 걸어 나간 뒤 사라집니다.

경비실 버티기 방지
- 플레이테스트에서 「경비실에 오래 있으면 파훼되지 않느냐, 밤을 그냥 넘기거나 연출을 안 보고 넘어갈 수 있다」는 피드백을 받아 넣었습니다.
- 수치를 정해 지시했습니다. 「약 30초 형광등 깜빡임·무전 잡음(문구 없음) · 약 60초 CCTV가 검은 남자 얼굴 · 약 90초 정전, 그래도 남으면 붙잡힘 …」

[Test] public void 머문_시간에_따라_깜빡임_CCTV_얼굴_정전으로_간다()
{
var g = new GuardRoomLoiter(); // 씬 없이 new로 생성
Stay(g, 29f); Assert.AreEqual(LoiterStage.None, g.Stage);
Stay(g, 2f); Assert.AreEqual(LoiterStage.Flicker, g.Stage);
Stay(g, 30f); Assert.AreEqual(LoiterStage.CctvFace, g.Stage);
Stay(g, 30f); Assert.AreEqual(LoiterStage.Blackout, g.Stage);
Stay(g, GuardRoomLoiter.CaptureGraceSeconds);
Assert.IsTrue(g.ConsumeCapture()); // 정전 뒤에도 남으면 붙잡힘
}
같은 파일의 테스트 11개에는 AI 검토에서 찾은 문제의 회귀 테스트도 있습니다. 경비실 밖에 잠깐 나갔다 문턱으로 돌아온 뒤 다시 잠깐 나가면, 두 번의 시간이 합쳐져 경비실을 떠난 것으로 처리되던 문제입니다.GuardRoomLoiterTests.cs
GuardRoomLoiter (Core) · GuardRoomCamp (Flow)
06AI와 일한 방식
Unity 에디터를 띄워 둔 채 Claude 데스크톱 앱(Opus 5.5)을 Unity CLI의 MCP 서버로 연결해 명령을 내렸습니다. 코드 · 씬 수정, 테스트 · 디버깅, 밤새 자동으로 돌린 QA 플레이까지 에디터 작업은 대부분 AI가 했습니다.
| 문제 | 플레이테스트에서 조우가 의도대로 나오지 않음 → 실제로 마주쳤는지로 다시 세어 본 시뮬레이션에서 미숙 플레이어 33% (07절 ①) |
|---|---|
| 도구 | Claude 데스크톱 앱(Opus 5.5) + Unity CLI. 메인 세션 · QA · 백그라운드 검토 · 조사 에이전트로 나눠 운영 |
| AI에게 맡긴 것 | 코드 · 씬 수정, 테스트 작성, 밤새 돌린 QA 플레이, 원인 진단 |
| 제가 판단한 것 | 테스트할 수 있는 구조의 기준(02절), 공포 디렉터 방향(03절), 수칙 수 · 지시 비중(04절), AI 이월 보정안 기각 → 고정 편성(07절 ①) |
| 검증한 방법 | 문제 측정: 숙련도마다 400판 시뮬레이션(배정 76% · 실제로 마주침 33%) · 고정 편성 확인: PlayScene 4 · 5일차 진행 + 편성 테스트(시뮬레이션 재측정은 안 함) · EditMode 테스트 666개 · 같은 조건 비교(렌더 ms · 실내 11곳 × 12방향) · 작은 빌드로 재현(0 → 0.29m) |
에이전트를 나눠 쓴 방식
| 방식 | 이렇게 시켰습니다 | 결과 |
|---|---|---|
| 조사 → 회의 → 보고 | 여러 에이전트에게 분야별 자료를 조사하게 한 뒤 회의 · 검토를 거쳐 보고하게 함. 「긴장감 컨트롤러도 다시 한번 전문가 에이전트들과 회의」 | 공포 분위기를 만드는 방법을 여러 자료에서 모아 선택지로 받고, 그중에서 고름. 회의 결과는 제안서 문서로 남김 (예: 「야간근무 3차 회의 — 경비원다운 [근무 지시]」) |
| 설계와 QA를 동시에 | 「설계만 해볼래? 하면서 에이전트 하나는 계속 버그수정/의도한 대로 작동하는지를 돌려봐」 | QA 에이전트가 새 근무 지시 기능을 플레이로 점검해 버그 2건 수정. 이어서 독립 QA가 5건을 고치고, 판단이 필요한 것은 「남은 제안」으로 따로 보고 |
| 구현 뒤 독립 · 백그라운드 검토 | 「프로젝트에 새로 구현한 부분들 버그 있는지 확인해주고 고쳐줘」 | 독립 검토로 버그를 고치고 테스트를 더해 EditMode 666/666. 별도 백그라운드 검토에서는, 금지된 방의 지시가 풀리지 않아 03:30에서 시계가 영영 멈출 수 있는 결함을 AI가 찾아 수정(제가 찾은 결함이 아님) |
조사 · 회의, QA 플레이, 구현 뒤 검토는 한 세션에 몰지 않고 따로 맡겼습니다. 에이전트는 고친 것과 판단이 필요한 것을 나눠 보고했고, 받아들일지 말지는 제가 정해 CLAUDE.md 개정 기록에 남겼습니다.
한 줄 지시를 나눠 맡긴 예
AI가 올린 피드백 항목(1–7번)을 받고 개발 후반에 보낸 실제 지시입니다. 같은 줄 안에서 바로 고칠 것, 시뮬레이션을 먼저 돌릴 것, 분석만 할 것을 나눴습니다.
「평가 문구 2회 · 정시 알림 두 통 · 결근 원인 축 · 1·2·4번 시뮬 · 5번 문제 분석 · 7번 독촉 · 3번 개선 뒤 QA」CLAUDE.md 개정 기록에 남은 원문
바로 고칠 것
평가 문구 · 정시 알림 중복 · 결근 원인 축 · 3번(창밖 조우 날짜) · 7번(밀린 점검 독촉 문자)
그 작업에서 구현하고 테스트를 더함
시뮬 먼저
- 1번(밤 안에서 연출 구간 올리기) — 결과를 보고 「1번은 적용해줘」. 보통 실력 플레이어 기준, 밤 안에 연출이 한 구간 오르는 비율 2 → 45%
- 2번(신뢰 구간 기준) — 다시 보니 사용하는 곳이 없는 값이라 바꾸지 않음(AI가 앞선 지적을 정정)
- 4번(변조 대상 쏠림) — 「4번 원래 의도는 처음 보는 수칙도 신뢰가 높으면 변조」로 의도를 다시 설명해 반영. 변조가 한 수칙에 몰리는 비율 50 → 12%
분석만
5번(조우를 놓치는 경우) — 구현 없이 분석만 받았고, AI는 이월 보정을 권했습니다.
이어서 「5번 놓치는 경우 분석」으로 다시 재게 했고, 이것이 고정 편성으로 이어졌습니다(07절).
AI 제안에 대한 판단 기록
| 유형 | AI 안 · 대상 | 제 판단 | 결과 |
|---|---|---|---|
| 채택 | 시체 낙하를 2일차로 고정하고 강도를 낮추는 추천안 | 강도를 낮춰서 조금 더 일찍 | 13종이 모두 배정된 회차가 늘어남(시뮬레이션, 07절 ①) |
| 위임 | QA 뒤 제가 결정할 항목을 추천과 함께 정리해 보고 | 1,2,3을 추천한 대로 하고, 4의 권장부분도 처리해줘 | 추천안대로 반영하고 QA를 한 번 더 |
| 기각 | 못 본 조우를 다음 뽑기로 넘겨 더 잘 뽑히게 하고(이월), 조우를 막던 조건을 풀어 주는 안 — 예상 75 → 85–90%(AI 보고서 원문 수치) | 날짜마다 정해 둔 조우를 그날 보여 주는 기획 의도를 우선했습니다. 모든 연출에서 축 조건 제거. 날짜 편성 … 이월은 없어. 의도한 날짜에 무조건 목격해야 해 | 고정 날짜 편성으로 전환 (07절) |
| 채택 후 되돌림 | 고정 편성 변주 — 같은 날 순서 섞기 · 날마다 빈 칸 · 수칙을 어기면 다음 날 후속 조우 | 축 조건을 제거하고 너무 고정이니 매력이 떨어진 느낌이라 셋을 채택했다가, 후속 개념은 없애줘. 버그가 너무 많을 것 같네 | 후속은 두 번에 걸쳐 모두 빼고 순서 섞기 · 빈 칸만 남김 |
| 되돌림 | 시야를 돌리면 창가 벽이 밝아지는 문제에 플레이어 카메라 오클루전 컬링 끄기를 먼저 적용(렌더 장당 약 +1ms) | 성능에 큰 문제가 생길 가능성이 있나?→ 대안으로 달빛을 꺼보고 한번 비교해봐 | 컬링 끄기는 되돌리고 달빛 끄기를 채택. 렌더 장당 원래 4.4ms, 컬링 끔 5.4ms, 달빛 끔 3.5ms(에디터 측정)이고 실내 화면 차이는 없었음 |
| 폐기 | AI와 따로 만들어 사용하던 디버그 콘솔 | 우리 것은 폐지하고(가독성이 떨어짐) 진선님 것에 합쳐 줘 | 김진선 님 개발자 모드 한 곳으로 합침(합치는 방식은 제가 진선님 파일에 통째로를 고름) |
AI 결과물에서 잡은 오류
- 먼저 적용된 컬링 끄기 — 창가가 밝아지는 문제에 AI가 플레이어 카메라의 컬링 끄기를 먼저 적용했습니다. 성능 영향을 묻고 달빛 끄기와 같은 조건에서 비교하게 해, 컬링 끄기를 되돌렸습니다(07절 ③).
- 세는 기준 바꾸기 — 배정만 세면 76%였지만, 실제로 마주쳤는지로 다시 세게 하니 33%였습니다(07절 ①).
도서관 노란 얼굴이 벽과 책장을 뚫고 다니는 것은 제가 찾았고, 원인(벽이 반영되지 않은 옛 NavMesh)은 AI가 찾아 실행 중에 NavMesh를 다시 굽도록 고쳤습니다.
AI에게 건 규칙
CLAUDE.md기록 규칙
- 「재지 않은 것을 적지 마십시오」(2026-09-21) — 확인하지 않고 쓴 문장 때문에 문서가 자꾸 틀려서 넣었습니다.
- 구현이 끝나면 개정 기록을 남기고, 바뀐 옛 값은 「되살리지 마십시오」 목록에 올림. 새 세션이 옛 값을 다시 가져오지 않게 하려고 둔 규칙이고, 기록은 100곳 넘게 쌓였습니다.
- 설계 문서와 코드 값이 어긋나면 실패하는 테스트(
DesignDriftTests)
인계서 · 작업 규칙도구 · 권한 규칙
- git 명령은 AI가 실행하지 않음 — 커밋 · 병합 · LFS 잠금은 제가 직접
- 병렬 에이전트일 때 에디터 조작은 메인 세션 한 곳에서만
- 공유 타입 시그니처를 모든 프롬프트에 똑같이 넣고 「자기 것만 정의하고 나머지는 이름으로만 참조하라」고 지시
새 세션 온보딩 — 인계서에는 처음 맡은 세션에게 「모르는 건 추측하지 말고 unity__eval로 직접 재십시오.」라고 적어 두었습니다.
07문제 해결 사례
① 조우 편성 — 다시 세어 보고 고정 날짜로
플레이테스트에서 공포 이벤트(조우)가 의도대로 나오지 않았습니다. 시뮬레이터에서는 미숙한 플레이어 판의 76%에 13종이 모두 배정됐지만, 실제로 마주쳤는지로 다시 세어 보게 하자 33%뿐이었습니다. AI는 이월 보정을 제안했습니다. 저는 모든 플레이어가 조우를 다 보게 하려면 확률에 맡기면 안 된다고 판단해, 조우를 날짜별로 고정하고 남은 조우가 있으면 밤이 끝나지 않게 바꿨습니다.
미숙한 플레이어가 조우를 다 못 보는 문제
개발 후반 · 시뮬레이션- 상황
- 감각 수치와 확률로 조우를 뽑던 방식(확률 편성)에서는, 미숙한 플레이어는 밤 후반 조우가 꺼져 13종을 다 보지 못했고 붙잡힘 원인도 배치 축에 쏠렸습니다. 13종은 측정 당시 기준이고, 이후 한 종을 빼 지금은 12종입니다.
- 측정
- 실제 편성 코드를 그대로 사용하는 시뮬레이터로 숙련도마다 가상 플레이어 400판을 돌리게 했습니다. 미숙 플레이어에게 13종이 모두 배정된 회차는 21%였습니다. Core가 Unity와 분리돼 있어 가능했습니다.
- 조정
- 날짜 흐름을 바꾸고, 시체 낙하를 2일차로 고정해 강도를 낮췄습니다.
- 다시 재기
- 플레이테스트에서 의도한 조우가 종종 나오지 않았습니다. 그래서 「5번 놓치는 경우 분석」을 지시해, 편성됐는지가 아니라 실제로 마주쳤는지로 다시 세어 보게 했습니다. 미숙한 플레이어는 33%로, 편성 기준 76%보다 크게 낮았습니다. 시뮬레이션에서는 위험한 분위기 때문에 늦은 조우가 꺼졌고, 시뮬레이션 밖에서는 정해진 시간 안에 그 공간에 들어가거나 머물지 못하면, 또는 일찍 퇴근하면 조우를 놓쳤습니다. 직접 플레이에서는 조우를 보기 전에 퇴근 트리거가 켜지거나, 플레이어가 움직이지 않는 사이 시간이 흘러 밤이 끝났습니다.
- 다시 보고
- 이후 직접 플레이에서도 같은 일이 있었습니다. 「… 수칙과 지시로 트리거는 된 것 같은데 연출이 안 나왔어」 AI 분석으로 조기 퇴근이 남은 조우를 지워 버리는 것 등을 찾았고, 남은 조우가 있으면 조기 퇴근부터 막도록 고쳤습니다.
- 판단
- AI의 이월 보정안 대신, 축 조건을 없애고 날마다 정해진 조우를 보여 주는 고정 날짜 편성으로 바꿨습니다. 03:30에 남은 조우가 있으면 시계를 붙들어, 그날의 조우가 끝나기 전에는 다음 날로 넘어가지 않게 했습니다. 이후 AI 변주안 중 같은 날 순서 섞기 · 날마다 빈 칸만 남겼습니다(06절 판단 기록).
- 검증
- PlayScene에서 4 · 5일차를 진행해 날짜표대로 나오는지 확인하고 편성 테스트로 묶었습니다.
- 한계
- 모든 수치는 가상 플레이어 시뮬레이션이며 실제 플레이 데이터가 아닙니다. 고정 편성 뒤의 목격률은 시뮬레이션으로 다시 재지 않았습니다.
붙잡힘 원인이 배치 축에 쏠리던 문제는, 점검 항목의 벌칙 축을 실제 원인 축과 맞추고 밤마다 세 축의 수칙이 한 장 이상 나오게 해서 바로잡았습니다. 미숙한 플레이어 기준 배치 축 비율이 67%에서 34%로 내려갔습니다(시뮬레이션).
② 구운 조명이라 정전이 되지 않던 문제
소등은 되는데 방은 그대로 밝음
직접 발견- 발견
- 직접 플레이하다 본 문제입니다. 「소등 조우 때 소등은 되는데 라이팅은 계속 유지돼」
- 원인
- 방의 밝기 대부분이 구워 둔 라이트맵이라 등을 꺼도 빛이 남았습니다(진단은 AI).
- 해결
- 라이트맵은 실행 중에 끌 수 없어서, 씬이 시작될 때 어두운 라이트맵 사본을 만들어 두고 정전 때 사본으로 바꿨습니다(
lightmapIndex교체). 불 꺼진 교실에 이미 사용하던 방식을 소등 방에도 적용한 것입니다. 라이트 프로브의 SH 계수도 낮추고, 형광등 발광은 공유 재질을 건드리지 않도록MaterialPropertyBlock으로 껐습니다.

③ 시야를 돌리면 창가가 밝아지던 문제
AI가 먼저 적용한 안을 같은 조건에서 비교해 되돌림
직접 발견- 발견
- 시야를 돌리면 창가 벽이 밝아지는 것을 찾았습니다. AI가 시점을 한 바퀴 돌려 가며 화면 평균 밝기를 재 보니, 특정 각도에서 48에서 71로 튀었습니다.
- 원인
- 오클루전 컬링이 달빛 그림자 캐스터도 시야 기준으로 걸러 냈습니다(진단은 AI).
- 판단
- AI는 플레이어 카메라의 컬링 끄기를 먼저 적용했습니다. 「성능에 큰 문제가 생길 가능성이 있나?」, 「달빛을 꺼보고 한번 비교해봐」로 두 안을 같은 조건에서 재게 했습니다. 렌더 장당 원래 4.4ms, 컬링을 끄면 5.4ms, 달빛을 끄면 3.5ms(에디터 측정)여서 달빛 끄기를 골랐습니다. 실내 11곳에서 12방향씩 비교한 화면도 차이가 없었습니다. 판단 기록은 06절에도 있습니다.
④ 빌드에서만 난 문제
두 건 모두 에디터에서는 보이지 않았습니다. 소년 건은 제가 빌드를 플레이하다 발견해 릴리스 · 개발자 빌드 모두에서 안 나온다고 좁혀 보고했고, 셰이더 건은 빌드 전 점검에서 AI가 찾았습니다.
발광이 꺼지는 문제
빌드 전 점검 · AI 발견- 발견
- 빌드 전에 「다른 문제들은 없을지」 점검을 맡겼고, AI가 찾아냈습니다.
- 원인
- 빌드에는 빌드에 포함된 재질이 사용하는 키워드 조합의 셰이더 변형만 들어갑니다. 실행 중에 코드로 켜는 발광 조합(URP Lit
_EMISSION)이 여기서 빠져, 붉은 등이나 점검 이상의 붉은 빛 같은 발광이 빌드에서 꺼졌습니다. - 해결
- 빌드 재질을 훑어, 빠진 조합마다 그 키워드를 켠 보존용 재질을 만드는 에디터 도구(
ShaderKeepBuilder)를 추가했습니다. 빠져 있던 발광 조합 18개를 복구했고, 조합이 다시 빠지면 실패하는 테스트를 추가했습니다. ShaderKeepBuilder.cs
빌드에서만 소년이 머리를 박지 않음
개발 후반 · 직접 발견- 발견
- 빌드를 플레이하다 발견해, 릴리스와 개발자 빌드 모두에서 안 나온다는 것까지 함께 보고했습니다. 「릴리스로 빌드하면 소년 머리박는게 적용이 안된다 · 어제 프리테스트 개발자 빌드본에서도 안 나왔다」
- 원인
- 애니메이터가 없는 대역 모델에
AnimationClip.SampleAnimation으로 클립을 재생했는데, 레거시가 아닌 클립은 빌드에서 Animator 없이 샘플링되지 않았습니다. 소리는 났지만 뼈는 움직이지 않았습니다. - 해결
- 클립을 레거시로 바꾸고(GUID와 곡선은 그대로), 대역을 만드는 도구도 고치고, 회귀 테스트를 추가했습니다. 임시 씬으로 릴리스 빌드를 만들어 재 보니 머리 이동량이 0m → 0.29m로 에디터와 같아졌습니다.
에디터와 빌드가 다르게 동작하면, 이번처럼 작은 빌드로 재현해 수치로 확인합니다.
08한계와 다시 만든다면
| 한계 | 무엇이 부족했나 | 다시 한다면 |
|---|---|---|
| 위반 피드백 | 플레이테스트에서 「위반 패널티가 명확했으면」이라는 의견이 많았습니다. 어겨도 축 수치만 조용히 올랐기 때문입니다. | 위반 즉시 화면 · 소리 · 태블릿으로 알림 |
| 최적화 | 에디터에서 FPS · 렌더 시간은 일부 쟀지만, 빌드 기준 FPS · 메모리 · 드로우콜 · GC를 재지 않아 최적화의 기준선이 없습니다. CCTV처럼 렌더를 아끼도록 만든 곳도 실제 비용은 재지 않았고, 빌드 용량(약 2.1GB, 대부분 4K 텍스처)도 줄이지 못했습니다. | 프로파일러로 빌드 기준선을 잡고, 텍스처 해상도 · 압축부터 정리 |
| 공포 디렉터 효과 | 놀람을 간격을 두고 내보내는 편이 낫다는 판단은 제 경험에 비춘 예상이고, 플레이어가 덜 무뎌지는지는 재지 않았습니다. | 같은 밤을 디렉터 켬 · 끔으로 플레이하게 해 반응 비교 |
| 통합 테스트 | 자동 테스트가 EditMode 위주라 씬 단위 동작은 직접 플레이로 확인했습니다. | PlayMode 테스트 추가 |