"첫 30초"를 만드는 데 집중한 세션. 인트로 카메라가 NPC를 보여주면서 살아있는 마을을 연출합니다.
인트로 카메라 진화 과정
총 6번 반복했습니다.
| 버전 | 문제 |
|---|---|
| v1: 사인파 패닝 + 줌아웃 | 밋밋함, NPC 안 보임 |
| v2: NPC 4명 순회 | 줌아웃이라 전체만 보임 |
| v3: 줌인 1.15x | 여전히 NPC에 포커스 안 됨 |
| v4: 줌인 1.8x | 내 캐릭터만 크게 보임 |
| v5: 플레이어 위치를 NPC로 이동 | 플레이어가 텔레포트 |
| v6: 가상 카메라 위치 | 플레이어 고정, 카메라만 이동 |
최종 구조
플레이어: (20, 25)에 고정 — 안 움직임
intraCamPos: 가상 카메라 위치 — NPC를 순회
renderer._cameraFollowTarget: intraCamPos (인트로 중만)
렌더러가 매 프레임 _cameraFollowTarget || player를 따라가므로, 인트로 중에는 가상 위치를, 인트로 후에는 플레이어를 따라갑니다.
인트로 시퀀스
NPC1: 혼잣말 중얼거리는 모습 (2.5초, 줌인)
↓
NPC쌍: 두 NPC가 대화하는 모습 (2.5초, 줌인)
↓
NPC2: 혼잣말 중얼거리는 모습 (2.5초, 줌인)
↓
카메라가 플레이어 위치로 부드럽게 복귀
카메라가 비추는 NPC에게 LLM 혼잣말/대화를 트리거합니다. triggerIntroSpeech()가 타겟이 바뀔 때 1회만 호출.
NPC간 대화 빈도
Before
nextSocialAt = world.totalMinutes + 22 + Math.random() * 34;
// 22~56분마다 — 사실상 안 일어남
After
nextSocialAt = now + 10000 + Math.random() * 15000;
// 10~25초마다 — 혼잣말(8~20초)과 비슷
가장 가까운 NPC 쌍을 찾아서 대화시킵니다. 6타일 이내면 서로 걸어가게.
Rule-base 혼잣말 → 이모티콘만
// Before
ambient_solo: ["🎵", "🎶", "~♪", "흠흠", "후~", "라라~", "음~"]
ambient_chat: ["ㅎㅎ", "와~", "그래?", "맞아", "음음", "오~", "헤헤"]
// After
ambient_solo: ["🎵", "🎶", "~♪", "💭", "✨"]
ambient_chat: ["😄", "😮", "🤭", "👋", "💬"]
LLM이 생성하는 혼잣말(가장 가까운 NPC)은 여전히 텍스트. 나머지는 이모티콘으로 깔끔하게.
같은 NPC 연속 혼잣말 방지
lastAmbientNpcId를 기억해서, 직전과 같은 NPC면 2번째로 가까운 NPC 선택.
오디오
Web Audio API → HTML5 <audio> 전환. 치지직/하울링 해결.
BGM을 동물의 숲 스타일 트랙으로 교체 (Pixabay: Chill Yume).
핵심
인트로가 보여주는 것:
카메라가 마을을 비추면, NPC가 혼잣말을 하고, 다른 NPC끼리 대화하고 있다. 이 마을은 내가 오기 전부터 살아있었다.
그리고 카메라가 플레이어에게 돌아오면, 유진이 걸어오며 인사한다.
이게 "첫 30초"입니다.