8.2 KiB
8.2 KiB
로비 맵 + 월드 NPC 설계 (P15)
작성일: 2026-06-14
브랜치: feature/p15-lobby-map-npc
목표
기존 UI 패널 로비(P14-8 LobbyHud — 색칠된 UIButton 4개 행)를 폐기하고,
전용 로비 맵에 월드 NPC 엔티티 4종을 배치한다. NPC를 누르면 각 기능이 실행되며,
플레이어 이동·공격 모션은 로비 맵에서만 풀린다(전투/런 맵에서는 기존대로 잠김 유지).
요청 원문: "로비를 UI로 만들지 말고, map을 추가해서 로비에 각각 기능을 할 수 있는 npc를 추가하고, 그 npc를 누르면 각 기능을 할 수 있도록 추가. 플레이어는 반드시 로비맵에서만 이동과 공격 모션을 풀어줘."
확정된 결정 (브레인스토밍)
| 항목 | 결정 |
|---|---|
| NPC 상호작용 | 근접 프롬프트+키(Up/Space) AND 직접 클릭 둘 다 지원 |
| NPC 기능 | 기존 4종 유지 + 외형을 정식 maplestory NPC 스프라이트(공식 RUID) 로 교체 |
| 로비 맵 | 새 전용 로비 맵 추가(map/lobby.map), 런 맵(map01~) 인덱스 불변 |
현재 상태 (조사 결과)
- 로비 = UI 패널
LobbyHud. NPC 4종은 색칠UIButton, 전부tools/deck/gen-slaydeck.mjs에 하드코딩.NpcRun(모험가→런 시작),NpcCodex(사서→카드 도감),NpcShop(상인→영혼 상점),NpcBoard(안내원→게시판).- 정의 ~
gen-slaydeck.mjs:2469-2487, 클릭 바인딩BindLobbyButtons()~2997-3014. - 기능 진입 메서드:
ShowCharacterSelect()(~3147),ShowCodex(),ShowSoulShop(),ShowBoard()— 재사용 대상.
- 이동/공격 이중 잠금:
tools/player/freeze-turn-player.mjs→Global/DefaultPlayer.modelspeed/jump/accel = 0 (전역).tools/player/gen-player-lock.mjs→PlayerLockcodeblock(pc.Enable=false,FixedLookAt=true)를 map01~05에 주입.- 공격은 순수 모션
PlayerAttackMotion()(StateComponent ATTACK→IDLE), 필드 몬스터와 무관(전투는 데이터 배열 UI 전투). - 플레이어 스폰:
TeleportToActMap()→Vector3(-6, 0.03, 0), Floor별 map 선택.
- 맵 파이프라인: map01 = 저작 템플릿, map02~05 = 복제 생성. 포털 없이
TeleportToMapPosition전환.Global/SectorConfig.config의 valid 목록에 맵 등록(현재 gen-maps.mjs가 갱신).- 컴포넌트 부착 패턴:
gen-combat-monster.mjs가 맵 몬스터에script.CombatMonster를 붙이고, 해당 codeblock이 OnBeginPlay에서/common컨트롤러에 자가등록.
- 흐름:
OnBeginPlay→ShowLobby()(UI).EndRun(text)→4초 후ShowLobby().
접근법
A. 새 로비 맵 + 월드 NPC 엔티티 (채택) — 맵 템플릿 복제 재사용, NPC를 월드 엔티티로 배치하고 각 NPC의 codeblock이 근접+클릭을 감지해 기존 기능 패널을 띄움. 이동/공격 해제는 로비 맵 전용 codeblock. 전투맵은 손대지 않아 잠금 유지. (B: 몬스터 배치기 재활용 → 로직 혼재로 비채택. C: 화면고정 UI 버튼 → 거부된 "UI 로비"라 제외.)
상세 설계
1) 로비 맵 — tools/map/gen-lobby-map.mjs → map/lobby.map
- map01 템플릿 deep clone → 경로
/maps/lobby로 치환, GUID 재발급(결정론 시드). - 마을/타운 배경 RUID + 타일셋 적용.
script.Monster/script.CombatMonster엔티티 전부 제거(전투 없음). - NPC 4종을 x축으로 벌려 월드 엔티티로 배치. 각 NPC:
- 스프라이트 = 공식 maplestory NPC RUID(계정 업로드 금지 — 흰 박스). 구현 단계에서 asset 검색으로 4개 확정.
script.LobbyNpc컴포넌트 +NpcId(run/codex/shop/board) + 머리 위 이름/!프롬프트용 텍스트 노드.
- 플레이어 스폰 지점(맵 중앙-좌측).
Global/SectorConfig.configvalid 목록에map://lobby추가 — SectorConfig 단일 소유자는 gen-maps.mjs로 유지하고 lobby 항목을 그 상수에 포함(두 생성기 충돌 방지).
2) NPC 상호작용 — tools/player/gen-lobby-npc.mjs → LobbyNpc codeblock
- 근접+키: 매 틱(타이머) 로컬 플레이어와의 x거리 측정 → 임계 거리 내면
!프롬프트 노드 활성 +Up/Space입력 시 트리거. - 직접 클릭: NPC 엔티티 클릭/터치 → 동일 트리거. (MSW 월드 엔티티 클릭 API는 구현 시
mlua_api_retriever로 확정: 엔티티 TouchEvent vs 스크린 오버레이 버튼 중 검증된 방식.) - 트리거 시
_EntityService:GetEntityByPath("/common").SlayDeckController:OnLobbyNpcInteract(NpcId)호출(경로 기반 크로스 codeblock — CombatMonster 자가등록과 동일 패턴). - 한 번에 하나만 상호작용(다른 패널 열려 있으면 무시).
3) 이동·공격 잠금 해제 (로비 맵 한정) — LobbyMobility codeblock
map/lobby.map에만 주입(전투맵 PlayerLock/전역 freeze는 불변).- OnBeginPlay 런타임 복원: 로컬 플레이어
MovementComponent(InputSpeed/JumpForce) 정상값,PlayerController.Enable=true,FixedLookAt=false. - 공격 입력(키/클릭) → 기존
PlayerAttackMotion()(코스메틱) 바인딩. 필드 타격 없음. - 전투맵 텔레포트 시 모델 기본값(speed=0)+PlayerLock 재적용 → "로비맵에서만"을 구조적으로 보장.
- 런타임 이동/공격 복원 정확한 API는 구현 단계에서
mlua_api_retriever로 확정. - 생성기 배치는
gen-lobby-npc.mjs에 함께 둘지 별도gen-lobby-unlock.mjs로 분리할지는 계획에서 결정(둘 다 lobby 맵 전용 codeblock).
4) 흐름 통합 — tools/deck/gen-slaydeck.mjs
- OnBeginPlay:
ShowLobby()(UI) → 로비 맵 텔레포트 + 경량 "lobby" 상태(전투/상점/맵 HUD 숨김). - EndRun: 4초 후
ShowLobby()→ 로비 맵 텔레포트 복귀. - OnLobbyNpcInteract(id) 신규:
run→ShowCharacterSelect(),codex→ShowCodex(),shop→ShowSoulShop(),board→ShowBoard()(전부 기존 메서드 재사용, 패널은 로비 맵 위 팝업). - 제거:
LobbyHud버튼-행 허브 패널 +BindLobbyButtons. - 유지: 영혼 포인트·승천 표시는 화면 모서리 미니 HUD(정보 표시 필요). 기능 패널 4종은 NPC 트리거.
- 런 시작(
StartRun/TeleportToActMap)·전투 흐름은 불변.
5) 미러/테스트 영향
- 이동/공격 해제·NPC 배치는 전투 규칙도 맵 그래프 생성 알고리즘도 아님 →
sim-balance.mjs/rogue-map.mjsJS 미러 동기화 불필요(RULES.md §6은 그 둘만 요구). - 검증(카운트만):
lobby.map내 NPC 엔티티 수, 산출물의LobbyNpc/LobbyMobility/OnLobbyNpcInteract개수, SectorConfigmap://lobby존재. 내용 출력 금지. - 동작 검증: 메이커 플레이테스트.
검증 시나리오 (메이커)
- 월드 시작 → 로비 맵에 스폰, 이동 가능, 공격 모션 가능.
- NPC 근접 →
!프롬프트 →Up/Space로 기능 패널 오픈. 직접 클릭으로도 오픈. - 4종 각각: 모험가→직업선택→런 시작, 사서→도감, 상인→영혼상점, 안내원→게시판.
- 런 시작 → map01 텔레포트, 이동/공격 잠김.
- 런 종료(클리어/패배) → 로비 맵 복귀, 이동/공격 재해제.
- 미니 HUD에 영혼/승천 표시 정상.
리스크
- MSW 런타임 이동 재활성 API 가용성 → 계획 단계
mlua_api_retriever검증. - MSW 월드 엔티티 클릭 감지 방식 → 동일 검증(불가 시 근접+키만으로 폴백, 직접 클릭은 스크린 오버레이 버튼으로 구현).
- 텔레포트 복귀 좌표/스폰 위치 정합.
- 메이커 stale 상태 — git pull 후 로컬 워크스페이스 reload 필수(RULES.md §5).
생성기/파일 변경 요약
| 파일 | 변경 |
|---|---|
tools/map/gen-lobby-map.mjs |
신규 — lobby.map(배경/타일/NPC 엔티티/스폰), SectorConfig 조율 |
tools/player/gen-lobby-npc.mjs |
신규 — LobbyNpc 상호작용 codeblock(+LobbyMobility 또는 분리) |
tools/deck/gen-slaydeck.mjs |
OnBeginPlay/EndRun 로비맵 전환, OnLobbyNpcInteract, 버튼-행 허브 제거, 미니 HUD |
Global/SectorConfig.config |
map://lobby 등록(생성 산출물) |
map/lobby.map, ui/DefaultGroup.ui, *.codeblock |
재생성 산출물 |