docs(A): README·framework 문서를 실제 구현에 맞게 정정

미존재 3컴포넌트(SlayCardCatalog/SlayRunState/SlayCombatManager)를 구현된 것처럼 서술하던 부분을 정정.

- '게임 프레임워크 현황'을 실제 구현(SlayDeckController 기반 카드 전투 + B 결과)으로 재작성
- 3대 컴포넌트는 '향후 설계(미구현 — 목표 아키텍처)' 섹션으로 분리 보존
- 디렉토리 트리·codeblock 목록·생성기(tools/) 반영, SlayDeckController 추가
- 스크립트 호출 예시를 실제 메서드(PlayCard/EndPlayerTurn/StartCombat)로 교체
- '다음 구현 단계'에서 전투 UI·전투 루프 완료 표시, D/F/E 반영
- 수치는 임시 placeholder임을 명시
- framework 문서도 동일 기조로 재작성 + Planned 섹션에 3컴포넌트 보존

검증: 문서에 적힌 컴포넌트명을 코드와 grep 교차확인 (SlayDeckController 실재, 3컴포넌트 코드 0건).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-09 01:10:35 +09:00
parent 9206018fbe
commit e8ed467cda
2 changed files with 118 additions and 52 deletions

View File

@@ -43,14 +43,15 @@ git pull
```
slaymaple/
├── Global/ # 월드 전역 설정 · 공용 모델 · 게임로직
│ ├── common.gamelogic # SlayCardCatalog / SlayRunState / SlayCombatManager 부착 지점
│ ├── common.gamelogic # SlayDeckController 부착 지점 (카드 UI 전투)
│ ├── Player.model # 플레이어 모델
│ ├── *.model # 몬스터 등 공용 모델
│ ├── WorldConfig.config # 월드 설정
│ └── ...
├── RootDesk/
│ └── MyDesk/ # 작업용 책상 — codeblock(스크립트)·모델·타일셋
│ ├── Monster.codeblock
│ ├── SlayDeckController.codeblock # 카드 UI 전투 컨트롤러 (생성물)
│ ├── Monster.codeblock # 필드 액션 몬스터 (HP·피격·리스폰, 카드 전투와 별개)
│ ├── MonsterAttack.codeblock
│ ├── PlayerAttack.codeblock
│ ├── PlayerHit.codeblock
@@ -58,7 +59,11 @@ slaymaple/
│ ├── UIToast.codeblock
│ └── RectTileData_Henesys.tileset
├── map/
── map01.map # 메인 맵
── map01.map ~ map11.map # 맵 11종 (공식 배경 + STS풍 우측 배치)
├── tools/ # 결정적 생성기 (단일 소스)
│ ├── gen-slaydeck.mjs # 카드/덱 UI · SlayDeckController · common 생성
│ ├── gen-cardhand.mjs # 손패 카드 엔티티 생성
│ └── gen-maps.mjs # 맵 생성
├── ui/ # UI 그룹 (Default / Popup / Toast)
├── docs/
│ └── slaymaple_basic_framework.md # 전투 프레임워크 설계 문서
@@ -71,42 +76,61 @@ slaymaple/
## 게임 프레임워크 현황
`Global/common.gamelogic``/common` 엔티티에 부착된 세 컴포넌트가 전투의 핵심입니다.
현재 전투는 `Global/common.gamelogic``/common` 엔티티에 부착된 **`SlayDeckController` 단일 컴포넌트**로 동작합니다. 모든 카드/덱/전투 관련 산출물(`ui/DefaultGroup.ui` · `RootDesk/MyDesk/SlayDeckController.codeblock` · `common.gamelogic`)은 **`tools/gen-slaydeck.mjs` 단일 소스에서 생성**됩니다(직접 편집 금지, 결정적 출력).
| 컴포넌트 | 역할 |
|---|---|
| `SlayCardCatalog` | 카드 데이터, 시작 덱 구성, 보상 풀, 카드 복제 정의 |
| `SlayRunState` | HP·골드·층수·덱·유물·카드 보상 등 런(run) 영속 데이터 관리 |
| `SlayCombatManager` | 턴 진행, 드로우/버림/소멸 더미, 에너지, 적 의도, 방어도, 데미지, 승패 처리 |
| 컴포넌트 | 상태 | 역할 |
|---|---|---|
| `SlayDeckController` | ✅ 구현됨 | 카드 손패 UI 전투 — 드로우/버림/재셔플, 에너지, 카드 효과(데미지/방어), 적 HP·방어·의도, 턴 진행, 승패 |
| `Monster.codeblock` | ✅ 구현됨 | 필드 액션 몬스터(HP·피격·리스폰) — 카드 전투와는 **별개** 시스템 |
### 프로토타입 흐름
1. `SlayRunState`가 HP 80 · 10장 시작 덱으로 새 런 시작
2. `SlayCombatManager`가 데모 전투 자동 시작
3. 매 플레이어 턴: 에너지 3 회복, 방어도 초기화, 적 의도 갱신, 5장 드로우
4. 카드 사용 시 에너지 소모 → 데미지/방어/드로우/에너지/상태이상 적용 → 버림 또는 소멸
5. 턴 종료 시 손패 버림, 적 의도 실행, 상태이상 처리, 다음 턴 시작
6. 전투 승리 시 잔여 HP 저장, 골드 15 지급, 카드 보상 3종 생성
### 구현된 카드 전투 (단일 전투 루프)
- **카드 손패 UI**: 에너지 3, 매 턴 5장 드로우, 버림 더미·재셔플, 카드 클릭 사용, 종류별 색상.
- **카드 3종**: 타격(피해 6) · 방어(방어도 5) · 강타(피해 10). 각 카드에 `damage`/`block` 수치 필드. 시작 덱 10장.
- **전투 상태**: 플레이어 `HP`/`Block`, 적 `HP`/`Block`/`Intent(의도)`. 적 의도는 **결정적 사이클**(공격10 → 공격6 → 방어8)로 다음 행동을 미리 표시.
- **규칙**: 데미지는 방어도 먼저 차감 후 잔여만 HP에 적용. 플레이어 Block은 턴 시작 시 리셋.
- **턴 흐름**: 카드 사용(`Attack`→적 HP↓, `Skill`→플레이어 Block↑) → 턴 종료 → 적 턴(의도 실행) → 다음 플레이어 턴.
- **승패**: 적 HP 0 → 승리, 플레이어 HP 0 → 패배. 승패 시 입력 잠금 + 결과 표시(전투 보상 훅 자리 = E 예정).
- **UI(CombatHud)**: 적 패널(이름·HP·방어·의도)·플레이어 패널(HP·방어)·승패 결과 텍스트.
> ⚠️ 플레이어 HP(80)·적 HP(45)·의도 수치(10·6·8)는 **루프 검증용 임시 placeholder**입니다.
> 향후 캐릭터 특성별/몬스터별 데이터로 분리할 예정입니다(아래 D 참조).
### 유용한 스크립트 호출
`/common` 엔티티에 붙은 스크립트에서:
`/common` 엔티티(또는 Play Test 컨텍스트)에서:
```lua
self.Entity.SlayCombatManager:PlayCard(1, 1)
self.Entity.SlayCombatManager:EndPlayerTurn()
self.Entity.SlayCombatManager:DebugPlayFirstPlayable()
self.Entity.SlayRunState:PickReward(1)
self.Entity.SlayCombatManager:StartCombat("elite")
local c = _EntityService:GetEntityByPath("/common").SlayDeckController
c:PlayCard(1) -- 손패 slot 카드 사용
c:EndPlayerTurn() -- 턴 종료 → 적 턴 → 다음 턴
c:StartCombat() -- 전투 재시작(상태 초기화)
```
상세 설계는 [`docs/slaymaple_basic_framework.md`](docs/slaymaple_basic_framework.md) 참조.
---
## 향후 설계 (미구현 — 목표 아키텍처)
아래는 로그라이크 메타까지 확장했을 때의 **목표 컴포넌트 구조**로, 현재는 미구현입니다. (현재는 `SlayDeckController` 하나가 카드 전투만 담당)
| 컴포넌트 (계획) | 역할 |
|---|---|
| `SlayCardCatalog` | 카드 데이터, 시작 덱 구성, 보상 풀, 카드 복제 정의 |
| `SlayRunState` | HP·골드·층수·덱·유물·카드 보상 등 런(run) 영속 데이터 관리 |
| `SlayCombatManager` | 턴 진행, 드로우/버림/소멸 더미, 에너지, 적 의도, 방어도, 데미지, 승패 처리 |
> 위 구조로 가더라도 카드/적 데이터는 `tools/`의 결정적 생성기를 단일 소스로 유지하는 방향을 권장합니다.
---
## 다음 구현 단계
- [ ] HP·방어도·에너지·적 의도·손패 5버튼을 렌더링하는 전투 UI
- [ ] 전투/엘리트/상점/휴식/이벤트/보스 노드를 가진 맵 노드 UI
- [ ] `OnCombatStart` / `OnCardPlayed` / `OnTurnStart` / `OnCombatReward` 훅을 가진 유물 시스템
- [ ] 적 행동 패턴을 데이터로 정의 (현재 단순 의도 패턴 → 무브셋)
- [ ] 런 루프 완성 후 저장/불러오기
- [x] HP·방어도·에너지·적 의도·손패 카드를 렌더링하는 전투 UI **(완료 — `SlayDeckController` + CombatHud)**
- [x] 카드 사용이 실제 데미지/방어/적 의도/승패에 반영되는 단일 전투 루프 **(완료)**
- [ ] 카드/적 데이터를 `data/cards.json` · `data/enemies.json`로 외부화 (D)
- [ ] 전투를 N회 자동 시뮬레이션하는 밸런스 검증 도구 `tools/sim-balance.mjs` (F, D 선행)
- [ ] 전투/엘리트/상점/휴식/이벤트/보스 노드를 가진 맵 노드 UI (E)
- [ ] `OnCombatStart` / `OnCardPlayed` / `OnTurnStart` / `OnCombatReward` 훅을 가진 유물 시스템 (E)
- [ ] 적 행동 패턴을 데이터로 정의 (현재 단순 결정적 의도 사이클 → 무브셋)
- [ ] 런 영속(HP/골드/층/덱/유물) + 저장/불러오기 (E, 루프 end-to-end 후)
---

View File

@@ -1,42 +1,84 @@
# SlayMaple Basic Framework
This project now has a small deckbuilder roguelike foundation inspired by turn-based card combat games.
This project has a working single-combat deckbuilder loop inspired by turn-based
card combat games. Card play is wired to real combat state (enemy/player HP,
block, enemy intent, win/lose).
## Components
## Current Components (implemented)
- `SlayCardCatalog`: Defines card data, starter deck composition, reward pool, and card cloning.
- `SlayRunState`: Owns persistent run data such as HP, gold, floor, deck, relics, and card rewards.
- `SlayCombatManager`: Runs combat turns, draw/discard/exhaust piles, energy, enemy intents, block, damage, victory, and defeat.
- `SlayDeckController`: The single combat component, attached to the `/common`
entity in `Global/common.gamelogic`. Handles the card-hand UI (draw/discard/
reshuffle, energy, card-click play), card effects (damage/block), enemy
HP/block/intent, turn flow, and victory/defeat.
- `Monster.codeblock`: A separate field-action monster system (HP, hit event,
respawn). **Not** part of the card combat.
All three components are attached to the `/common` entity in `Global/common.gamelogic`.
All card/deck/combat artifacts (`ui/DefaultGroup.ui`,
`RootDesk/MyDesk/SlayDeckController.codeblock`, `Global/common.gamelogic`) are
**generated from a single source, `tools/gen-slaydeck.mjs`** (deterministic
output — do not hand-edit; change the generator and re-run `node
tools/gen-slaydeck.mjs`).
If the Maker session was already open before these files were added, reopen or reload the local workspace so the new codeblock files are imported into the editor state.
If the Maker session was already open before these files changed, reload the
local workspace so the regenerated codeblock/UI files are imported into the
editor state.
## Prototype Flow
## Implemented Combat Loop
1. `SlayRunState` starts a new run with 80 HP and a 10-card starter deck.
2. `SlayCombatManager` starts a demo combat automatically.
3. Each player turn refreshes energy to 3, clears block, rolls enemy intent, and draws 5 cards.
4. Playing a card spends energy, applies damage/block/draw/energy/status effects, then sends the card to discard or exhaust.
5. Ending the turn discards the hand, resolves enemy intent, ticks statuses, and starts the next turn.
6. Winning combat stores the remaining HP back into the run, grants 15 gold, and generates 3 card reward options.
1. `StartCombat` initializes player (HP 80, Block 0) and a single enemy
(HP 45, Block 0) with a deterministic 3-step intent cycle
(Attack 10 → Attack 6 → Defend 8), then starts the first player turn.
2. Each player turn refreshes energy to 3, resets player block, and draws 5
cards. The enemy's upcoming intent is shown in advance.
3. Cards: Strike (damage 6), Defend (block 5), Bash (damage 10). Each card has
numeric `damage`/`block` fields; starter deck is 10 cards.
4. Playing a card spends energy: `Attack` reduces enemy HP (block absorbs
first); `Skill` adds player block. The card moves to the discard pile.
5. Ending the turn discards the hand, runs the enemy turn (executes the current
intent — attack the player or gain block), advances the intent index, then
starts the next player turn.
6. Enemy HP 0 → victory; player HP 0 → defeat. On combat end, input is locked
and a result text is shown (combat-reward hook reserved for the roguelike
meta — see Planned below).
> Player HP (80), enemy HP (45), and intent values (10/6/8) are temporary
> placeholders for loop verification. They will move to per-character /
> per-enemy data (see "Data externalization" under Planned).
## Useful Script Calls
From a script attached to the same `/common` entity:
From the `/common` entity (or a Play Test context):
```lua
self.Entity.SlayCombatManager:PlayCard(1, 1)
self.Entity.SlayCombatManager:EndPlayerTurn()
self.Entity.SlayCombatManager:DebugPlayFirstPlayable()
self.Entity.SlayRunState:PickReward(1)
self.Entity.SlayCombatManager:StartCombat("elite")
local c = _EntityService:GetEntityByPath("/common").SlayDeckController
c:PlayCard(1) -- play the hand card in the given slot
c:EndPlayerTurn() -- end turn → enemy turn → next turn
c:StartCombat() -- restart combat (reset state)
```
## Planned (not yet implemented) — Target Architecture
The originally envisioned component split for the full roguelike. Currently
**none of these exist**; `SlayDeckController` covers only the card combat above.
- `SlayCardCatalog`: Card data, starter deck composition, reward pool, card cloning.
- `SlayRunState`: Persistent run data — HP, gold, floor, deck, relics, card rewards.
- `SlayCombatManager`: Turn flow, draw/discard/exhaust piles, energy, enemy
intents, block, damage, victory, and defeat (the role currently played by
`SlayDeckController`).
## Next Implementation Steps
- Add a combat UI that renders HP, block, energy, enemy intent, and 5 hand-card buttons.
- Add a map node UI with combat, elite, shop, rest, event, and boss node types.
- Add relic definitions and hooks such as `OnCombatStart`, `OnCardPlayed`, `OnTurnStart`, and `OnCombatReward`.
- Add enemy move sets as data instead of the current simple intent pattern.
- Add save/load once the run loop is playable end to end.
- [x] Combat UI rendering HP, block, energy, enemy intent, and hand cards
(done — `SlayDeckController` + CombatHud).
- [x] Card play wired to real damage/block/intent/win-lose (done).
- [ ] Externalize card/enemy data to `data/cards.json` / `data/enemies.json`,
injected by the generator.
- [ ] Monte-Carlo balance simulator `tools/sim-balance.mjs` (requires the data
externalization above).
- [ ] Map node UI with combat, elite, shop, rest, event, and boss node types.
- [ ] Relic definitions and hooks (`OnCombatStart`, `OnCardPlayed`,
`OnTurnStart`, `OnCombatReward`).
- [ ] Enemy move sets as data instead of the current deterministic intent cycle.
- [ ] Run persistence (HP/gold/floor/deck/relics) + save/load once the loop is
playable end to end.