--- id: wiki-2026-0508-combat-timeline-difficulty-scali title: Combat Timeline Difficulty Scaling category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Combat Difficulty Curve, Encounter Scaling, Dynamic Difficulty Adjustment] duplicate_of: none source_trust_level: B confidence_score: 0.85 verification_status: applied tags: [game-design, combat, difficulty, ddа, encounter] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: C#/Python framework: Game-engine-agnostic --- # Combat Timeline Difficulty Scaling ## 매 한 줄 > **"매 combat encounter 의 매력 = 매 player skill 곡선과 challenge 곡선의 일치 (flow channel)."**. 매 timeline-based scaling 은 encounter 의 시작/중반/끝 phase 별로 enemy 능력을 progress 시키며, 매 player metric (DPS, HP%, time-to-kill) 을 feedback 으로 받아 dynamic 하게 조정. 매 2026 modern AAA (Elden Ring DLC, Helldivers 2) 가 telemetry-driven scaling 채택. ## 매 핵심 ### 매 scaling axis - **Static curve**: 매 fixed level → enemy stat lookup table. - **Dynamic (DDA)**: 매 runtime player perf 로 parameter 조정. - **Timeline phase**: 매 encounter 내부 phase 분할 (intro → escalation → climax). - **Hybrid**: 매 baseline curve + DDA correction. ### 매 measurable metric - **TTK** (time to kill enemy). - **TTD** (time to death — player). - **Damage taken / second**. - **Resource economy** (potions/ammo per minute). - **Player retry count**. ### 매 응용 1. **Soulslike boss phase transition**: 매 50%/25% HP → new moveset. 2. **Roguelike floor scaling**: 매 depth × player level 함수. 3. **MMO raid enrage timer**: 매 hard cutoff DPS check. 4. **Casual mode auto-easing**: 매 3회 사망 → enemy HP -10%. ## 💻 패턴 ### Phase-based encounter timeline ```csharp public class BossEncounter : MonoBehaviour { enum Phase { Intro, Build, Climax, Enrage } Phase phase = Phase.Intro; float t; void Update() { t += Time.deltaTime; var hpFrac = boss.HP / boss.MaxHP; var newPhase = phase; if (hpFrac < 0.25f) newPhase = Phase.Climax; else if (hpFrac < 0.60f) newPhase = Phase.Build; else if (t > 180f) newPhase = Phase.Enrage; if (newPhase != phase) { OnPhaseEnter(newPhase); phase = newPhase; } ApplyPhaseModifiers(phase); } } ``` ### Stat curve table ```yaml # enemies/orc_warrior.yaml levels: 1: { hp: 100, dmg: 10, speed: 3.0 } 10: { hp: 250, dmg: 22, speed: 3.5 } 20: { hp: 600, dmg: 50, speed: 4.0 } 50: { hp: 5000, dmg: 220, speed: 5.0 } # interpolate between keypoints ``` ```csharp EnemyStats Lerp(EnemyStats a, EnemyStats b, float t) => new EnemyStats { HP = Mathf.Lerp(a.HP, b.HP, t), Damage = Mathf.Lerp(a.Damage, b.Damage, t), Speed = Mathf.Lerp(a.Speed, b.Speed, t), }; ``` ### DDA — sliding window perf ```python class DDAController: def __init__(self, target_ttd=45.0, window=5): self.target = target_ttd self.history = collections.deque(maxlen=window) self.scale = 1.0 def record_death(self, ttd_seconds): self.history.append(ttd_seconds) if len(self.history) < 3: return avg = sum(self.history) / len(self.history) # too easy → ramp up; too hard → ease delta = (avg - self.target) / self.target # +0.2 = 20% too easy self.scale = clamp(self.scale + delta * 0.05, 0.7, 1.5) def apply(self, enemy): enemy.hp *= self.scale enemy.dmg *= math.sqrt(self.scale) # damage scales softer ``` ### Enrage timer ```csharp void Update() { enrageT += Time.deltaTime; if (enrageT > enrageStart) { var f = Mathf.Clamp01((enrageT - enrageStart) / 30f); boss.DamageMultiplier = 1f + f * 4f; // 5x dmg over 30s } } ``` ### Skill-bracket matchmaking adjust ```python def select_encounter(player_mmr: int, depth: int): target_difficulty = base_curve(depth) * mmr_multiplier(player_mmr) candidates = [e for e in pool if abs(e.difficulty - target_difficulty) < 0.15] return random.choice(candidates) if candidates else fallback(pool, target_difficulty) ``` ### Telemetry-driven re-tuning (offline) ```sql -- find under-tuned bosses (too easy) SELECT boss_id, AVG(time_to_kill) AS avg_ttk, AVG(player_deaths) AS avg_deaths, COUNT(*) AS attempts FROM encounter_log WHERE patch_version = '2.4.0' GROUP BY boss_id HAVING avg_ttk < 30 AND avg_deaths < 0.3 ORDER BY attempts DESC; ``` ### Adaptive damage curve ```csharp // damage taken curves softer the lower player HP — "comeback mechanic" float TakenMultiplier(float hpFrac) => Mathf.Lerp(1.2f, 0.7f, 1f - hpFrac); // low HP = less dmg taken ``` ## 매 결정 기준 | 상황 | Scaling | |---|---| | Linear narrative game | static curve | | Roguelike / replayable | static + run-level scale | | Live-service skill gap | DDA + bracket matchmaking | | Boss fight 10+ min | phase-based + enrage | | Accessibility mode | one-way DDA (only ease) | **기본값**: phase-based timeline + soft DDA (max ±20%) + telemetry retune per patch. ## 🔗 Graph - 부모: [[Game_Design]] · [[Combat_System]] - 변형: [[Dynamic_Difficulty_Adjustment]] ## 🤖 LLM 활용 **언제**: encounter design, difficulty curve tuning, DDA controller 설계. **언제 X**: pure narrative pacing (story beats 영역). ## ❌ 안티패턴 - **HP-sponge scaling**: 매 단순 HP × 10 → boring, not harder. - **Hidden DDA without disclosure**: 매 player 가 눈치채면 frustration. - **No floor on DDA**: 매 player 일부러 죽으며 game 망가뜨림. - **One curve for all enemies**: 매 archetype 별 differentiation 부재. - **Untested enrage timer**: 매 DPS check 가 unfair RNG 가 되면 community 폭발. ## 🧪 검증 / 중복 - Verified (GDC talks "Resident Evil 4 DDA" 2005, "Helldivers 2 mission director" 2024). - 신뢰도 B. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — phase timeline, DDA controller, telemetry retuning |