Files
maplecontest/docs/superpowers/specs/2026-06-16-charselect-images-back-design.md
gahusb 2e8a1ab869 docs(spec): 직업 선택 캐릭터 이미지 + 뒤로가기 설계
CharacterSelectHud 단색 박스 → 캐릭터 이미지 카드(이름 하단 배너·선택 금색
테두리), 뒤로가기→로비. data/characters.json 단일 소스(메이커 임포트 RUID).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 00:59:43 +09:00

8.0 KiB
Raw Blame History

직업 선택 — 캐릭터 이미지 + 뒤로가기 설계

작성일: 2026-06-16 브랜치: feature/charselect-images

목표

런 시작 시 띄우는 캐릭터(직업) 선택 화면(CharacterSelectHud)을 두 가지로 개선한다:

  1. 직업 3종(전사/도적/마법사)을 지금의 단색 네모 박스각 직업 캐릭터 이미지 카드로. 이미지를 선택하면 그 직업으로 런 진행(기존 연결 유지).
  2. 직업 선택 화면에 뒤로가기 버튼 추가 → 로비로 복귀.

요청 원문: "런 시작 시, 직업 선택 창을 뒤로가기도 가능하게 추가. 각 직업별로 지금은 네모 박스인데 각각 이미지(warrior/mage/bandit.png) 추가해서 적용하고, 선택했을 때 그 캐릭터로 진행하도록 연결."

확정된 결정 (브레인스토밍)

항목 결정
이미지 RUID 확보 사용자가 메이커에서 3 PNG 로컬 임포트.sprite+RUID(P13 카드프레임과 동일). MCP/계정 업로드는 흰박스라 불가
이미지 배치 카드 전체를 이미지로, 이름은 하단 배너, 선택 시 금색 테두리
뒤로가기 대상 로비로 (ShowLobby()) — 로비 NPC에서 진입하므로

소스 이미지 (사용자 임포트 대상)

  • 전사: C:\Users\jaeoh\Desktop\workspace\source\images\maple\character\warrior.png (~1.05MB)
  • 법사: …\mage.png (~1.28MB)
  • 도적: …\bandit.png (~1.0MB)

