---
id: wiki-2026-0508-staggered-firing-logic-and-phase
title: Staggered Firing Logic and Phase Offset
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Phase Offset Firing, Staggered Volley, Spread Salvo]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [game-design, combat, simulation, weapons]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
  language: typescript
  framework: ecs
---

# Staggered Firing Logic and Phase Offset

## 매 한 줄
> **"매 weapon battery 의 fire timing 의 distribute 의 anti-burst pattern"**. 매 multi-barrel platform 의 simultaneous discharge 의 회피 — 매 DPS smoothing, FPS spike 의 prevention, AOE counter 의 mitigation. 매 War Commander, EVE Online, Mechabellum 의 핵심 timing primitive.

## 매 핵심

### 매 문제
- **Synchronized salvo**: 매 N barrels 의 simultaneous fire — 매 frame spike + AOE 1-shot vulnerability.
- **Wasted DPS**: 매 target dead 의 mid-volley — overkill 의 absorb.
- **AI predictability**: 매 player 의 dodge timing 의 학습 가능.

### 매 phase offset 의 mechanism
- **Period T**: 매 weapon 의 cooldown.
- **Offset φᵢ**: barrel i 의 initial delay = (i / N) * T.
- **Result**: 매 N evenly-spaced shots per period — 매 smooth DPS curve.

### 매 응용
1. Capital ship turret battery — 매 broadside 의 sustained fire.
2. Tower defense 의 multi-tower volley.
3. Auto-attack RPG 의 multi-projectile spread.

## 💻 패턴

### Phase-offset scheduler
```typescript
interface Barrel {
  id: number;
  cooldownMs: number;
  nextFireAt: number;
}

export function initBattery(count: number, period: number, now: number): Barrel[] {
  return Array.from({ length: count }, (_, i) => ({
    id: i,
    cooldownMs: period,
    nextFireAt: now + (i / count) * period,
  }));
}

export function tickBattery(battery: Barrel[], now: number, fire: (b: Barrel) => void) {
  for (const b of battery) {
    if (now >= b.nextFireAt) {
      fire(b);
      b.nextFireAt += b.cooldownMs;
    }
  }
}
```

### ECS system (bitECS-style)
```typescript
import { defineQuery, defineSystem } from 'bitecs';
import { Weapon, Position, Target } from './components';

const weaponQuery = defineQuery([Weapon, Position, Target]);

export const firingSystem = defineSystem((world: any) => {
  const ents = weaponQuery(world);
  const now = world.time.now;
  for (const eid of ents) {
    if (now >= Weapon.nextFireAt[eid]) {
      spawnProjectile(world, eid);
      Weapon.nextFireAt[eid] = now + Weapon.cooldown[eid];
    }
  }
  return world;
});
```

### Adaptive jitter (anti-prediction)
```typescript
export function jitteredOffset(base: number, jitterPct = 0.1): number {
  const jitter = (Math.random() * 2 - 1) * jitterPct * base;
  return base + jitter;
}

export function rescheduleWithJitter(b: Barrel, now: number) {
  b.nextFireAt = now + jitteredOffset(b.cooldownMs);
}
```

### Target switch on phase
```typescript
export function selectTarget(barrel: Barrel, candidates: Entity[]): Entity | null {
  // 매 phase-offset barrel 의 priority swap — 매 focused fire 의 회피
  const phaseIdx = barrel.id % candidates.length;
  return candidates.sort((a, b) => a.hp - b.hp)[phaseIdx] ?? null;
}
```

### DPS smoothing 검증
```typescript
export function dpsHistogram(events: {t: number; dmg: number}[], binMs = 100) {
  const bins = new Map<number, number>();
  for (const e of events) {
    const k = Math.floor(e.t / binMs);
    bins.set(k, (bins.get(k) ?? 0) + e.dmg);
  }
  const values = [...bins.values()];
  const mean = values.reduce((a,b)=>a+b,0)/values.length;
  const variance = values.reduce((a,b)=>a+(b-mean)**2,0)/values.length;
  return { mean, stddev: Math.sqrt(variance), peak: Math.max(...values) };
}
```

### Group-level phase coordination
```typescript
export function coordinateGroup(barrels: Barrel[], period: number, now: number) {
  // 매 N barrels 의 even spread + small group jitter
  const groupJitter = Math.random() * 0.05 * period;
  barrels.forEach((b, i) => {
    b.cooldownMs = period;
    b.nextFireAt = now + (i / barrels.length) * period + groupJitter;
  });
}
```

## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 capital ship turret | Even phase offset + small jitter (5%). |
| 매 missile salvo | Single-shot batch (volley) — narrative impact. |
| 매 anti-AOE need | Maximum stagger — 매 wide phase distribution. |
| 매 boss fight 의 telegraph | Synchronized fire — readable pattern. |

**기본값**: Even phase offset (i/N * T) + 5-10% jitter.

## 🔗 Graph
- 부모: [[Anti-Air-and-Anti-Ground-Combat]] · [[War-Commander-Combat-Ecosystem]]
- 변형: [[State-Machine-and-Phase-Transition-Events]] · [[Defense-Buildings]]
- 응용: [[Assault-Platoons]] · [[Damage-Resistance-Platforms]]
- Adjacent: [[Fixed Time Step vs Variable Time Step]] · [[Physics]]

## 🤖 LLM 활용
**언제**: barrel timing 의 review prompt, AI behavior 의 design 의 brainstorm.
**언제 X**: tight inner loop scheduling (deterministic ECS).

## ❌ 안티패턴
- **All barrels same time**: 매 burst spike + AOE 1-shot.
- **Random offset only**: 매 worst-case stack — no smoothness guarantee.
- **No jitter**: 매 player 의 perfect dodge timing 의 학습.

## 🧪 검증 / 중복
- Verified: War Commander combat patches, EVE turret cycle docs, Mechabellum balance posts.
- 신뢰도 A.

## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — phase offset scheduler + ECS pattern 추가 |
