# Wave Manager Logic > **Status**: In Design > **Author**: SepComet + Claude > **Last Updated**: 2026-04-27 > **Implements Pillar**: 战场即信息 (The Field is Information), 形态即战术 (Form is Tactics) ## Overview Wave Manager Logic 是夜裔的遭遇战编排系统——控制每一波敌人的生成时机、类型构成、数量和波次推进节奏。它不是一个简单的"定时刷怪"计时器,而是战斗节奏的作曲家:它决定什么时候让玩家感到压力(混合编制波次)、什么时候给玩家喘息(波次间 10-20s 间隔)、以及什么时候考验玩家的形态切换决策(同一波内投放多种需要不同形态克制的敌人)。 玩家直接感受 Wave Manager 的输出——但不是通过 UI 数字,而是通过**战场节奏**。一波 Swarm 海从四面八方涌来就是"切雾形"的信号。一波 Brute+Stalker 混合编制就是在问玩家:"你先处理哪个?Brute 的弹反窗口还是 Stalker 的冲刺?"波次清空后的短暂沉默不是空白——那是玩家重新评估血能、调整位置、预判下一波构成的战略时刻。Wave Manager Logic 是"战场即信息"和"形态即战术"的编排引擎——它通过敌人构成设计来创造有意义的形态切换压力,而不是靠随机数。 ## Player Fantasy Wave Manager Logic 服务于一个任何动作游戏玩家都熟悉但很少被命名的幻想:**掌控节奏**。当你清空一波敌人、战场突然安静的那 10 秒钟,你的心跳从"战斗模式"的高频切回战术思考——"我还有多少血能?下一波会是什么?我该站在哪里?"——这就是 Wave Manager 在发挥作用。它不是制造敌人,而是制造**期待**。 好的波次编排像一场 DJ 演出:它知道什么时候给你密集的低音(Swarm 海)、什么时候切入一个重拍让你展示技巧(Brute 弹反)、什么时候让所有声音同时响起制造混乱(混合编制)、以及什么时候全部静默给你喘息(波次间隔)。玩家不会说"这波次设计得真好"——他们会说"再来一波,我能打"。 参考 Vampire Survivors 的波次节奏——敌人密度波浪式增长,偶尔给一个"安全窗口"让你有空间操作——和 Hades 的遭遇战房间——每个房间是一场独立的微型战斗拼图。夜裔的 Wave Manager 将两者融合:**波浪式密度 + 拼图式构成**。每一波不只是"更多敌人",而是"不同的问题"。第一波是热身(纯 Swarm,教你切雾形),第三波是期中考试(Brute + Swarm 混合,考验你什么时候放弃 AOE 去做弹反),最后一波是终极考验(三种类型同时在场,要求完整的形态切换循环)。 ## Detailed Design ### Core Rules **1. Wave Lifecycle** ``` InterWave ──(delay elapsed)──→ WaveActive ──(all enemies dead)──→ InterWave ↑ │ └──────────────────── (next wave exists) ────────────────────────────┘ │ └── (no more waves) → LevelComplete ``` **2. Spawning Rules** - 敌人从竞技场边界(perimeter)生成:以竞技场中心为圆心、固定半径 R 的圆周上随机取点 - 生成时敌人面向竞技场中心(朝向玩家方向) - 同一 `SpawnGroup` 内的敌人同时生成(同一帧),不同 SpawnGroup 之间有 `SpawnDelay` 间隔 - 生成后立即进入 Enemy AI 的 Idle 状态(玩家进入 DetectionRange 时进入 Chase) **3. Wave Tracking** - Wave Manager 订阅 `EnemyAI.OnEnemyDied(enemyId, enemyType, killerForm)` 事件 - 维护 `aliveEnemyCount` — 当前波次中存活敌人数量 - 当 `aliveEnemyCount == 0` 且所有 SpawnGroup 已生成完毕 → 波次清空 - 仅追踪由当前波次生成的敌人。不在波次中的敌人不计入 **4. Wave Advancement** - 波次清空后立即进入 InterWave 状态,启动 `InterWaveDelay` 计时器(10-20s,由 LevelData 配置) - 计时器结束 → 自动推进到下一波 - 无需玩家交互 — 节奏完全由设计者控制 - 如果是最后一波 → 发射 `OnLevelComplete`,不再进入 InterWave **5. Level Completion** - 最后一波的所有敌人死亡 → `OnLevelComplete` 发射 - 此时所有敌人已清除,关卡结束 - 后续流程(结算、菜单、下一关)由 L1/L2 处理 ### Wave Structure **WaveData 定义:** ``` WaveData { int WaveIndex; // 0-based wave number string WaveName; // Designer label (e.g. "Swarm Intro") List SpawnGroups; // Groups spawned this wave float PreWaveDelay; // Additional delay before first spawn (default 0) bool IsFinalWave; // Marks level completion } ``` **WaveSpawnGroup 定义:** ``` WaveSpawnGroup { EnemyType Type; // Swarm(1) / Brute(2) / Stalker(3) int Count; // How many enemies of this type float SpawnDelay; // Seconds after wave start to spawn this group SpawnPattern Pattern; // Perimeter / Clustered / Opposite / Random } ``` **SpawnPattern 枚举:** | Pattern | Behavior | When to Use | |---------|----------|-------------| | `Perimeter` | 随机分布在竞技场边界圆周上 | 标准包围感,适合 Swarm | | `Clustered` | 集中在圆周的一个 60° 弧段内 | 紧凑编队,适合 Brute 群 | | `Opposite` | 分布在两个相对的 60° 弧段 | 夹击压力,适合 Stalker 编队 | | `Random` | 完全随机分布在整个边界上 | 混合编制默认 | ### MVP Level: "First Night" 波次设计 7 波,教学曲线从单一类型引入到全类型混合: | Wave | Name | Composition | Design Intent | |------|------|-------------|---------------| | 1 | Awakening | 8× Swarm (Perimeter) | 雾形教学 — 圆形 AOE 清屏。玩家学会"看到很多小敌人→切雾形"。 | | 2 | The Pack | 12× Swarm (Perimeter, 2 groups staggered 1s) | 雾形巩固 — 更多数量,分两批生成创造持续压力。 | | 3 | Heavy | 2× Brute (Clustered) | 弹反教学 — 两个 Brute 先后攻击,玩家学会"看到大块头→切人形弹反"。SpawnDelay=2s 确保不会同时攻击。 | | 4 | Swarm + Brute | 8× Swarm (Perimeter) + 2× Brute (Opposite) | 首次混合 — 玩家被迫在 AOE 清小怪和弹反大怪之间切换。Swarm 先刷(0s),Brute 延迟 3s 刷。 | | 5 | Hunters | 3× Stalker (Opposite, 2 groups staggered 0.5s) | 冲刺教学 — 首次引入 Stalker,玩家学会"看到高速冲刺→切狼形对撞"。 | | 6 | Full House | 6× Swarm (Perimeter) + 1× Brute (Clustered) + 2× Stalker (Opposite) | 全类型混合 — 三种形态循环的完整考验。生成顺序:Swarm(0s) → Stalker(2s) → Brute(4s)。 | | 7 | Final Stand | 10× Swarm (Perimeter) + 3× Brute (Random) + 3× Stalker (Random) | 最终波 — 高密度全类型。所有 SpawnGroup 同时生成(SpawnDelay=0),制造最大混乱和最大切换压力。 | **设计原则**: - 每种敌人类型的前两次出现都是"纯编制"(只有该类型),给予玩家学习空间 - 混合编制在玩家掌握基础后引入(Wave 4+) - 生成顺序创造"先处理A再处理B"的引导:先刷的敌人先到达玩家 - SpawnDelay 控制敌人到达玩家的时间差,防止所有敌人同时压上 ### Interactions with Other Systems | System | Direction | Interface | |--------|-----------|-----------| | **Enemy AI Logic** | Downstream | 生成敌人实例并注入 `EnemyTypeConfig`。调用 Enemy AI 的 `SpawnEnemy(typeConfig, position, facingAngle)` 工厂方法。 | | **Enemy AI Logic** | Upstream | 订阅 `OnEnemyDied(enemyId, enemyType, killerForm)` — 追踪存活敌人数量,判断波次是否结束。 | | **Combat Logic** | — | 无直接依赖。Wave Manager 不参与伤害判定。通过 Enemy AI 间接关联。 | | **UI/HUD (L2)** | Downstream | 发射 `OnWaveChanged(waveIndex, waveName)` — HUD 显示当前波次信息。发射 `OnInterWaveStarted(duration)` — HUD 显示倒计时或"准备"提示。 | | **VFX Spawner (L1)** | Downstream | 发射 `OnWaveStarted`(波次开始 VFX)、`OnWaveCleared`(波次清空 VFX)、`OnEnemySpawned`(敌人出现 VFX) | | **Audio Player (L1)** | Downstream | 发射 `OnWaveStarted`(波次音效)、`OnInterWaveStarted`(喘气/心跳音效) | | **Level Loader (L1)** | Upstream | Level Loader 加载关卡时提供 `LevelData`(包含所有 WaveData)。可选:提供竞技场边界参数(中心点、半径)用于生成位置计算。 | | **Score Calculator** | Downstream | 发射 `OnWaveCleared` + 波次数据 — Score Calculator 可根据波次清空速度计算评分。 | ## Formulas ### Spawn Position Calculation The spawn position formula is defined as: `spawnPos = arenaCenter + (cos(angle), 0, sin(angle)) × arenaRadius` **Variables:** | Variable | Symbol | Type | Range | Description | |----------|--------|------|-------|-------------| | Arena center | `arenaCenter` | Vector3 | any | Arena center point (from Level Loader) | | Arena radius | `arenaRadius` | float | 20–40 | Spawn perimeter radius (LevelData config) | | Angle | `angle` | float | 0–360° | Random angle for perimeter spawns. Clustered: 60° range from base angle. Opposite: two 60° ranges 180° apart. | **Output Range**: Any point on the perimeter circle at `arenaRadius` from center. For `Clustered` pattern: `angle = baseAngle + random(-30°, +30°)` where `baseAngle` is randomized per wave. For `Opposite` pattern: half at `baseAngle ± 30°`, half at `baseAngle + 180° ± 30°`. For `Random` pattern: `angle = random(0, 360°)`. --- ### Alive Enemy Count The wave tracking formula is defined as: `aliveCount = spawnedThisWave - killedThisWave` **Variables:** | Variable | Symbol | Type | Range | Description | |----------|--------|------|-------|-------------| | Spawned this wave | `spawnedThisWave` | int | 0–totalWaveEnemies | Cumulative count of enemies spawned in current wave | | Killed this wave | `killedThisWave` | int | 0–spawnedThisWave | Incremented on each `OnEnemyDied` for enemies belonging to this wave | **Output**: 0 to totalWaveEnemies. Wave clears when `aliveCount == 0 && allSpawnGroupsCompleted`. --- ### Wave Completion The wave completion formula is defined as: `isWaveCleared = (aliveEnemyCount == 0) AND (allSpawnGroups have been spawned)` **Output**: Boolean. Once true, triggers transition to InterWave or LevelComplete. ## Edge Cases - **If all enemies in a wave are killed before all SpawnGroups have spawned**: Wave remains active. `isWaveCleared` requires both conditions — all enemies dead AND all groups spawned. Remaining SpawnGroups continue spawning on schedule. - **If player dies during WaveActive**: Wave state freezes. Death/Respawn Rules manages respawn. On respawn, Wave Manager resets the current wave to its initial state (all enemies despawned, wave restarts from InterWave → WaveActive). - **If deltaTime = 0 (game paused)**: All Wave Manager timers pause (InterWaveDelay, SpawnDelay). No spawning occurs. No state transitions. - **If a wave has 0 enemies (all SpawnGroups have Count=0)**: Wave immediately completes (aliveCount=0, all groups "spawned"). Transition directly to InterWave. Logged as a warning — likely a data error. - **If a wave has only one SpawnGroup**: SpawnDelay is irrelevant — all enemies spawn simultaneously at wave start. No timer needed between groups. - **If `OnEnemyDied` fires for an enemy not spawned by this wave**: Ignore the event. Wave Manager maintains a set of tracked enemy IDs. Unknown IDs are silently skipped. - **If arenaRadius <= 0 (invalid LevelData)**: Log error. Use fallback radius = 20.0. Spawning continues with fallback. - **If LevelData has an empty Waves list**: Log error, emit `OnLevelComplete` immediately. No enemies, no gameplay — treat as degenerate level. - **If `InterWaveDelay = 0`**: Wave advancement is instant — no breather between waves. Valid but not recommended for MVP. Minimum enforced by design: 5s (clamped at runtime). - **If `PreWaveDelay + SpawnDelay` exceeds practical limit (>30s)**: Log warning. Enemies not spawning for too long creates dead air. Designer should review timing. - **If spawned position would place enemy inside arena geometry (e.g., pillar)**: MVP does not handle this — arenas are assumed to be clear circles. Enemy collision with geometry deferred to vertical slice. - **If `OnLevelComplete` fires but game state is already transitioning**: Guard with `_levelCompleteFired` flag. Emit event exactly once. Duplicate calls are ignored. ## Dependencies | System | Layer | Type | Hard/Soft | Interface | |--------|-------|------|-----------|-----------| | **Enemy AI Logic** | L0 | Upstream/Downstream | Hard | Downstream: calls `SpawnEnemy(typeConfig, position, facingAngle)` to create enemies. Upstream: subscribes to `OnEnemyDied(enemyId, enemyType, killerForm)` to track alive count. Cannot function without Enemy AI. | | **Level Loader (L1)** | L1 | Upstream | Hard | Provides `LevelData` (wave list, arena params, InterWaveDelay) on level start. Without it, Wave Manager has nothing to manage. | | **UI/HUD (L2)** | L2 | Downstream | Soft | Emits `OnWaveChanged`, `OnInterWaveStarted` for HUD display. Gameplay works without HUD. | | **VFX Spawner (L1)** | L1 | Downstream | Soft | Emits `OnWaveStarted`, `OnWaveCleared`, `OnEnemySpawned` for visual feedback. | | **Audio Player (L1)** | L1 | Downstream | Soft | Emits `OnWaveStarted`, `OnInterWaveStarted` for audio cues. | | **Score Calculator** | L0 | Downstream | Soft | Emits `OnWaveCleared` with wave index and clear time for scoring. | | **Death/Respawn Rules** | L0 | Upstream | Soft | Receives `OnPlayerDied` to freeze/reset wave state. Soft because wave system could function without death handling (just loses state on death). | **Hard dependencies** (system cannot function without): Enemy AI Logic, Level Loader. **Soft dependencies** (enhanced by but works without): UI/HUD, VFX Spawner, Audio Player, Score Calculator, Death/Respawn Rules. ## Tuning Knobs | Parameter | Default | Safe Range | Too Low | Too High | |-----------|---------|------------|---------|----------| | `InterWaveDelay` | 15s | 8–25s | No time to reassess — waves blur together | Dead air — player gets bored waiting | | `ArenaRadius` | 30.0 | 20–40 | Enemies spawn on top of player — no reaction time | Enemies take too long to reach player — no pressure | | `PreWaveDelay` (per wave) | 0s | 0–3s | — | Delays wave start, creates dead air before fights | | `SpawnDelay` (between groups) | 2s | 0.5–5s | All enemies arrive simultaneously — no staggered pressure | Groups arrive so far apart wave loses cohesion | | **Swarm count per wave** | 8–12 | 4–20 | Not enough to justify AOE form switch | Frame rate and readability suffer | | **Brute count per wave** | 1–3 | 1–5 | Brute not threatening — can be ignored | Multiple simultaneous heavy attacks unreadable | | **Stalker count per wave** | 2–3 | 1–5 | Stalker not creating urgency | Stalker rush overlaps unreactable | | **Total enemies per wave** | 8–16 | 4–30 | Wave feels empty — no density | 200+ total active enemies — performance risk | **Key tuning groups**: - **Pacing rhythm**: `InterWaveDelay` + `PreWaveDelay` + `SpawnDelay` — the sum of delays determines the feel of "combat density vs breathing room" - **Form pressure balance**: Swarm count vs Brute count vs Stalker count per wave — if any type dominates, the wave only tests one form - **Performance ceiling**: Total enemies alive simultaneously — Combat Logic budget is 200 enemies at <1ms. Total active across all waves must stay under this limit. At default counts (Wave 7: 16 total), performance is not a concern. Future tuning should profile before increasing. ## Visual/Audio Requirements Combat is a visual system category — Visual/Audio is REQUIRED. | Event | VFX | Audio | |-------|-----|-------| | `OnWaveStarted` | Arena perimeter pulse — brief geometric ring flash at spawn boundary. Color: white → fade. | Rising tone / alarm — pitch increases with wave number | | `OnWaveCleared` | Brief screen flash + all remaining enemy fragments dissolve simultaneously | Bass drop + short silence before InterWave heartbeat | | `OnEnemySpawned` | Small geometric "materialize" effect at spawn point — shape matches enemy type | Subtle whoosh — pitch varies by enemy size | | `OnInterWaveStarted` | Screen edges dim slightly (vignette increase) — signals "safe moment" | Heartbeat / breathing SFX — tempo slows as InterWaveDelay nears end | | `OnLevelComplete` | Full screen geometric pattern (like shattered glass reforming) — gold/white | Victory fanfare — short, geometric, not orchestral | ## UI Requirements | Element | Content | Trigger | |---------|---------|---------| | Wave Banner | "Wave [N]: [WaveName]" — appears at wave start, fades after 2s | `OnWaveChanged` | | InterWave Countdown | "[N]s until next wave" — centered, subtle | `OnInterWaveStarted(duration)` | | Enemy Remaining Counter | "[N] enemies remaining" — small HUD element | Alive count update each time `OnEnemyDied` fires | | Wave Clear Text | "Cleared!" — brief centered text | `OnWaveCleared` | ## Acceptance Criteria | # | GIVEN | WHEN | THEN | |---|-------|------|------| | 1 | LevelData with 7 waves loaded. Wave 1 has 8× Swarm (Perimeter). InterWaveDelay=15s. | Level starts | Wave 1 spawns 8 Swarm at arena perimeter. OnWaveChanged fires with waveIndex=0. | | 2 | Wave 1 active. 8 enemies alive. | Enemy AI emits OnEnemyDied for one Swarm | aliveCount=7. Wave remains active. | | 3 | Wave 1 active. 8 enemies alive. All 8 OnEnemyDied events fire. | Last enemy dies | Wave clears. OnWaveCleared fires. Transition to InterWave. InterWaveDelay timer starts. | | 4 | InterWave state. 15s elapsed. Next wave exists (Wave 2). | Timer expires | Transition to WaveActive. Wave 2 begins spawning. OnWaveChanged fires with waveIndex=1. | | 5 | Wave 7 (IsFinalWave=true) active. All enemies dead. | Last enemy dies | OnWaveCleared fires. OnLevelComplete fires. No InterWave transition. | | 6 | Wave with 2 SpawnGroups: Group1(Delay=0s), Group2(Delay=3s). Wave starts. | Wave becomes active | Group1 spawns immediately. 3s later, Group2 spawns. Both before any died events. | | 7 | SpawnPattern=Clustered, baseAngle=90°. Count=4. ArenaRadius=30. ArenaCenter=(0,0,0). | Spawn executed | 4 enemies spawned within 60° arc centered on 90° (±30°). All at distance 30 from center. | | 8 | deltaTime=0.0. InterWave state with 10s remaining on timer. | Update called | Timer does not advance. Still 10s remaining. | | 9 | Player dies during WaveActive (Wave 3). Death/Respawn emits OnPlayerRespawned. | OnPlayerRespawned received | Wave 3 resets: all enemies despawned, wave restarts from InterWave → re-spawn all Wave 3 enemies. | | 10 | OnEnemyDied fires for enemy ID not in tracked set (not spawned by this wave). | Event received | Ignored. aliveCount unchanged. | | 11 | LevelData.Waves is empty list. | Level starts | Log error. OnLevelComplete fires immediately. | | 12 | Wave 3 "Heavy": 2× Brute (Clustered, SpawnDelay=2s between them). | Wave becomes active | First Brute spawns at 0s. Second Brute spawns at 2s. Two separate spawn events. | ## Open Questions - Player death wave reset: Should the player restart the entire level, the current wave, or from a checkpoint (e.g., every 3 waves)? Defer to Death/Respawn Rules GDD. - Wave difficulty scaling: Should enemy stats increase per wave (health/damage scaling) or is composition change alone sufficient for difficulty? MVP assumes composition-only scaling. - Boss wave integration: How does Boss AI Logic GDD's boss encounter integrate into the wave system? Is the boss a special "Wave 8" or a separate encounter after Wave 7? - Wave order randomization: Should the 7-wave structure be fixed (same every playthrough) or allow designer to tag waves as "random pool" for replayability? MVP uses fixed order. - Spawn visual transition: Should enemies "phase in" with a brief materialize animation, or pop into existence? Enemy AI GDD says Idle state has no wake-up animation — spawning FX is a Wave Manager concern.