세 PNG는 현재 워크스페이스 미임포트(코드 미참조). 기존 RootDesk/MyDesk/*_normal|unique|legend.sprite는 P13 카드 프레임이지 캐릭터 초상화가 아니다.

현재 구조 (조사 결과)

  • CLASSES 상수 gen-slaydeck.mjs:7-11warrior{label,maxHp}, bandit, magician.
  • CharacterSelectHud emit :2432-2598. classCards 배열 :2482-2486 (key Warrior/Thief/Mage, classId warrior/bandit/magician, x 360/0/360, tint). 각 카드(270×330)의 자식: Name(상단, 108), Portrait(142×142 색상 tint, :2524-2525 부근), Desc(하단 105), LockBody/LockShackle(비활성 직업용). 별도 …DeckButton(덱 보기)·StartButton.
  • 선택 로직: 클릭 바인딩 BindMenuButtons:3100/3108/3116SelectClass(classId) :3358-3361(=self.SelectedClass=…+RenderCharacterSelect()). 시작 :3151-3157StartNewGame :3395-3399(미선택 가드 후 StartRun()).
  • RenderCharacterSelect :3362-3394 — 선택 카드 밝게/미선택 어둡게 + Status 텍스트.
  • 진입/전환: ShowState :3062-3078가 HUD 토글. 진입 = 로비 NPC OnLobbyNpcInteract :3199-3203(런 비활성 시 ShowCharacterSelect() :3355-3357) 및 (사실상 미사용) MainMenu :3092. ShowLobby :3175. 게임은 OnBeginPlay→ShowLobby로 부팅(로비 허브).
  • emit 헬퍼: entity():466, transform():286, sprite():311(dataId로 ImageRUID 주입 가능), button():347, text():372, guid().
  • 이미지 외부화 패턴: 카드프레임은 data/cardframes.jsonluaFramesTable()(:72 부근) → self.CardFrames Lua 테이블 + 런타임 ApplyCardFace :4167-4202e.SpriteGUIRendererComponent.ImageRUID=ruid 주입. 생성 시 주입은 sprite({dataId}).

상세 설계

1) data/characters.json (신설 — 단일 소스)

{
  "portraits": {
    "warrior":  "<32hex RUID>",
    "magician": "<32hex RUID>",
    "bandit":   "<32hex RUID>"
  }
}
  • 사용자 임포트 후 RootDesk/MyDesk/*.sprite에서 RUID를 읽어 채운다(파일명은 임포트 시 결정 — warrior.sprite 등으로 매칭, 모호하면 사용자 확인).
  • 나중에 이미지 교체 = 이 파일 RUID만 바꿔 재생성.

2) gen-slaydeck.mjs — 로드·검증·주입

  • 상단에서 const CHARS = JSON.parse(readFileSync('data/characters.json','utf8')) 로드(cardframes 로드 패턴 인접).
  • fail-fast 검증: portraitswarrior/magician/bandit 3키 존재 + 각 값이 32hex. 누락 시 throw.
  • 카드 Art 이미지는 생성 시 dataId 주입(런타임 테이블 불필요). 즉 classCards의 classId로 CHARS.portraits[classId]를 조회해 Art 스프라이트 dataId에 박는다.

3) CharacterSelectHud — 카드 전체 이미지화 (:2432-2598, classCards emit 루프)

각 직업 카드 구조를 다음으로 변경(엔티티 경로 …/{key}Button·클릭 바인딩은 불변):

  • {key}Button(270×330): 클릭 가능한 테두리 프레임. sprite Color = 미선택 어둡게(0.16,0.2,0.26,1)/선택 금색(1,0.82,0.3,1). raycast on, button() 유지.
  • 신규 자식 Art(약 258×318, 6px 인셋, center): sprite({ dataId: CHARS.portraits[classId], type:1, raycast:false }) — 캐릭터 이미지 풀블리드. (테두리가 이미지 뒤로 6px 보임 → 금색 테두리 효과.)
  • Name(하단 배너): 반투명 어두운 띠 sprite(예: 0,0,0,0.55, 270×54, 하단) + 금색 텍스트. 기존 Name 재배치.
  • 제거: 기존 색상 Portrait 박스, Desc 텍스트(선택 레이아웃에 없음).
  • LockBody/LockShackle: 비활성 직업용으로 유지(현재 3직업 모두 enabled라 표시 안 됨).

4) RenderCharacterSelect Lua 변경 (:3362-3394)

  • 기존 "박스 밝게/어둡게"를 테두리(={key}Button sprite Color) 금색/어둡게로 교체. 선택된 classId의 카드만 Color(1,0.82,0.3,1), 나머지 Color(0.16,0.2,0.26,1).
  • Art 이미지는 생성 시 고정 주입이라 런타임 변경 없음. Status 텍스트 로직은 유지.

5) 뒤로가기 버튼

  • 신규 CharacterSelectHud/BackButton(ShopHud Leave 패턴 재사용 :2020-2031): 좌상단(예: pos {x:-820,y:430}, 180×56), text "← 뒤로", DARK sprite + button().
  • BindMenuButtons에 바인딩 추가(ShopHud Leave 바인딩 패턴 :3715-3717): back:ConnectEvent(ButtonClickEvent, function() self:ShowLobby() end). 핸들러 prop 저장(재바인딩 시 해제).
  • ShowCharacterSelect/SelectClass/StartNewGame/StartRun 로직 불변.

6) GUID 네임스페이스

  • 신규 엔티티(Art·NameBanner·BackButton)는 CharacterSelect용 기존 prefix에 번호 추가. 미등록 prefix면 ns 바이트 등록(생성기 끝 id 유일성 검증이 충돌 잡음).

흐름

로비(맵) ──NPC 상호작용──> ShowCharacterSelect (HUD 오버레이)
  카드3=캐릭터 이미지, 클릭 → SelectClass → 금색 테두리
  [시작] → StartNewGame(가드) → StartRun (그 직업으로)
  [← 뒤로] → ShowLobby() → 로비 HUD 복귀

미러/테스트 영향

  • 전투규칙·맵생성 미변경sim-balance/rogue-map 미러 동기화 불필요.
  • 카운트 검증: CharacterSelectHud/.../Art ImageRUID 3개, BackButton 1개, characters.json 3 RUID 등장(tools/verify/count.mjs 또는 grep -c).
  • 메이커 플레이테스트: 로비 NPC→3 이미지 표시→클릭 금색 테두리→시작 그 직업으로 진행→뒤로 로비 복귀.

리스크

  • 이미지 임포트 선행 의존: RUID가 있어야 생성기 실행 가능. 사용자 임포트 완료 후 진행(임포트 무관한 코드 골격은 먼저 작성 가능).
  • 이미지 비율: PNG가 세로 초상화면 258×318(≈0.81 비율)에서 잘리거나 여백 — 임포트 후 스크린샷으로 인셋/사이즈 조정.
  • ShowLobby() 재텔레포트: 이미 로비 맵 위라 GoLobbyMap 재호출 시 위치/카메라 jolt 가능 → 보이면 뒤로가기를 ShowState("lobby")로 축소(플레이테스트 확인).
  • 흰박스: 공식 절차(로컬 임포트)면 렌더됨. reload 필수.

변경 파일 요약

파일 변경
data/characters.json 신설 — 직업 3종 초상화 RUID(단일 소스)
tools/deck/gen-slaydeck.mjs characters.json 로드·검증, CharacterSelectHud 카드 이미지화(Art/NameBanner), RenderCharacterSelect 테두리 선택표시, BackButton emit+바인딩
RootDesk/MyDesk/*.sprite (×3) 사용자 임포트 산출물(커밋)
ui/DefaultGroup.ui·SlayDeckController.codeblock 재생성 산출물