๐ฎ g5se ๋ธ๋ผ์ฐ์ ๋์ ํฌ๋กค๋ฌ - ํด๋ฆญ RPG ์ด๋๋ฒค์ฒ
g5se-browser-dungeon-crawler
๋ฌธ์ ์ค๋ช
๐ ํ๋ก์ ํธ ๊ฐ์
๋ธ๋ผ์ฐ์ ์์ ์ฆ๊ธฐ๋ ํด๋ฆญํ ๋์ ํํ RPG! ๋ชฌ์คํฐ๋ฅผ ์ฒ์นํ๊ณ , ์์ดํ ์ ํ๋ํ๋ฉฐ, ๋ ๋ฒจ์ ํ๋ ์ฌ๋ฏธ๋ฅผ g5se ์์์ ๊ตฌํํฉ๋๋ค. ์ ํฌ๋ ํด์ ๋ฐฉ์์ผ๋ก, ํ๋ ์ด์ด๊ฐ ๊ณต๊ฒฉ/์คํฌ/ํฌ์ ์ฌ์ฉ์ ์ ํํ๋ฉด ๋ชฌ์คํฐ๊ฐ ๋ฐ๊ฒฉํ๋ ๊ตฌ์กฐ์ ๋๋ค. ๊ฒ์ ์งํ ์ํฉ์ SQLite DB์ ์ ์ฅ๋์ด ๋ค์ ๋ฐฉ๋ฌธ ์์๋ ์ด์ด์ ํ๋ ์ดํ ์ ์์ต๋๋ค.
โจ ํ์ ๊ธฐ๋ฅ
1. ์บ๋ฆญํฐ ์์คํ
- ๋๋ค์ ์ ๋ ฅ ํ ๊ฒ์ ์์ (์ฒซ ๋ฐฉ๋ฌธ ์)
- ์บ๋ฆญํฐ ์คํฏ: HP, MP, ๊ณต๊ฒฉ๋ ฅ, ๋ฐฉ์ด๋ ฅ, ๋ ๋ฒจ, ๊ฒฝํ์น
- ๋ ๋ฒจ์ ์ ์คํฏ ์๋ ์์น & ์ถํ ์ ๋๋ฉ์ด์
- ์ฅ๋น ์ฌ๋กฏ (๋ฌด๊ธฐ/๋ฐฉ์ด๊ตฌ) - ์์ดํ ์ฐฉ์ฉ ์ ์คํฏ ๋ณด๋์ค
2. ๋์ ํํ
- 3๊ฐ์ง ๋์ด๋ ๋์ (์ด๊ธ/์ค๊ธ/๊ณ ๊ธ)
- ๊ฐ ๋์ ๋ง๋ค ๊ณ ์ ๋ชฌ์คํฐ ํ (์ฌ๋ผ์, ๊ณ ๋ธ๋ฆฐ, ๋๋๊ณค ๋ฑ)
- ๋๋ค ์ธ์นด์ดํฐ - "ํํํ๊ธฐ" ๋ฒํผ ํด๋ฆญ ์ ๋ชฌ์คํฐ ๋ฑ์ฅ
- ๋์ ๋ณ ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง & ๋ถ์๊ธฐ ์์
3. ์ ํฌ ์์คํ
- ํด์ ์ ํฌ: ํ๋ ์ด์ด ํด โ ๋ชฌ์คํฐ ํด ๋ฐ๋ณต
- ํ๋ ์ ํ: ์ผ๋ฐ ๊ณต๊ฒฉ / ์คํฌ ์ฌ์ฉ (MP ์๋ชจ) / ํฌ์ ์ฌ์ฉ
- ๋ฐ๋ฏธ์ง ๊ณ์ฐ์:
๊ณต๊ฒฉ๋ ฅ - ์๋ ๋ฐฉ์ด๋ ฅ + ๋๋ค(0~5) - ์ ํฌ ๋ก๊ทธ ์ค์๊ฐ ์ถ๋ ฅ ("๋น์ ์ ์ฌ๋ผ์์๊ฒ 15์ ํผํด๋ฅผ ์ ํ์ต๋๋ค!")
- ์น๋ฆฌ ์ ๊ฒฝํ์น & ๊ณจ๋ ํ๋, ๋๋ค ์์ดํ ๋๋กญ
- ํจ๋ฐฐ ์ ๊ฒฝํ์น ์ผ๋ถ ์์ค & ๋ง์๋ก ๊ทํ
4. ์ธ๋ฒคํ ๋ฆฌ & ์์
- ํ๋ํ ์์ดํ ๋ชฉ๋ก (๋ฌด๊ธฐ/๋ฐฉ์ด๊ตฌ/ํฌ์ )
- ์์ดํ ์ฅ์ฐฉ/ํด์ ๊ธฐ๋ฅ
- ์์ ์์ ํฌ์ ๊ตฌ๋งค (HP ํฌ์ 50๊ณจ๋, MP ํฌ์ 30๊ณจ๋)
- ๋ถํ์ํ ์์ดํ ํ๋งค (ํ๋ ๊ฐ๊ฒฉ์ 50%)
5. ๋ฐ์ดํฐ ์์์ฑ
- SQLite DB์ ์บ๋ฆญํฐ ์ ๋ณด, ์ธ๋ฒคํ ๋ฆฌ, ์ ํฌ ๊ธฐ๋ก ์ ์ฅ
- ๋ธ๋ผ์ฐ์ ์ฟ ํค๋ก ์บ๋ฆญํฐ ID ๊ธฐ์ต (์ฌ๋ฐฉ๋ฌธ ์ ์๋ ๋ก๋)
- "์ ๊ฒ์ ์์" ๋ฒํผ์ผ๋ก ์บ๋ฆญํฐ ์ด๊ธฐํ ๊ฐ๋ฅ
6. UI/UX
- modern shell ์ ์ฉ์ผ๋ก ๋คํฌ๋ชจ๋ ์๋ ๋์
- ์คํฏ๋ฐ (HP/MP) ํ๋ก๊ทธ๋ ์ค๋ฐ ์๊ฐํ
- ์ ํฌ ์ค ๋ชฌ์คํฐ ์ด๋ฏธ์ง (ํ ์คํธ ์์คํค ์ํธ ๋๋ ์ด๋ชจ์ง)
- ๋ฒํผ ํด๋ฆญ ์ ์ฟจํ์ ์ ๋๋ฉ์ด์ (์ค๋ณต ํด๋ฆญ ๋ฐฉ์ง)
- ๋ ๋ฒจ์ /์์ดํ ํ๋ ์ ํ ์คํธ ์๋ฆผ
๐ ์ ํ ์ถ๊ฐ ๊ธฐ๋ฅ (๋ณด๋์ค)
- ์คํฌ ํธ๋ฆฌ: ๋ ๋ฒจ์ ์ ์คํฌ ํฌ์ธํธ ํ๋ & ์ ์คํฌ ํด๊ธ
- ๋ณด์ค ๋ชฌ์คํฐ: ๋์ 10ํ ํํ๋ง๋ค ๋ณด์ค ๋ฑ์ฅ (ํน๋ณ ๋ณด์)
- ์ ์ ์์คํ : "์ฌ๋ผ์ 100๋ง๋ฆฌ ์ฒ์น", "๋ ๋ฒจ 10 ๋ฌ์ฑ" ๋ฑ
- ๋ญํน ์์คํ : ๋ ๋ฒจ & ๊ณจ๋ ๊ธฐ์ค ์ ์ฒด ํ๋ ์ด์ด ์์
- ์ฌ์ด๋ ์ดํํธ: ์ ํฌ/๋ ๋ฒจ์ /์์ดํ ํ๋ ์ ํจ๊ณผ์ (Web Audio API)
- ์ฅ๋น ๊ฐํ ์์คํ : ๊ณจ๋๋ฅผ ์๋ชจํด ๋ฌด๊ธฐ/๋ฐฉ์ด๊ตฌ ๊ฐํ (์คํจ ํ๋ฅ ์์)
๐ฏ ํ์ต ๋ชฉํ
- g5se ํด๋ ๊ธฐ๋ฐ ๋ผ์ฐํ ํ์ฉ
- SQLite ๋ค์ค ํ ์ด๋ธ ์ค๊ณ (์บ๋ฆญํฐ, ์ธ๋ฒคํ ๋ฆฌ, ๋ชฌ์คํฐ ๋ฐ์ดํฐ)
- ๋ณต์กํ ๊ฒ์ ๋ก์ง์ PHP๋ก ๊ตฌํ (์ ํฌ ์๊ณ ๋ฆฌ์ฆ, ํ๋ฅ ๊ณ์ฐ)
- AJAX๋ฅผ ํตํ ๋น๋๊ธฐ ์ ํฌ ์ฒ๋ฆฌ (ํ์ด์ง ์๋ก๊ณ ์นจ ์์ด)
- CSS ๋ณ์ + ์ ๋๋ฉ์ด์ ์ผ๋ก ์๋๊ฐ ์๋ UI ๊ตฌํ
- ์ฟ ํค/์ธ์ ์ ํ์ฉํ ์ฌ์ฉ์ ์ํ ๊ด๋ฆฌ
์ ์ฝ ์กฐ๊ฑด
- โข g5se main ๋ธ๋์น ๊ธฐ์ค (https://github.com/gnuboard/g5se)
- โข ์์ PHP + g5se ์ปจ๋ฒค์ ๋ง ์ฌ์ฉ (Laravel/Composer/npm/React/Vue ์ ๋ ๊ธ์ง)
- โข ํด๋ ๊ธฐ๋ฐ ์๋ ๋ผ์ฐํ : app/modules/dungeon/index.php โ /dungeon
- โข modern shell ํ์ ์ ์ฉ (_head.inc.php + m-shell + _nav.inc.php + m-container + _footer.inc.php + tail.sub.php)
- โข ๋์์ธ ํ ํฐ ์ฌ์ฉ์ผ๋ก ๋คํฌ๋ชจ๋ ์๋ ๋์ (var(--m-surface), var(--m-text) ๋ฑ)
- โข SQLite DB๋ G5_DATA_PATH.'/modules/dungeon.sqlite'์ ์์ฑ
- โข DB ์คํค๋ง: characters(id, nickname, level, exp, hp, max_hp, mp, max_mp, atk, def, gold, created_at), inventory(id, character_id, item_type, item_name, item_stats, equipped, acquired_at), monsters(id, name, level, hp, atk, def, exp_reward, gold_reward, drop_items)
- โข prepared statement๋ก SQL ์ธ์ ์ ๋ฐฉ์ง
- โข htmlspecialchars()๋ก XSS ๋ฐฉ์ง
- โข AJAX ์์ฒญ์ fetch API ์ฌ์ฉ (jQuery ๊ธ์ง)
- โข ์ธ๋ถ CDN ์์กด ์ต์ํ (์์ CSS/JS๋ก ๊ตฌํ)
- โข ์ ํฌ ๋ก์ง์ ์๋ฒ ์ฌ์ด๋(PHP)์์ ์ฒ๋ฆฌ (ํด๋ผ์ด์ธํธ ์กฐ์ ๋ฐฉ์ง)
- โข ์ฟ ํค๋ก character_id ์ ์ฅ (์ ํจ๊ธฐ๊ฐ 30์ผ)
- โข ๋ชฌ์คํฐ ๋ฐ์ดํฐ๋ DB์ ์๋ ๋ฐ์ดํฐ๋ก ๋ฏธ๋ฆฌ ์ฝ์
ํ๋กฌํํธ ๋ ์ํผ
์๋ ํ๋กฌํํธ๋ฅผ ์์๋๋ก AI์๊ฒ ๋ณด๋ด๋ฉด ๋ฉ๋๋ค. ๋ณต์ฌ ๋ฒํผ์ ๋๋ฌ ๋ฐ๋ก ์ฌ์ฉํ์ธ์.
g5se๊ฐ ์ค์น๋ ๋๋ ํฐ๋ฆฌ(๋ฃจํธ์ `index.php`ยท`app/`์ด ์๋ ๊ณณ)์์ ์์
์ ์์ํฉ๋๋ค. (g5se ์ค์น๋ https://github.com/gnuboard/g5se ์ฐธ๊ณ )
## Step 1: ํ๋ก์ ํธ ๊ณจ๊ฒฉ & DB ์คํค๋ง ์์ฑ
`app/modules/dungeon/index.php` ํ์ผ์ ์์ฑํ๊ณ ๋ค์ ๊ตฌ์กฐ๋ก ์์ฑํ์ธ์:
1. **modern shell ๊ณจ๊ฒฉ ์ ์ฉ**
- `_common.php` ์ธํด๋ฃจ๋
- `_head.inc.php`, `_nav.inc.php`, `_footer.inc.php`, `tail.sub.php` ํฌํจ
- `<main class="m-container">` ์์ ๊ฒ์ UI ๋ฐฐ์น
2. **SQLite DB ์ด๊ธฐํ**
- DB ๊ฒฝ๋ก: `G5_DATA_PATH.'/modules/dungeon.sqlite'`
- ๋๋ ํฐ๋ฆฌ๊ฐ ์์ผ๋ฉด `@mkdir(G5_DATA_PATH.'/modules', 0707, true);`๋ก ์์ฑ
- 3๊ฐ ํ
์ด๋ธ ์์ฑ:
- `characters`: id(INTEGER PRIMARY KEY), nickname(TEXT), level(INTEGER DEFAULT 1), exp(INTEGER DEFAULT 0), hp(INTEGER DEFAULT 100), max_hp(INTEGER DEFAULT 100), mp(INTEGER DEFAULT 50), max_mp(INTEGER DEFAULT 50), atk(INTEGER DEFAULT 10), def(INTEGER DEFAULT 5), gold(INTEGER DEFAULT 100), created_at(TEXT)
- `inventory`: id(INTEGER PRIMARY KEY), character_id(INTEGER), item_type(TEXT), item_name(TEXT), item_stats(TEXT), equipped(INTEGER DEFAULT 0), acquired_at(TEXT)
- `monsters`: id(INTEGER PRIMARY KEY), name(TEXT), level(INTEGER), hp(INTEGER), atk(INTEGER), def(INTEGER), exp_reward(INTEGER), gold_reward(INTEGER), drop_items(TEXT)
3. **๋ชฌ์คํฐ ์๋ ๋ฐ์ดํฐ ์ฝ์
**
- ์ด๊ธ ๋์ : ์ฌ๋ผ์(Lv1, HP30, ATK5, DEF2), ๊ณ ๋ธ๋ฆฐ(Lv2, HP50, ATK8, DEF3)
- ์ค๊ธ ๋์ : ์คํฌ(Lv5, HP120, ATK15, DEF8), ๋คํฌ์ํ(Lv7, HP150, ATK20, DEF10)
- ๊ณ ๊ธ ๋์ : ๋๋๊ณค(Lv10, HP300, ATK35, DEF20), ๋ฐ๋ชฌ๋ก๋(Lv15, HP500, ATK50, DEF30)
- drop_items๋ JSON ํ์์ผ๋ก ์ ์ฅ (์: `["์ฒ ๊ฒ", "๊ฐ์ฃฝ๊ฐ์ท"]`)
4. **๊ธฐ๋ณธ UI ๊ตฌ์กฐ**
- ํ์ด์ง ํ์ดํ: "๐ฎ ๋ธ๋ผ์ฐ์ ๋์ ํฌ๋กค๋ฌ"
- ๋ ๊ฐ ์น์
:
- ์ผ์ชฝ: ์บ๋ฆญํฐ ์ ๋ณด ์นด๋ (๋๋ค์, ๋ ๋ฒจ, HP/MP ๋ฐ, ์คํฏ)
- ์ค๋ฅธ์ชฝ: ๋์ ์ ํ & ์ ํฌ ์์ญ
- CSS ๋ณ์ ์ฌ์ฉ: `background: var(--m-surface);`, `color: var(--m-text);`
5. **์ฟ ํค ์ฒดํฌ ๋ก์ง**
- `$_COOKIE['dungeon_character_id']` ํ์ธ
- ์์ผ๋ฉด DB์์ ์บ๋ฆญํฐ ๋ก๋, ์์ผ๋ฉด "์ ๊ฒ์ ์์" ํผ ํ์
DB ์ด๊ธฐํ์ ๋ชฌ์คํฐ ์๋๋ ํ์ด์ง ๋ก๋ ์ ์๋์ผ๋ก ์คํ๋๋๋ก ํ๋, `CREATE TABLE IF NOT EXISTS`์ `INSERT OR IGNORE`๋ก ์ค๋ณต ๋ฐฉ์งํ์ธ์.
๊ธฐ๋ ๊ฒฐ๊ณผ: - `/dungeon` URL๋ก ์ ๊ทผ ๊ฐ๋ฅํ ํ์ด์ง ์์ฑ - modern shell์ด ์ ์ฉ๋์ด ๋ค๋น๊ฒ์ด์ /ํธํฐ/๋คํฌ๋ชจ๋ ํ ๊ธ์ด ๋ณด์ - SQLite DB ํ์ผ์ด `data/modules/dungeon.sqlite`์ ์์ฑ๋จ - 3๊ฐ ํ ์ด๋ธ(characters, inventory, monsters)์ด ์คํค๋ง๋๋ก ์์ฑ๋จ - ๋ชฌ์คํฐ ์๋ ๋ฐ์ดํฐ 6์ข ์ด DB์ ์ฝ์ ๋จ - ์ฒซ ๋ฐฉ๋ฌธ ์ "๋๋ค์์ ์ ๋ ฅํ๊ณ ๋ชจํ์ ์์ํ์ธ์!" ํผ์ด ํ์๋จ - ์ฟ ํค๊ฐ ์์ผ๋ฉด ์บ๋ฆญํฐ ์ ๋ณด๊ฐ ๋ก๋๋์ด ํ๋ฉด์ ํ์๋จ - ๊ธฐ๋ณธ ๋ ์ด์์(์บ๋ฆญํฐ ์นด๋ + ๋์ ์์ญ)์ด 2์ด ๊ทธ๋ฆฌ๋๋ก ๋ฐฐ์น๋จ
## Step 2: ์บ๋ฆญํฐ ์์ฑ & ์คํฏ ์์คํ
๊ตฌํ
1. **์บ๋ฆญํฐ ์์ฑ ํผ ์ฒ๋ฆฌ**
- POST ์์ฒญ์ผ๋ก ๋๋ค์ ๋ฐ๊ธฐ (`$_POST['nickname']`)
- ๋๋ค์ ๊ฒ์ฆ: 2~10์, ํน์๋ฌธ์ ์ ๊ฑฐ (`htmlspecialchars()`)
- DB์ ์ ์บ๋ฆญํฐ INSERT (๊ธฐ๋ณธ ์คํฏ: Lv1, HP100, MP50, ATK10, DEF5, GOLD100)
- ์์ฑ ํ `character_id`๋ฅผ ์ฟ ํค์ ์ ์ฅ (์ ํจ๊ธฐ๊ฐ 30์ผ)
- ํ์ด์ง ๋ฆฌ๋ค์ด๋ ํธ๋ก ์๋ก๊ณ ์นจ
2. **์บ๋ฆญํฐ ์ ๋ณด ์นด๋ UI**
- ๋๋ค์ & ๋ ๋ฒจ ํ์ (ํฐ ๊ธ์จ)
- HP/MP ํ๋ก๊ทธ๋ ์ค๋ฐ:
- `<div class="stat-bar"><div class="stat-fill" style="width: {ํ์ฌHP/์ต๋HP*100}%"></div></div>`
- HP๋ ๋นจ๊ฐ์, MP๋ ํ๋์ ๊ทธ๋ผ๋ฐ์ด์
- ์คํฏ ๋ชฉ๋ก:
- ๊ณต๊ฒฉ๋ ฅ: โ๏ธ {atk}
- ๋ฐฉ์ด๋ ฅ: ๐ก๏ธ {def}
- ๊ณจ๋: ๐ฐ {gold}G
- ๊ฒฝํ์น ๋ฐ: "Lv{level} ({exp}/{๋ค์๋ ๋ฒจํ์๊ฒฝํ์น})"
3. **๋ ๋ฒจ์
์์คํ
๋ก์ง**
- ํ์ ๊ฒฝํ์น ๊ณต์: `level * 100`
- ๊ฒฝํ์น๊ฐ ์ถฉ๋ถํ๋ฉด ๋ ๋ฒจ์
:
- level +1
- max_hp +20, max_mp +10, atk +3, def +2
- ํ์ฌ HP/MP๋ฅผ ์ต๋์น๋ก ํ๋ณต
- ์ด๊ณผ ๊ฒฝํ์น๋ ๋ค์ ๋ ๋ฒจ๋ก ์ด์
- ๋ ๋ฒจ์
์ ํ๋ฉด์ "๐ ๋ ๋ฒจ์
! Lv{new_level}" ํ ์คํธ ๋ฉ์์ง ํ์
4. **"์ ๊ฒ์ ์์" ๋ฒํผ**
- ํ์ฌ ์บ๋ฆญํฐ ๋ฐ์ดํฐ ์ญ์ (characters ํ
์ด๋ธ์์ DELETE)
- ๊ด๋ จ ์ธ๋ฒคํ ๋ฆฌ ์์ดํ
๋ ์ญ์ (inventory ํ
์ด๋ธ์์ character_id๋ก DELETE)
- ์ฟ ํค ์ญ์ ํ ํ์ด์ง ๋ฆฌ๋ค์ด๋ ํธ
5. **CSS ์คํ์ผ๋ง**
- ์บ๋ฆญํฐ ์นด๋: `border-radius: var(--m-radius-lg);`, `box-shadow: var(--m-shadow);`
- ํ๋ก๊ทธ๋ ์ค๋ฐ ์ ๋๋ฉ์ด์
: `transition: width 0.5s ease;`
- ์คํฏ ์์ด์ฝ ์ ๋ ฌ: flexbox๋ก ์์ด์ฝ+ํ
์คํธ ์ํ ๋ฐฐ์น
๋ชจ๋ DB ์ฟผ๋ฆฌ๋ prepared statement๋ก ์์ฑํ๊ณ , ๋ ๋ฒจ์
๋ก์ง์ ํจ์๋ก ๋ถ๋ฆฌํ์ฌ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๊ฒ ํ์ธ์.
๊ธฐ๋ ๊ฒฐ๊ณผ: - ๋๋ค์ ์ ๋ ฅ ํผ์ด ์ ์ ์๋ํ์ฌ ์บ๋ฆญํฐ ์์ฑ๋จ - ์์ฑ ํ ์ฟ ํค๊ฐ ์ค์ ๋๊ณ ์บ๋ฆญํฐ ์ ๋ณด ์นด๋๊ฐ ํ์๋จ - HP/MP ํ๋ก๊ทธ๋ ์ค๋ฐ๊ฐ ํ์ฌ ๊ฐ์ ๋ง์ถฐ ์๊ฐํ๋จ (์ ๋๋ฉ์ด์ ํฌํจ) - ์คํฏ(๊ณต๊ฒฉ๋ ฅ, ๋ฐฉ์ด๋ ฅ, ๊ณจ๋)์ด ์์ด์ฝ๊ณผ ํจ๊ป ๊น๋ํ๊ฒ ํ์๋จ - ๊ฒฝํ์น ๋ฐ๊ฐ "Lv1 (0/100)" ํ์์ผ๋ก ํ์๋จ - "์ ๊ฒ์ ์์" ๋ฒํผ ํด๋ฆญ ์ ๋ฐ์ดํฐ ์ด๊ธฐํ & ์ฟ ํค ์ญ์ ํ ํผ์ผ๋ก ๋์๊ฐ - ๋คํฌ๋ชจ๋ ์ ํ ์ ์นด๋ ๋ฐฐ๊ฒฝ/ํ ์คํธ ์์์ด ์์ฐ์ค๋ฝ๊ฒ ๋ณ๊ฒฝ๋จ
## Step 3: ๋์ ์ ํ & ๋ชฌ์คํฐ ์ธ์นด์ดํฐ
1. **๋์ ์ ํ UI**
- 3๊ฐ ๋์ ๋ฒํผ:
- ๐ฑ ์ด๊ธ ๋์ (๊ถ์ฅ Lv1~3)
- โ๏ธ ์ค๊ธ ๋์ (๊ถ์ฅ Lv4~8)
- ๐ฅ ๊ณ ๊ธ ๋์ (๊ถ์ฅ Lv9+)
- ๊ฐ ๋ฒํผ์ ๋ฐฐ๊ฒฝ์ ๊ทธ๋ผ๋ฐ์ด์
(์ด๊ธ: ์ฐ๋, ์ค๊ธ: ์ฃผํฉ, ๊ณ ๊ธ: ๋นจ๊ฐ)
- ๋์ ๋ณ "ํํํ๊ธฐ" ๋ฒํผ (ํด๋ฆญ ์ AJAX ์์ฒญ)
2. **๋ชฌ์คํฐ ๋๋ค ์ธ์นด์ดํฐ (AJAX)**
- ์๋ํฌ์ธํธ: `?action=encounter&dungeon={level}`
- ๋์ ๋ ๋ฒจ์ ๋ง๋ ๋ชฌ์คํฐ๋ฅผ DB์์ ๋๋ค ์ ํ:
- ์ด๊ธ: level 1~2 ๋ชฌ์คํฐ
- ์ค๊ธ: level 5~7 ๋ชฌ์คํฐ
- ๊ณ ๊ธ: level 10~15 ๋ชฌ์คํฐ
- ์ ํ๋ ๋ชฌ์คํฐ ์ ๋ณด๋ฅผ JSON์ผ๋ก ๋ฐํ:
```json
{
"monster_id": 1,
"name": "์ฌ๋ผ์",
"level": 1,
"hp": 30,
"max_hp": 30,
"atk": 5,
"def": 2,
"emoji": "๐ข"
}
```
3. **์ ํฌ ํ๋ฉด ์ ํ**
- AJAX ์๋ต์ ๋ฐ์ผ๋ฉด ๋์ ์ ํ UI๋ฅผ ์จ๊ธฐ๊ณ ์ ํฌ UI๋ฅผ ํ์
- ์ ํฌ UI ๊ตฌ์ฑ:
- ์๋จ: ๋ชฌ์คํฐ ์ ๋ณด ์นด๋ (์ด๋ฆ, ๋ ๋ฒจ, HP๋ฐ, ์ด๋ชจ์ง)
- ์ค๋จ: ์ ํฌ ๋ก๊ทธ ์์ญ (์คํฌ๋กค ๊ฐ๋ฅํ ํ
์คํธ ๋ฐ์ค)
- ํ๋จ: ํ๋ ๋ฒํผ (์ผ๋ฐ ๊ณต๊ฒฉ / ์คํฌ / ํฌ์
/ ๋๋ง)
4. **๋ชฌ์คํฐ ์ ๋ณด ํ์**
- ๋ชฌ์คํฐ ์ด๋ฆ & ๋ ๋ฒจ: "๐ข ์ฌ๋ผ์ Lv1"
- HP ๋ฐ: ๋นจ๊ฐ์ ํ๋ก๊ทธ๋ ์ค๋ฐ (ํ๋ ์ด์ด์ ๋์ผํ ์คํ์ผ)
- ๋ชฌ์คํฐ๋ณ ์ด๋ชจ์ง ๋งคํ:
- ์ฌ๋ผ์: ๐ข, ๊ณ ๋ธ๋ฆฐ: ๐บ, ์คํฌ: ๐, ๋คํฌ์ํ: ๐ง, ๋๋๊ณค: ๐, ๋ฐ๋ชฌ๋ก๋: ๐
5. **์ ํฌ ๋ก๊ทธ ์ด๊ธฐํ**
- ์ธ์นด์ดํฐ ์ ์ฒซ ๋ฉ์์ง: "์ผ์์ {๋ชฌ์คํฐ ์ด๋ฆ}์ด(๊ฐ) ๋ํ๋ฌ๋ค!"
- ๋ก๊ทธ๋ ์๋์์ ์๋ก ์์ด๋ ๋ฐฉ์ (์ต์ ๋ฉ์์ง๊ฐ ๋งจ ์๋)
- ์คํฌ๋กค์ ์๋์ผ๋ก ๋งจ ์๋๋ก ์ด๋
6. **์ ํฌ ์ํ ์ ์ฅ (์ธ์
)**
- ํ์ฌ ์ ํฌ ์ค์ธ ๋ชฌ์คํฐ ์ ๋ณด๋ฅผ PHP ์ธ์
์ ์ ์ฅ:
```php
$_SESSION['current_battle'] = [
'monster_id' => $monster['id'],
'monster_hp' => $monster['hp'],
'monster_max_hp' => $monster['hp']
];
```
- ์ดํ ์ ํฌ ์ก์
์์ ์ธ์
๋ฐ์ดํฐ๋ฅผ ์ฐธ์กฐ
CSS๋ก ์ ํฌ ํ๋ฉด ์ ํ ์ ํ์ด๋์ธ ์ ๋๋ฉ์ด์
์ ์ถ๊ฐํ๊ณ , ๋ชฌ์คํฐ ์นด๋์ ์ด์ง ํ๋ค๋ฆฌ๋ ํจ๊ณผ๋ฅผ ์ฃผ์ธ์ (`@keyframes shake`).
๊ธฐ๋ ๊ฒฐ๊ณผ: - ๋์ ์ ํ UI๊ฐ 3๊ฐ ๋ฒํผ์ผ๋ก ํ์๋จ (์์ ๊ทธ๋ผ๋ฐ์ด์ ํฌํจ) - "ํํํ๊ธฐ" ๋ฒํผ ํด๋ฆญ ์ AJAX ์์ฒญ์ด ๋ฐ์ํ๊ณ ๋ชฌ์คํฐ ์ ๋ณด๋ฅผ ๋ฐ์์ด - ๋์ ์ ํ UI๊ฐ ์ฌ๋ผ์ง๊ณ ์ ํฌ ํ๋ฉด์ผ๋ก ์ ํ๋จ (ํ์ด๋์ธ ์ ๋๋ฉ์ด์ ) - ๋ชฌ์คํฐ ์ ๋ณด ์นด๋๊ฐ ํ์๋จ (์ด๋ฆ, ๋ ๋ฒจ, HP๋ฐ, ์ด๋ชจ์ง) - ์ ํฌ ๋ก๊ทธ์ "์ผ์์ ์ฌ๋ผ์์ด(๊ฐ) ๋ํ๋ฌ๋ค!" ๋ฉ์์ง๊ฐ ์ถ๋ ฅ๋จ - ํ๋ ๋ฒํผ 4๊ฐ(์ผ๋ฐ ๊ณต๊ฒฉ, ์คํฌ, ํฌ์ , ๋๋ง)๊ฐ ํ์๋จ - ์ธ์ ์ ํ์ฌ ์ ํฌ ์ํ๊ฐ ์ ์ฅ๋จ - ๋ชฌ์คํฐ ์นด๋์ ํ๋ค๋ฆผ ์ ๋๋ฉ์ด์ ์ด ์ ์ฉ๋จ
## Step 4: ํด์ ์ ํฌ ์์คํ
๊ตฌํ
1. **์ผ๋ฐ ๊ณต๊ฒฉ ๋ก์ง (AJAX)**
- ์๋ํฌ์ธํธ: `?action=attack`
- ํ๋ ์ด์ด ํด:
- ๋ฐ๋ฏธ์ง ๊ณ์ฐ: `max(1, $player_atk - $monster_def + rand(0, 5))`
- ๋ชฌ์คํฐ HP ๊ฐ์ & ์ธ์
์
๋ฐ์ดํธ
- ๋ก๊ทธ ์ถ๊ฐ: "๋น์ ์ {๋ชฌ์คํฐ}์๊ฒ {๋ฐ๋ฏธ์ง}์ ํผํด๋ฅผ ์
ํ์ต๋๋ค!"
- ๋ชฌ์คํฐ ํด (๋ชฌ์คํฐ HP > 0์ธ ๊ฒฝ์ฐ):
- ๋ฐ๋ฏธ์ง ๊ณ์ฐ: `max(1, $monster_atk - $player_def + rand(0, 5))`
- ํ๋ ์ด์ด HP ๊ฐ์ & DB ์
๋ฐ์ดํธ
- ๋ก๊ทธ ์ถ๊ฐ: "{๋ชฌ์คํฐ}์ ๊ณต๊ฒฉ! {๋ฐ๋ฏธ์ง}์ ํผํด๋ฅผ ๋ฐ์์ต๋๋ค!"
- JSON ์๋ต:
```json
{
"player_hp": 85,
"monster_hp": 15,
"logs": [
"๋น์ ์ ์ฌ๋ผ์์๊ฒ 15์ ํผํด๋ฅผ ์
ํ์ต๋๋ค!",
"์ฌ๋ผ์์ ๊ณต๊ฒฉ! 5์ ํผํด๋ฅผ ๋ฐ์์ต๋๋ค!"
],
"battle_end": false
}
```
2. **์ ํฌ ์ข
๋ฃ ์กฐ๊ฑด**
- ๋ชฌ์คํฐ HP โค 0: ์น๋ฆฌ
- ๊ฒฝํ์น & ๊ณจ๋ ํ๋
- ๋๋ค ์์ดํ
๋๋กญ (30% ํ๋ฅ )
- ๋ ๋ฒจ์
์ฒดํฌ (๊ฒฝํ์น๊ฐ ์ถฉ๋ถํ๋ฉด ์๋ ๋ ๋ฒจ์
)
- ๋ก๊ทธ: "๐ ์น๋ฆฌ! {exp}EXP, {gold}G ํ๋!"
- ์์ดํ
๋๋กญ ์: "๐ {์์ดํ
์ด๋ฆ}์(๋ฅผ) ํ๋ํ์ต๋๋ค!"
- ํ๋ ์ด์ด HP โค 0: ํจ๋ฐฐ
- ๊ฒฝํ์น 10% ์์ค (์ต์ 0)
- ๊ณจ๋ ์์ค ์์ (์ด๋ณด์ ๋ฐฐ๋ ค)
- HP/MP ์ต๋์น๋ก ํ๋ณต (๋ง์ ๊ทํ)
- ๋ก๊ทธ: "๐ ํจ๋ฐฐํ์ต๋๋ค... ๋ง์๋ก ๋์๊ฐ๋๋ค."
- ์ ํฌ ์ข
๋ฃ ์ ์ธ์
ํด๋ฆฌ์ด & "๋์ ์ผ๋ก ๋์๊ฐ๊ธฐ" ๋ฒํผ ํ์
3. **์คํฌ ์ฌ์ฉ (AJAX)**
- ์๋ํฌ์ธํธ: `?action=skill`
- ์คํฌ "ํ์ ์ดํ": MP 20 ์๋ชจ, ๋ฐ๋ฏธ์ง 2๋ฐฐ
- MP ๋ถ์กฑ ์ ์๋ฌ ๋ฉ์์ง: "MP๊ฐ ๋ถ์กฑํฉ๋๋ค!"
- ์ฑ๊ณต ์ ์ผ๋ฐ ๊ณต๊ฒฉ๊ณผ ๋์ผํ ํด ์งํ
- ๋ก๊ทธ: "โก ํ์ ์ดํ ๋ฐ๋! {๋ฐ๋ฏธ์ง}์ ๊ฐ๋ ฅํ ํผํด!"
4. **ํฌ์
์ฌ์ฉ (AJAX)**
- ์๋ํฌ์ธํธ: `?action=use_potion&type={hp|mp}`
- ์ธ๋ฒคํ ๋ฆฌ์์ ํฌ์
์ฒดํฌ (inventory ํ
์ด๋ธ์์ item_type='potion' & item_name='{type}_potion')
- ์์ผ๋ฉด ์๋ฌ: "ํฌ์
์ด ์์ต๋๋ค!"
- HP ํฌ์
: HP +50 (์ต๋์น ์ด๊ณผ ๋ถ๊ฐ)
- MP ํฌ์
: MP +30 (์ต๋์น ์ด๊ณผ ๋ถ๊ฐ)
- ์ฌ์ฉ ํ ์ธ๋ฒคํ ๋ฆฌ์์ DELETE
- ๋ก๊ทธ: "๐ {ํฌ์
์ด๋ฆ} ์ฌ์ฉ! {ํ๋ณต๋} ํ๋ณต!"
- ๋ชฌ์คํฐ ํด์ ์ ์ ์งํ
5. **๋๋ง (AJAX)**
- ์๋ํฌ์ธํธ: `?action=flee`
- 50% ํ๋ฅ ๋ก ์ฑ๊ณต
- ์ฑ๊ณต ์: ์ ํฌ ์ข
๋ฃ, ์ธ์
ํด๋ฆฌ์ด, ๋ก๊ทธ: "๐ ๋ฌด์ฌํ ๋๋ง์ณค์ต๋๋ค!"
- ์คํจ ์: ๋ชฌ์คํฐ ํด๋ง ์งํ, ๋ก๊ทธ: "โ ๋๋ง ์คํจ! ๋ชฌ์คํฐ์ ๊ณต๊ฒฉ!"
6. **UI ์
๋ฐ์ดํธ**
- AJAX ์๋ต์ ๋ฐ์ ํ๋ฉด ๊ฐฑ์ :
- ํ๋ ์ด์ด HP/MP ๋ฐ ์ ๋๋ฉ์ด์
- ๋ชฌ์คํฐ HP ๋ฐ ์ ๋๋ฉ์ด์
- ๋ก๊ทธ ์ถ๊ฐ (์๋ ์คํฌ๋กค)
- ์ ํฌ ์ข
๋ฃ ์ ํ๋ ๋ฒํผ ์จ๊ธฐ๊ณ "๋์ ์ผ๋ก ๋์๊ฐ๊ธฐ" ๋ฒํผ ํ์
๋ชจ๋ ์ ํฌ ์ก์
์ ์๋ฒ ์ฌ์ด๋์์ ๊ฒ์ฆํ๊ณ , ํด๋ผ์ด์ธํธ๋ ๊ฒฐ๊ณผ๋ง ๋ฐ์์ UI๋ฅผ ์
๋ฐ์ดํธํ์ธ์. ๋ฒํผ ํด๋ฆญ ์ 0.5์ด ์ฟจํ์์ ์ ์ฉํ์ฌ ์ค๋ณต ํด๋ฆญ์ ๋ฐฉ์งํ์ธ์.
๊ธฐ๋ ๊ฒฐ๊ณผ: - "์ผ๋ฐ ๊ณต๊ฒฉ" ๋ฒํผ ํด๋ฆญ ์ AJAX ์์ฒญ์ด ๋ฐ์ํ๊ณ ์ ํฌ ๋ก๊ทธ๊ฐ ์ ๋ฐ์ดํธ๋จ - ํ๋ ์ด์ด์ ๋ชฌ์คํฐ์ HP ๋ฐ๊ฐ ๋ฐ๋ฏธ์ง์ ๋ฐ๋ผ ๋ถ๋๋ฝ๊ฒ ๊ฐ์ํจ - ๋ชฌ์คํฐ ์ฒ์น ์ ๊ฒฝํ์น/๊ณจ๋ ํ๋ ๋ฉ์์ง๊ฐ ๋ก๊ทธ์ ํ์๋จ - ์์ดํ ๋๋กญ ์ ์ธ๋ฒคํ ๋ฆฌ์ ์๋ ์ถ๊ฐ๋๊ณ ์๋ฆผ์ด ๋ธ - ๋ ๋ฒจ์ ์กฐ๊ฑด ์ถฉ์กฑ ์ "๐ ๋ ๋ฒจ์ !" ํ ์คํธ ๋ฉ์์ง ํ์ & ์คํฏ ์ฆ๊ฐ - ํ๋ ์ด์ด HP๊ฐ 0 ์ดํ๊ฐ ๋๋ฉด ํจ๋ฐฐ ๋ฉ์์ง & HP/MP ์ต๋์น ํ๋ณต - ์คํฌ ์ฌ์ฉ ์ MP ์๋ชจ & ๊ฐ๋ ฅํ ๋ฐ๋ฏธ์ง ์ ์ฉ - ํฌ์ ์ฌ์ฉ ์ HP/MP ํ๋ณต & ์ธ๋ฒคํ ๋ฆฌ์์ ์ ๊ฑฐ๋จ - ๋๋ง ์ฑ๊ณต/์คํจ์ ๋ฐ๋ผ ๋ค๋ฅธ ๋ฉ์์ง ์ถ๋ ฅ - ์ ํฌ ์ข ๋ฃ ํ "๋์ ์ผ๋ก ๋์๊ฐ๊ธฐ" ๋ฒํผ์ผ๋ก ๋์ ์ ํ ํ๋ฉด ๋ณต๊ท - ๋ฒํผ ํด๋ฆญ ์ 0.5์ด ์ฟจํ์ ์ ๋๋ฉ์ด์ ์ ์ฉ
## Step 5: ์ธ๋ฒคํ ๋ฆฌ & ์ฅ๋น ์์คํ
1. **์ธ๋ฒคํ ๋ฆฌ UI**
- ์บ๋ฆญํฐ ์ ๋ณด ์นด๋ ํ๋จ์ "๐ ์ธ๋ฒคํ ๋ฆฌ" ํญ ์ถ๊ฐ
- ํด๋ฆญ ์ ๋ชจ๋ฌ ๋๋ ์ฌ๋ผ์ด๋ ํจ๋๋ก ์์ดํ
๋ชฉ๋ก ํ์
- ์์ดํ
์นดํ
๊ณ ๋ฆฌ:
- ๋ฌด๊ธฐ (โ๏ธ): ๊ณต๊ฒฉ๋ ฅ ๋ณด๋์ค
- ๋ฐฉ์ด๊ตฌ (๐ก๏ธ): ๋ฐฉ์ด๋ ฅ ๋ณด๋์ค
- ํฌ์
(๐): HP/MP ํ๋ณต
- ๊ฐ ์์ดํ
์นด๋:
- ์์ดํ
์ด๋ฆ & ์ด๋ชจ์ง
- ์คํฏ ์ ๋ณด (์: "๊ณต๊ฒฉ๋ ฅ +5")
- ์ฅ์ฐฉ/ํด์ ๋ฒํผ (๋ฌด๊ธฐ/๋ฐฉ์ด๊ตฌ๋ง)
- ํ๋งค ๋ฒํผ (๊ฐ๊ฒฉ์ 50%)
2. **์์ดํ
๋๋กญ ์์คํ
**
- ๋ชฌ์คํฐ ์ฒ์น ์ 30% ํ๋ฅ ๋ก ์์ดํ
๋๋กญ
- ๋๋กญ ์์ดํ
์ ๋ชฌ์คํฐ ๋ฐ์ดํฐ์ `drop_items` JSON์์ ๋๋ค ์ ํ
- ์์ดํ
์คํฏ์ ๋ชฌ์คํฐ ๋ ๋ฒจ ๊ธฐ๋ฐ์ผ๋ก ์์ฑ:
- ๋ฌด๊ธฐ: ๊ณต๊ฒฉ๋ ฅ + (๋ชฌ์คํฐ ๋ ๋ฒจ * 2)
- ๋ฐฉ์ด๊ตฌ: ๋ฐฉ์ด๋ ฅ + (๋ชฌ์คํฐ ๋ ๋ฒจ * 1)
- ์ธ๋ฒคํ ๋ฆฌ์ INSERT:
```php
$stmt = $pdo->prepare("INSERT INTO inventory (character_id, item_type, item_name, item_stats, acquired_at) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$char_id, 'weapon', '์ฒ ๊ฒ', json_encode(['atk' => 5]), date('Y-m-d H:i:s')]);
```
3. **์ฅ๋น ์ฅ์ฐฉ/ํด์ (AJAX)**
- ์๋ํฌ์ธํธ: `?action=equip&item_id={id}`
- ๊ฐ์ ํ์
์ ๊ธฐ์กด ์ฅ์ฐฉ ์์ดํ
์ ๋จผ์ ํด์ (equipped=0)
- ์ ํํ ์์ดํ
์ ์ฅ์ฐฉ (equipped=1)
- ์บ๋ฆญํฐ ์คํฏ ์ฌ๊ณ์ฐ:
- ์ฅ์ฐฉ๋ ๋ชจ๋ ์์ดํ
์ ์คํฏ์ ํฉ์ฐ
- ๊ธฐ๋ณธ ์คํฏ + ์ฅ๋น ๋ณด๋์ค
- DB ์
๋ฐ์ดํธ ํ ํ๋ฉด ๊ฐฑ์
- ๋ก๊ทธ: "โ๏ธ {์์ดํ
์ด๋ฆ}์(๋ฅผ) ์ฅ์ฐฉํ์ต๋๋ค! ๊ณต๊ฒฉ๋ ฅ +{๋ณด๋์ค}"
4. **์์ดํ
ํ๋งค (AJAX)**
- ์๋ํฌ์ธํธ: `?action=sell&item_id={id}`
- ํ๋งค ๊ฐ๊ฒฉ ๊ณ์ฐ:
- ๋ฌด๊ธฐ/๋ฐฉ์ด๊ตฌ: ์คํฏ ๋ณด๋์ค * 10 * 0.5
- ํฌ์
: ๊ณ ์ ๊ฐ๊ฒฉ (HP ํฌ์
25G, MP ํฌ์
15G)
- ๊ณจ๋ ์ฆ๊ฐ & ์์ดํ
DELETE
- ์ฅ์ฐฉ ์ค์ธ ์์ดํ
์ ํ๋งค ๋ถ๊ฐ (์๋ฌ ๋ฉ์์ง)
- ๋ก๊ทธ: "๐ฐ {์์ดํ
์ด๋ฆ}์(๋ฅผ) {๊ฐ๊ฒฉ}G์ ํ๋งคํ์ต๋๋ค!"
5. **์์ ์์คํ
**
- ์ธ๋ฒคํ ๋ฆฌ ๋ชจ๋ฌ์ "๐ช ์์ " ํญ ์ถ๊ฐ
- ๊ตฌ๋งค ๊ฐ๋ฅ ์์ดํ
:
- HP ํฌ์
(50G)
- MP ํฌ์
(30G)
- ๊ตฌ๋งค ๋ฒํผ ํด๋ฆญ ์ (AJAX):
- ๊ณจ๋ ๋ถ์กฑ ์ฒดํฌ
- ๊ณจ๋ ์ฐจ๊ฐ & ์ธ๋ฒคํ ๋ฆฌ์ ํฌ์
์ถ๊ฐ
- ๋ก๊ทธ: "๐ {์์ดํ
}์(๋ฅผ) ๊ตฌ๋งคํ์ต๋๋ค!"
6. **UI ๊ฐ์ **
- ์ธ๋ฒคํ ๋ฆฌ ๋ชจ๋ฌ: ๋ฐฐ๊ฒฝ ๋ธ๋ฌ ์ฒ๋ฆฌ (`backdrop-filter: blur(5px);`)
- ์์ดํ
์นด๋: ํธ๋ฒ ์ ํ๋ ํจ๊ณผ (`transform: scale(1.05);`)
- ์ฅ์ฐฉ ์ค์ธ ์์ดํ
: ํ
๋๋ฆฌ ๊ฐ์กฐ (`border: 2px solid gold;`)
- ๋น ์ธ๋ฒคํ ๋ฆฌ: "์์ง ํ๋ํ ์์ดํ
์ด ์์ต๋๋ค" ์๋ด ๋ฉ์์ง
๋ชจ๋ ์์ดํ
์ก์
์ prepared statement๋ก ์ฒ๋ฆฌํ๊ณ , ์คํฏ ์ฌ๊ณ์ฐ ๋ก์ง์ ํจ์๋ก ๋ถ๋ฆฌํ์ฌ ์ฅ์ฐฉ/ํด์ ์ ์ฌ์ฌ์ฉํ์ธ์.
๊ธฐ๋ ๊ฒฐ๊ณผ: - ์บ๋ฆญํฐ ์นด๋์ "๐ ์ธ๋ฒคํ ๋ฆฌ" ๋ฒํผ์ด ์ถ๊ฐ๋จ - ํด๋ฆญ ์ ๋ชจ๋ฌ์ด ์ด๋ฆฌ๊ณ ํ๋ํ ์์ดํ ๋ชฉ๋ก์ด ํ์๋จ - ์์ดํ ์ ์นดํ ๊ณ ๋ฆฌ๋ณ๋ก ์ ๋ ฌ๋์ด ํ์๋จ (๋ฌด๊ธฐ/๋ฐฉ์ด๊ตฌ/ํฌ์ ) - ๋ฌด๊ธฐ/๋ฐฉ์ด๊ตฌ ์ฅ์ฐฉ ์ ์คํฏ์ด ์ฆ์ ๋ฐ์๋๊ณ ์บ๋ฆญํฐ ์นด๋๊ฐ ์ ๋ฐ์ดํธ๋จ - ์ฅ์ฐฉ ์ค์ธ ์์ดํ ์ ๊ธ์ ํ ๋๋ฆฌ๋ก ๊ฐ์กฐ๋จ - ์์ดํ ํ๋งค ์ ๊ณจ๋๊ฐ ์ฆ๊ฐํ๊ณ ์์ดํ ์ด ๋ชฉ๋ก์์ ์ฌ๋ผ์ง - ์์ ํญ์์ ํฌ์ ๊ตฌ๋งค ๊ฐ๋ฅ (๊ณจ๋ ๋ถ์กฑ ์ ์๋ฌ ๋ฉ์์ง) - ์ธ๋ฒคํ ๋ฆฌ ๋ชจ๋ฌ ๋ฐฐ๊ฒฝ์ด ๋ธ๋ฌ ์ฒ๋ฆฌ๋์ด ์๊ฐ์ ์ผ๋ก ๋ถ๋ฆฌ๋จ - ๋น ์ธ๋ฒคํ ๋ฆฌ์ผ ๋ ์๋ด ๋ฉ์์ง๊ฐ ํ์๋จ - ๋ชจ๋ ์์ดํ ์ก์ ํ ํ ์คํธ ์๋ฆผ์ด ํ์๋จ
## Step 6: ์ต์ข
๋ค๋ฌ๊ธฐ & ๋ณด๋์ค ๊ธฐ๋ฅ
1. **๋ ๋ฒจ์
์ ๋๋ฉ์ด์
๊ฐํ**
- ๋ ๋ฒจ์
์ ํ๋ฉด ์ ์ฒด์ "๐ LEVEL UP!" ์ค๋ฒ๋ ์ด ํ์
- 1์ด๊ฐ ๊ธ์ ๋น ํจ๊ณผ (`@keyframes glow`)
- ์๋ก์ด ์คํฏ์ ์ ๋๋ฉ์ด์
์ผ๋ก ํ์ (์ซ์ ์นด์ดํธ์
ํจ๊ณผ)
2. **์ ํฌ ํจ๊ณผ์ (์ ํ)**
- Web Audio API๋ก ๊ฐ๋จํ ํจ๊ณผ์ ์์ฑ:
- ๊ณต๊ฒฉ: ์งง์ "ํ" ์๋ฆฌ (์ฃผํ์ 200Hz, 0.1์ด)
- ๋ ๋ฒจ์
: ์์น ๋ฉ๋ก๋ (์ฃผํ์ 400โ600Hz, 0.5์ด)
- ์์ดํ
ํ๋: "๋ฉ" ์๋ฆฌ (์ฃผํ์ 800Hz, 0.2์ด)
- ์์๊ฑฐ ํ ๊ธ ๋ฒํผ ์ถ๊ฐ (localStorage์ ์ค์ ์ ์ฅ)
3. **์
์ ์์คํ
(์ ํ)**
- ์
์ ๋ฐ์ดํฐ๋ฅผ DB์ ์ ์ฅ (achievements ํ
์ด๋ธ):
- id, character_id, achievement_name, unlocked_at
- ์กฐ๊ฑด ์ฒดํฌ:
- "์ฒซ ์น๋ฆฌ": ๋ชฌ์คํฐ 1๋ง๋ฆฌ ์ฒ์น
- "์ฌ๋ผ์ ํํฐ": ์ฌ๋ผ์ 10๋ง๋ฆฌ ์ฒ์น
- "๋ ๋ฒจ ๋ง์คํฐ": ๋ ๋ฒจ 5 ๋ฌ์ฑ
- "๋ถ์": ๊ณจ๋ 1000G ๋ณด์
- ์
์ ๋ฌ์ฑ ์ ํ ์คํธ ์๋ฆผ & ๋ณด์ (๊ณจ๋ 100G)
- ์ธ๋ฒคํ ๋ฆฌ ๋ชจ๋ฌ์ "๐ ์
์ " ํญ ์ถ๊ฐ
4. **๋ญํน ์์คํ
(์ ํ)**
- ์ ์ฒด ํ๋ ์ด์ด ์์:
- ๋ ๋ฒจ ๊ธฐ์ค (๋์ ์ ๊ฒฝํ์น)
- ๊ณจ๋ ๊ธฐ์ค
- ๋์ ํ์ด์ง ์๋จ์ "๐ ๋ญํน" ๋ฒํผ ์ถ๊ฐ
- ํด๋ฆญ ์ ๋ชจ๋ฌ๋ก TOP 10 ํ์
- ๋ณธ์ธ ์์ ๊ฐ์กฐ (๋ฐฐ๊ฒฝ์ ๋ณ๊ฒฝ)
5. **๋ฐ์ํ ๋์์ธ**
- ๋ชจ๋ฐ์ผ ํ๋ฉด (768px ์ดํ):
- ์บ๋ฆญํฐ ์นด๋์ ๋์ ์์ญ์ ์ธ๋ก ๋ฐฐ์น
- ๋ฒํผ ํฌ๊ธฐ ํ๋ (ํฐ์น ์นํ์ )
- ์ ํฌ ๋ก๊ทธ ๋์ด ์ถ์
- ๋คํฌ๋ชจ๋ ๋์ ์ฌํ์ธ:
- ๋ชจ๋ ์์์ด CSS ๋ณ์ ์ฌ์ฉ
- ํ๋์ฝ๋ฉ๋ ์์์ด ์๋ค๋ฉด ๋ณ์๋ก ๊ต์ฒด
6. **์ฑ๋ฅ ์ต์ ํ**
- DB ์ฟผ๋ฆฌ ์ต์ํ:
- ์บ๋ฆญํฐ ์ ๋ณด๋ ํ ๋ฒ๋ง ๋ก๋ํ๊ณ JS ๋ณ์์ ์บ์ฑ
- ์ ํฌ ์ค ๋ถํ์ํ SELECT ์ ๊ฑฐ
- AJAX ์์ฒญ ์ค๋ณต ๋ฐฉ์ง:
- ๋ฒํผ ํด๋ฆญ ์ ์ฆ์ ๋นํ์ฑํ
- ์๋ต ํ ์ฌํ์ฑํ
- ๋ก๊ทธ ๋ฉ์์ง ๊ฐ์ ์ ํ (์ต๋ 50๊ฐ, ์ด๊ณผ ์ ์ค๋๋ ๊ฒ ์ญ์ )
7. **์๋ฌ ํธ๋ค๋ง**
- DB ์ฐ๊ฒฐ ์คํจ ์ ์ฌ์ฉ์ ์นํ์ ๋ฉ์์ง
- AJAX ์์ฒญ ์คํจ ์ ์ฌ์๋ ๋ฒํผ ํ์
- ์ธ์
๋ง๋ฃ ์ ์๋ ๋ก๊ทธ์์ & ์ฌ๋ก๊ทธ์ธ ์ ๋
8. **์ต์ข
ํ
์คํธ**
- ์๋๋ฆฌ์ค ํ
์คํธ:
1. ์บ๋ฆญํฐ ์์ฑ โ ์ด๊ธ ๋์ ํํ โ ์ฌ๋ผ์ ์ฒ์น โ ๋ ๋ฒจ์
2. ์์ดํ
ํ๋ โ ์ฅ์ฐฉ โ ์คํฏ ์ฆ๊ฐ ํ์ธ
3. ์ค๊ธ ๋์ ๋์ โ ํจ๋ฐฐ โ ๊ฒฝํ์น ์์ค ํ์ธ
4. ํฌ์
๊ตฌ๋งค โ ์ฌ์ฉ โ HP ํ๋ณต ํ์ธ
5. ๊ณ ๊ธ ๋์ ๋์ โ ๋๋๊ณค ์ฒ์น โ ์
์ ๋ฌ์ฑ
- ๋คํฌ๋ชจ๋ ์ ํ ์ ๋ชจ๋ UI ์์ ์ ์ ์๋ ํ์ธ
- ๋ชจ๋ฐ์ผ ํ๋ฉด์์ ํฐ์น ์ธํฐ๋์
ํ
์คํธ
๋ชจ๋ ๊ธฐ๋ฅ์ด ์์ฑ๋๋ฉด README.md๋ฅผ ์์ฑํ์ฌ ๊ฒ์ ์ค๋ช
, ์กฐ์๋ฒ, ์์คํ
์๊ตฌ์ฌํญ์ ์ ๋ฆฌํ์ธ์.
๊ธฐ๋ ๊ฒฐ๊ณผ: - ๋ ๋ฒจ์ ์ ํ๋ฉด ์ ์ฒด์ "LEVEL UP!" ์ค๋ฒ๋ ์ด๊ฐ 1์ด๊ฐ ํ์๋จ (๊ธ์ ๋น ํจ๊ณผ) - ์ ํฌ ํจ๊ณผ์์ด ์ฌ์๋จ (์์๊ฑฐ ํ ๊ธ ๊ฐ๋ฅ) - ์ ์ ์์คํ ์ด ์๋ํ์ฌ ์กฐ๊ฑด ๋ฌ์ฑ ์ ์๋ฆผ & ๋ณด์์ด ์ง๊ธ๋จ - ๋ญํน ์์คํ ์ด TOP 10์ ํ์ํ๊ณ ๋ณธ์ธ ์์๋ฅผ ๊ฐ์กฐํจ - ๋ชจ๋ฐ์ผ ํ๋ฉด์์ ๋ ์ด์์์ด ์ธ๋ก๋ก ์ฌ๋ฐฐ์น๋๊ณ ๋ฒํผ์ด ํฐ์นํ๊ธฐ ํธํ๊ฒ ํ๋๋จ - ๋คํฌ๋ชจ๋์์ ๋ชจ๋ ์์์ด ์์ฐ์ค๋ฝ๊ฒ ๋ณ๊ฒฝ๋จ - AJAX ์์ฒญ ์ค ๋ฒํผ์ด ๋นํ์ฑํ๋์ด ์ค๋ณต ํด๋ฆญ์ด ๋ฐฉ์ง๋จ - ์ ํฌ ๋ก๊ทธ๊ฐ 50๊ฐ๋ก ์ ํ๋์ด ์ฑ๋ฅ์ด ์ ์ง๋จ - ์๋ฌ ๋ฐ์ ์ ์ฌ์ฉ์ ์นํ์ ์ธ ๋ฉ์์ง๊ฐ ํ์๋จ - ๋ชจ๋ ์๋๋ฆฌ์ค ํ ์คํธ๊ฐ ํต๊ณผํ๊ณ ๊ฒ์์ด ์ ์ ์๋ํจ - README.md์ ๊ฒ์ ์๊ฐ์ ์กฐ์๋ฒ์ด ๋ช ํํ ์์ฑ๋จ
์ ์ถ๋ ์ํ (0)
๋ก๊ทธ์ธ ํ ์ ์ถ์์ง ์ ์ถ๋ ์ํ์ด ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ ๋์ ์๊ฐ ๋์ด๋ณด์ธ์!