f8b21af4be
10_Wiki/Topics 대규모 정리: - 오류 캡처/미완성 stub 문서 227개 제거 - 교차폴더 중복 43클러스터 병합 (63파일 → redirect) - 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건 - 카테고리 MOC 6개 신규 생성 - Graph 섹션 미해결 related-keyword 링크 10,058건 제거 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
194 lines
6.0 KiB
Markdown
194 lines
6.0 KiB
Markdown
---
|
|
id: wiki-2026-0508-가차-gacha
|
|
title: 가차(Gacha)
|
|
category: 10_Wiki/Topics
|
|
status: verified
|
|
canonical_id: self
|
|
aliases: [Gacha, ガチャ, 뽑기, Lootbox]
|
|
duplicate_of: none
|
|
source_trust_level: A
|
|
confidence_score: 0.9
|
|
verification_status: applied
|
|
tags: [game-design, monetization, randomness, mobile-game]
|
|
raw_sources: []
|
|
last_reinforced: 2026-05-10
|
|
github_commit: pending
|
|
tech_stack:
|
|
language: TypeScript
|
|
framework: Game Server (Node.js)
|
|
---
|
|
|
|
# 가차(Gacha)
|
|
|
|
## 매 한 줄
|
|
> **"매 weighted random pull + pity system — 매 mobile game monetization 의 dominant 메커니즘."**. 1965 일본 캡슐 토이 (gachapon) 어원. 2010s Puzzle & Dragons / FGO / Genshin Impact 매 globalization. 매 2026 regulatory scrutiny (Belgium ban, China 概率 disclosure, Japan 上限) 매 mature.
|
|
|
|
## 매 핵심
|
|
|
|
### 매 components
|
|
- **Pool / Banner**: 매 pullable item set — rate-up, character-specific, standard.
|
|
- **Rate**: 매 rarity 별 확률 (e.g. SSR 0.6%, SR 5.4%, R 94%).
|
|
- **Pity**: 매 N pull guarantee — 매 player frustration cap (Genshin 90 pull, FGO 330).
|
|
- **Soft pity**: 매 pity 근접 시 rate ramp (Genshin 75+ → SSR rate 폭증).
|
|
- **Currency**: 매 premium (paid) vs free — 매 dual track.
|
|
- **50/50**: 매 rate-up 미달 시 standard pool 으로 떨어짐.
|
|
|
|
### 매 design 축
|
|
- **Convergent vs divergent**: 매 dupe 가 useful (constellation) vs useless (shard).
|
|
- **Hard pity**: 매 deterministic ceiling — 매 player trust.
|
|
- **Spark / mileage**: 매 pull 누적 → 매 직접 교환 — 매 ultimate pity.
|
|
|
|
### 매 응용
|
|
1. Mobile RPG (Genshin Impact, Honkai Star Rail).
|
|
2. Card collection (Hearthstone pack 매 gacha 변형).
|
|
3. Battle pass 매 deterministic 변형.
|
|
4. Cosmetic-only gacha (매 regulatory safer).
|
|
|
|
## 💻 패턴
|
|
|
|
### Weighted random pull
|
|
```typescript
|
|
type Item = { id: string; rarity: 'SSR'|'SR'|'R'; rateUp?: boolean };
|
|
|
|
function pull(rates: Record<string, number>, items: Item[]): Item {
|
|
const r = Math.random();
|
|
let acc = 0;
|
|
let chosenRarity: keyof typeof rates;
|
|
for (const [rarity, p] of Object.entries(rates)) {
|
|
acc += p;
|
|
if (r < acc) { chosenRarity = rarity as any; break; }
|
|
}
|
|
const pool = items.filter(i => i.rarity === chosenRarity!);
|
|
return pool[Math.floor(Math.random() * pool.length)];
|
|
}
|
|
|
|
const rates = { SSR: 0.006, SR: 0.054, R: 0.94 };
|
|
```
|
|
|
|
### Soft + hard pity
|
|
```typescript
|
|
class PitySystem {
|
|
pulls = 0;
|
|
softStart = 75;
|
|
hardCap = 90;
|
|
|
|
ssrRate(): number {
|
|
if (this.pulls >= this.hardCap) return 1.0;
|
|
if (this.pulls < this.softStart) return 0.006;
|
|
// 매 linear ramp 75 → 89
|
|
const t = (this.pulls - this.softStart) / (this.hardCap - this.softStart);
|
|
return 0.006 + t * (1.0 - 0.006);
|
|
}
|
|
|
|
pull(): { rarity: string; pulls: number } {
|
|
this.pulls++;
|
|
if (Math.random() < this.ssrRate()) {
|
|
const out = { rarity: 'SSR', pulls: this.pulls };
|
|
this.pulls = 0;
|
|
return out;
|
|
}
|
|
return { rarity: 'SR/R', pulls: this.pulls };
|
|
}
|
|
}
|
|
```
|
|
|
|
### 50/50 rate-up
|
|
```typescript
|
|
class RateUpBanner {
|
|
guaranteed = false; // 매 직전 SSR 이 off-banner 이면 다음 SSR rate-up 확정
|
|
|
|
rollSSR(featured: Item, standardSSRs: Item[]): Item {
|
|
if (this.guaranteed) {
|
|
this.guaranteed = false;
|
|
return featured;
|
|
}
|
|
if (Math.random() < 0.5) {
|
|
this.guaranteed = false;
|
|
return featured;
|
|
}
|
|
this.guaranteed = true;
|
|
return standardSSRs[Math.floor(Math.random() * standardSSRs.length)];
|
|
}
|
|
}
|
|
```
|
|
|
|
### Spark / mileage shop
|
|
```typescript
|
|
type Wallet = { stones: number; mileage: number };
|
|
|
|
function spend(wallet: Wallet, cost: number) {
|
|
if (wallet.stones < cost) throw new Error('insufficient');
|
|
wallet.stones -= cost;
|
|
wallet.mileage += 1; // 매 pull 당 1 mileage
|
|
}
|
|
|
|
function exchangeMileage(wallet: Wallet, item: Item, price = 300) {
|
|
if (wallet.mileage < price) throw new Error('mileage 부족');
|
|
wallet.mileage -= price;
|
|
return item;
|
|
}
|
|
```
|
|
|
|
### 매 rate disclosure (compliance)
|
|
```typescript
|
|
// 매 일본 JOGA / 중국 网信办 매 mandatory disclosure.
|
|
function bannerDisclosure(banner: Banner) {
|
|
return {
|
|
rates: banner.rates, // SSR 0.6% etc
|
|
pity: { soft: 75, hard: 90 },
|
|
rateUpItems: banner.featured.map(i => i.id),
|
|
expectedCostJPY: estimateExpectedCost(banner),
|
|
};
|
|
}
|
|
```
|
|
|
|
### Server-side roll (anti-cheat)
|
|
```typescript
|
|
import { randomBytes } from 'node:crypto';
|
|
|
|
// 매 client 의 RNG 신뢰 X — 매 server 결정.
|
|
async function serverPull(userId: string, bannerId: string) {
|
|
const seed = randomBytes(16).toString('hex');
|
|
const result = pull(bannerRates[bannerId], items);
|
|
await db.gachaLog.insert({ userId, bannerId, seed, result, ts: Date.now() });
|
|
return result;
|
|
}
|
|
```
|
|
|
|
## 매 결정 기준
|
|
| 상황 | Approach |
|
|
|---|---|
|
|
| 매 player 신뢰 | hard pity + spark |
|
|
| 매 monetization 극대화 | soft pity 후반 ramp |
|
|
| 매 collection 게임 | convergent (constellation 유용) |
|
|
| 매 PVP 밸런스 | 매 cosmetic-only 우선 (regulatory safe) |
|
|
| 매 신규 banner | 50/50 with rate-up |
|
|
|
|
**기본값**: 매 soft pity 75 / hard 90 / 50-50 / spark 300 — 매 Genshin model 의 industry baseline.
|
|
|
|
## 🔗 Graph
|
|
- 부모: [[Game_Monetization]]
|
|
- 변형: [[Lootbox]]
|
|
- 응용: [[Genshin_Impact]]
|
|
|
|
## 🤖 LLM 활용
|
|
**언제**: 매 mobile RPG monetization 설계, gacha sim, drop rate calculation.
|
|
**언제 X**: 매 Belgium / Netherlands market (매 lootbox 금지). 매 PEGI 18 관련 region risk.
|
|
|
|
## ❌ 안티패턴
|
|
- **Hidden rate**: 매 disclosure X — 매 regulatory ban / store removal 위험.
|
|
- **No pity**: 매 player frustration → churn 폭증.
|
|
- **Client-side RNG**: 매 trivially exploit — 매 packet replay attack.
|
|
- **Stacking dupes 무용**: 매 SSR pull 후 dupe = 매 무가치 → 매 trust 손실. 매 conversion 시스템 mandatory.
|
|
- **PvP P2W gacha**: 매 정체된 player base — 매 cosmetic 분리.
|
|
|
|
## 🧪 검증 / 중복
|
|
- Verified (Genshin Wiki rate data, JOGA guidelines, Belgium Gaming Commission report).
|
|
- 신뢰도 A.
|
|
|
|
## 🕓 Changelog
|
|
| 날짜 | 변경 |
|
|
|---|---|
|
|
| 2026-05-08 | Phase 1 |
|
|
| 2026-05-10 | Manual cleanup — gacha mechanics + pity / regulatory |
|