5.7 KiB
5.7 KiB
P8 — 로그라이크 절차 생성 맵·층 시스템·유물 방 설계
날짜: 2026-06-12 (사용자 승인 완료)
브랜치: feature/p8-rogue-map
선행: P7 (유물 19종 — 유물 방이 PickNewRelic 재사용)
범위
- 절차 생성 맵 — 막 시작마다 8층×최대 4열 DAG를 Lua 런타임 생성 (런·막마다 다른 맵).
data/map.json정적 맵 제거 - 층(depth) 시스템 — 노드를 지날 때마다 층 +1 (층 = 행), 층별 노드 타입 등장 규칙
- 유물 방(보물 노드) — 상자 열리는 모션 + 유물(
PickNewRelic)·메소 획득, 노드 타입treasure추가 - 맵 UI 정비 — 노드 연결 점선(도트 3개 보간), 타입별 아이콘 색/라벨, 상태 4단(방문/현재/도달 가능/잠김)
- 메소 표기 — 화폐 표시 텍스트 "골드" → "메소" (메이플 IP, 표시만 — 내부 변수 Gold 유지)
비범위: 이벤트 노드(?), 경로 교차 방지(시각 교차 허용 — 점선이라 식별 가능), 저장.
절차 생성 알고리즘 (StS 방식)
그리드: 행 17 × 열 14 + 8행 보스 단일 노드. 노드 id = "r{row}c{col}", 보스 = "boss".
- 시작 열: {1,2,3,4} 셔플 후 앞 2개 = 경로 1·2의 시작(서로 다름 보장), 경로 3·4는 랜덤
- 경로 4개를 각각 1행→7행으로 걸어 올림: 다음 열 =
clamp(열 + random(-1..1), 1, 4). 지나는 칸마다 노드 생성(중복은 병합),(r,c) → (r+1,c')간선 추가(중복 간선 병합) - 7행의 모든 노드 → 보스 간선
MapStart= 1행에 생성된 노드들
타입 배정 (행 오름차순)
| 행 | 규칙 |
|---|---|
| 1~2행 | combat 고정 |
| 3행 | combat 45 / shop 12 / rest 12 (가중 추첨, 합계로 정규화) |
| 4~6행 | combat 45 / elite 16 / shop 12 / rest 12 / treasure 15 |
| 7행 (보스 직전) | rest 50 / combat 25 / shop 10 / elite 8 / treasure 7 |
| 8행 | boss 고정 |
추가 제약: 부모(간선으로 들어오는 이전 행 노드) 중 elite가 있으면 해당 노드는 elite 금지 (연속 엘리트 방지).
층 카운터
Depth prop: PickNode 시 Depth = node.row. 막 전환·런 시작 시 0. TopBar Floor 텍스트를 막 F/3 · D층으로 확장.
노드 enemy 필드 제거
몬스터는 P4 이후 node.type 그룹 필터(BuildMonsters)로 결정되므로 enemy 필드·CurrentEnemyId 대입은 제거(CurrentEnemyId = "" 유지). data/map.json·luaMapNodesTable·luaStartArray·MAX_ROW 제거.
유물 방 (TreasureHud)
PickNode분기에treasure→ShowTreasure추가 (ShowState("treasure")·HideGameHud등록)- UI: 어두운 패널 + 타이틀("보물 상자") + 중앙 상자 버튼(닫힌 상자 RUID) + 보상 텍스트(초기 숨김) + 나가기 버튼
OpenChest: 1회 가드(ChestOpened) → 흔들림 모션(anchoredPosition ±8px, 0.08s × 6스텝 타이머 체인) → 열린 상자 RUID로 교체 → 보상 지급·표시- 메소:
40 + random(0..20) - 유물:
PickNewRelic()— 미보유 추첨, 전부 보유 시 메소 +30 대체 - 보상 텍스트 예:
유물 획득: 황소 투구 · 메소 +52
- 메소:
- 상자 닫힘/열림 스프라이트는 공식 maplestory 리소스 검색("상자"/"보물상자") 후 메이커 선별
- 나가기 →
LeaveNode(기존 → ShowMap)
맵 UI
정적 그리드 (생성기, MapHud 섹션 재작성)
- 노드 버튼 28개(
Node_r{1..7}c{1..4}, 56×56) +Node_boss(72×72, 상단 중앙) + 각 노드Label(타입 한글) - 배치: 행 y =
-330 + (row-1)*105(보스 y=405), 열 x =-270 + (col-1)*180, 보스 x=0 - 점선 도트: 모든 가능 간선(행 1~6:
c→c±1/c, 행 7→보스)에 대해 도트 3개(8×8, t=0.25/0.5/0.75 보간 위치). 엔티티Dot_r{r}c{c}_{c'}_{k}(보스행은Dot_r7c{c}_b_{k}) - 모든 노드·도트는 기본 비활성,
RenderMap이 토글
RenderMap 재작성 (상태 4단 + 점선)
- 노드: 맵에 없으면 숨김. 있으면 Label = 타입명, 색:
- 방문(
VisitedNodes에 포함) → 어둡게(0.18,0.19,0.22) - 현재 위치 → 골드
(0.95,0.8,0.3) - 도달 가능(IsReachable) → 타입색 밝게 + 버튼 활성
- 잠김 → 타입색 45% 어둡게 + 버튼 비활성
- 방문(
- 타입색: 전투
(0.78,0.36,0.32)/ 엘리트(0.62,0.4,0.85)/ 상점(0.9,0.75,0.35)/ 휴식(0.4,0.75,0.45)/ 보물(0.35,0.7,0.75)/ 보스(0.85,0.25,0.25) - 도트: 간선 존재 시 표시. 현재 노드(또는 시작 전 1행 진입선)에서 나가는 간선 = 골드, 그 외 = 회색
(0.5,0.5,0.55) VisitedNodes(any prop): PickNode 시 추가
메소 표기
표시 문자열 "골드" → "메소": TopBar Gold·ShopHud Gold·상점 가격(N 메소)·유물 소진 토스트. 내부 prop Gold 유지.
검증
- JS 미러 + 단위 테스트:
tools/map/rogue-map.mjs에generateMap(rng)동일 로직(시드 PRNG 주입) +rogue-map.test.mjs— 모든 노드가 시작점에서 도달 가능·보스 수렴·1~2행 combat만·elite/treasure 4행부터·간선 인접 열만·elite 부모 연속 금지·결정성(동일 시드 동일 맵). ⚠️ LuaGenerateMap과 로직 동기화 유지(sim-balance 패턴) - 기존
sim-balance21건 유지 (맵과 무관) - 메이커: 빌드 0에러, 플레이테스트 — 맵 생성/점선/상태색, 노드 진행(층 증가), 유물 방 상자 연출·보상, 보스 클리어 → 다음 막 새 맵
결정 사항
- 경로 4개·8층×4열 (사용자 승인 규모)
- 점선 도트 방식 채택 (UI 회전 리스크 회피, StS 원작 미감)
- 시각적 간선 교차는 허용 (점선이라 추적 가능 — YAGNI)
RUN_LENGTH/ACT_MAPS막 시스템은 변경 없음 (막마다 새 맵 생성만 추가)