ブログ一覧に戻る
Game Development
Unity DOTSで音楽リアクティブ弾幕シューティングを作る
2025-11-26
20 min
UnityDOTSECSWASAPIGame DevelopmentC#
プロジェクト概要
HARMONIC BARRAGEは、Space Invaders Infinity GeneとBeat Saberにインスパイアされた、 音楽連動型弾幕シューティングゲームです。システム音声(Spotify、YouTube等)をリアルタイムキャプチャし、 FFT解析で音楽を「視覚化」して弾幕パターンを生成します。
主要スペック
- 弾幕パターン: 32種類(完全実装済み)
- パフォーマンス: 100,000弾 @ 144fps
- 技術スタック: Unity 6 + DOTS + WASAPI + NAudio
- 実装コード: 11,303行(Phase 1-3完了)
1. Unity DOTS アーキテクチャ
なぜDOTSなのか?
従来のGameObject/MonoBehaviourでは、10万弾の同時処理は不可能です。 DOTSはデータ指向設計により、CPUキャッシュを最大限活用し、 Burst Compilerで高速化、Job Systemで並列処理を実現します。
ECS コンポーネント設計
弾幕システムを構成する主要コンポーネント:
using Unity.Entities;
using Unity.Mathematics;
// 弾のコンポーネント
public struct BulletComponent : IComponentData
{
public float3 Velocity;
public float Speed;
public float Size;
public float4 Color;
public BulletPatternType PatternType;
}
// パターン固有のデータ
public struct SpiralPatternData : IComponentData
{
public float AngularVelocity; // 回転速度
public float RadialVelocity; // 半径方向速度
public float CurrentAngle; // 現在の角度
}System 実装例: スパイラルパターン
[BurstCompile]
public partial struct SpiralBulletSystem : ISystem
{
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
var deltaTime = SystemAPI.Time.DeltaTime;
foreach (var (transform, bullet, spiral) in
SystemAPI.Query<
RefRW<LocalTransform>,
RefRO<BulletComponent>,
RefRW<SpiralPatternData>>())
{
// 角度更新
spiral.ValueRW.CurrentAngle +=
spiral.ValueRO.AngularVelocity * deltaTime;
// スパイラル軌道計算
float radius = spiral.ValueRO.RadialVelocity * deltaTime;
float angle = spiral.ValueRO.CurrentAngle;
float3 spiralOffset = new float3(
math.cos(angle) * radius,
math.sin(angle) * radius,
0
);
transform.ValueRW.Position += spiralOffset;
}
}
}2. WASAPI 音楽キャプチャ
システム音声のリアルタイムキャプチャ
WASAPIループバックモードで、システム全体の音声を取得します。 これにより、Spotify、YouTube、Apple Music等、あらゆる音源に対応できます。
using NAudio.Wave;
using NAudio.Dsp;
public class WASAPIAudioCapture : MonoBehaviour
{
private WasapiLoopbackCapture capture;
private BufferedWaveProvider waveProvider;
private Complex[] fftBuffer;
void Start()
{
// ループバックキャプチャ開始
capture = new WasapiLoopbackCapture();
waveProvider = new BufferedWaveProvider(capture.WaveFormat);
capture.DataAvailable += OnDataAvailable;
capture.StartRecording();
// FFTバッファ初期化(512サンプル)
fftBuffer = new Complex[512];
}
private void OnDataAvailable(object sender,
WaveInEventArgs e)
{
waveProvider.AddSamples(e.Buffer, 0, e.BytesRecorded);
// FFT解析実行
PerformFFT(e.Buffer, e.BytesRecorded);
}
private void PerformFFT(byte[] buffer, int bytesRecorded)
{
// バイト配列をfloat配列に変換
float[] samples = ConvertToFloat(buffer, bytesRecorded);
// FFT実行
for (int i = 0; i < fftBuffer.Length; i++)
{
fftBuffer[i].X = (i < samples.Length)
? samples[i] : 0;
fftBuffer[i].Y = 0;
}
FastFourierTransform.FFT(true,
(int)Math.Log(fftBuffer.Length, 2),
fftBuffer);
// 周波数帯域ごとの強度を計算
AnalyzeFrequencyBands(fftBuffer);
}
}周波数帯域解析
FFT結果から、Bass・Mid・Trebleの3帯域を抽出し、弾幕パターンにマッピングします。
private void AnalyzeFrequencyBands(Complex[] fftData)
{
// 周波数帯域定義
const int bassEnd = 20; // 20-250Hz
const int midEnd = 160; // 250-4000Hz
const int trebleEnd = 512; // 4000-20000Hz
float bass = 0, mid = 0, treble = 0;
for (int i = 0; i < bassEnd; i++)
bass += fftData[i].Magnitude;
for (int i = bassEnd; i < midEnd; i++)
mid += fftData[i].Magnitude;
for (int i = midEnd; i < trebleEnd; i++)
treble += fftData[i].Magnitude;
// 正規化
bass /= bassEnd;
mid /= (midEnd - bassEnd);
treble /= (trebleEnd - midEnd);
// DOTSブリッジに送信
AudioBridge.Instance.UpdateMusicData(
new MusicData
{
BassIntensity = bass,
MidIntensity = mid,
TrebleIntensity = treble,
BeatDetected = DetectBeat(bass)
}
);
}3. 音楽→弾幕マッピング
周波数帯域と弾幕パラメータの対応
| 周波数帯域 | 影響範囲 | 効果 |
|---|---|---|
| Bass (20-250Hz) | 弾サイズ、スポーン数 | 重低音 = 大きく遅い弾 |
| Mid (250-4000Hz) | パターン密度、回転速度 | 中音 = 複雑な動き |
| Treble (4000-20000Hz) | 弾速度、レーザー頻度 | 高音 = 速く小さい弾 |
実装例: 音楽データから弾幕生成
[BurstCompile]
public partial struct MusicReactiveSpawnerSystem : ISystem
{
public void OnUpdate(ref SystemState state)
{
var musicData = AudioBridge.Instance.GetMusicData();
// Bass強度に応じて弾サイズを調整
float bulletSize = 0.5f + musicData.BassIntensity * 1.5f;
// Mid強度に応じてスパイラル回転速度を調整
float angularVelocity =
2.0f + musicData.MidIntensity * 8.0f;
// Treble強度に応じて弾速度を調整
float bulletSpeed =
5.0f + musicData.TrebleIntensity * 15.0f;
// ビート検出時に弾を生成
if (musicData.BeatDetected)
{
SpawnBulletPattern(
PatternType.Spiral,
bulletSize,
bulletSpeed,
angularVelocity
);
}
}
}4. 32種類の弾幕パターン
パターン分類
実装した32パターンを5つのカテゴリに分類:
1. 基本パターン(4種)
- Linear: 直線発射
- Radial: 放射状
- Fan: 扇型
- Aimed: プレイヤー狙い
2. 幾何学パターン(5種)
- Spiral: スパイラル
- Vortex: 渦巻き
- Wave: 波動
- Elliptical: 楕円軌道
- Polygon: 多角形
3. 動的パターン(5種)
- Homing: 追尾弾
- Accelerating: 加速弾
- Decelerating: 減速弾
- Reflecting: 反射弾
- Boomerang: ブーメラン
4. 複雑パターン(6種)
- Streaming: 連続発射
- Laser: レーザー
- Random: ランダム
- Staged: 段階遷移
- Splitting: 分裂弾
- Chaining: 連鎖弾
5. 拡張パターン(12種)
- Petal, Cross, Wall, Ring, Bounce, Gravity, Snake, Orbit, Butterfly, Cascade など
5. パフォーマンス最適化
目標達成状況
| 指標 | 目標値 | 達成状況 |
|---|---|---|
| フレームレート | 144 fps | ✅ 達成 |
| 同時弾数 | 100,000+ | ✅ 達成 |
| フレームタイム | 6.94ms | ✅ 達成 |
最適化手法
- Burst Compiler: SIMD命令を活用した高速化
- 通常C#の10-20倍のパフォーマンス
- [BurstCompile]属性で自動最適化
- Job System: マルチスレッド並列処理
- 弾の移動計算を全コア並列実行
- データレース防止(Read/Write分離)
- GPU Instancing: 描画コール削減
- 10万弾を1ドローコールで描画
- Entities Graphicsで自動バッチング
- Spatial Hash: 衝突判定高速化
- O(n²) → O(n) に削減
- グリッドベース空間分割
6. GameObjectとDOTSのブリッジ
ハイブリッドアーキテクチャ
WASAPI(GameObject)とDOTS(ECS)を接続するブリッジパターン:
// シングルトンブリッジ
public class AudioBridge : MonoBehaviour
{
public static AudioBridge Instance { get; private set; }
// GameObject側からセット
private MusicData currentMusicData;
// DOTS側から読み取り
public MusicData GetMusicData()
{
return currentMusicData;
}
// WASAPI側が呼び出し
public void UpdateMusicData(MusicData data)
{
currentMusicData = data;
}
}7. 技術スタック
Unity側
- Unity 6.0 LTS
- Entities 1.4.2: ECS
- Burst 1.8.18: コンパイラ
- URP 17.0.3: レンダリング
- Entities Graphics: ECS描画
音楽解析
- WASAPI: Windows Audio API
- NAudio 2.2.1: 音声処理ライブラリ
- FFT 512バンド: 周波数解析
プラットフォーム
- Windows x64: 開発・デプロイ
- Steam: 配信プラットフォーム(予定)
8. プロジェクト構成
ディレクトリ構造
UnityProject/
├── Assets/
│ ├── Scripts/
│ │ ├── Bootstrap/
│ │ │ └── GameBootstrap.cs # ECS初期化 (428行)
│ │ ├── ECS/
│ │ │ ├── Components/ # 13 ECS Components
│ │ │ └── Systems/
│ │ │ ├── BulletPatterns/ # 32パターン (2,654行)
│ │ │ └── Boss/ # 5ボス (2,506行)
│ │ ├── Audio/
│ │ │ ├── WASAPIAudioCapture.cs # WASAPI (619行)
│ │ │ └── CrossPlatformAudioBridge.cs # (345行)
│ │ └── UI/ # UI (1,711行C#)
│ ├── Editor/
│ │ └── AutoSetup/
│ │ └── GameSceneAutoSetup.cs # 自動セットアップ (546行)
│ └── Scenes/
│ └── GameScene.unity
合計実装コード: 11,303行まとめ
Unity DOTSとWASAPIを組み合わせることで、リアルタイム音楽解析から 弾幕パターンを生成する革新的なシューティングゲームを実現できます。
主要成果
- ✅ 32種類の弾幕パターン完全実装
- ✅ 100,000弾 @ 144fps達成
- ✅ システム音声のリアルタイムキャプチャ
- ✅ FFT解析による周波数帯域抽出
- ✅ 11,303行の実装コード