# 機能設計書: パーティクルシステム

## 1. 機能概要

### 1.1 機能の目的

パーティクルシステムは、Godot Engineにおける粒子効果の生成と管理を提供する。2D/3Dの両方で、CPUベースとGPUベースのパーティクルエミッターをサポートする。煙、火、爆発、雪、魔法効果などの視覚エフェクトを効率的に描画するための機能を提供する。

### 1.2 主要な責務

| 責務 | 説明 |
|------|------|
| パーティクル生成 | 設定に基づいたパーティクルの生成と初期化 |
| パーティクル更新 | 位置、速度、色、サイズの時間経過による更新 |
| 描画管理 | MultiMeshを使用した効率的な描画 |
| パラメータ制御 | 速度、加速度、角度、スケールなどのパラメータ |
| エミッション形状 | 点、球、矩形、リングなどの発生形状 |
| ライフタイム管理 | パーティクルの寿命と再利用 |

### 1.3 アーキテクチャ上の位置づけ

```
+------------------+
|   Game Scripts   |
+------------------+
         |
         v
+------------------+     +------------------+
| CPUParticles2D   |     | GPUParticles2D   |
| CPUParticles3D   |     | GPUParticles3D   |
+------------------+     +------------------+
         |                       |
         v                       v
+------------------+     +------------------+
|   CPU計算        |     | ParticleProcess  |
| (Particle構造体) |     | Material (Shader)|
+------------------+     +------------------+
         |                       |
         v                       v
+------------------+
|   MultiMesh      |
+------------------+
         |
         v
+------------------+
| RenderingServer  |
+------------------+
```

## 2. クラス構造

### 2.1 CPUParticles2Dクラス

```cpp
// scene/2d/cpu_particles_2d.h 38-198行目
class CPUParticles2D : public Node2D {
    GDCLASS(CPUParticles2D, Node2D);

    // 状態管理
    bool emitting = false;
    bool active = false;
    double time = 0.0;
    int cycle = 0;

    // レンダリング用リソース
    RID mesh;
    RID multimesh;

    // パーティクルデータ
    Vector<Particle> particles;
    Vector<float> particle_data;
    Vector<int> particle_order;

    // 基本設定
    bool one_shot = false;
    double lifetime = 1.0;
    real_t explosiveness_ratio = 0.0;
    real_t randomness_ratio = 0.0;
    bool local_coords = false;

    // 動き設定
    Vector2 direction = Vector2(1, 0);
    real_t spread = 45.0;
    Vector2 gravity = Vector2(0, 980);

    // パラメータ
    real_t parameters_min[PARAM_MAX];
    real_t parameters_max[PARAM_MAX];
    Ref<Curve> curve_parameters[PARAM_MAX];

    // 色設定
    Color color;
    Ref<Gradient> color_ramp;
    Ref<Gradient> color_initial_ramp;

    // エミッション形状
    EmissionShape emission_shape = EMISSION_SHAPE_POINT;
    real_t emission_sphere_radius = 1.0;
    Vector2 emission_rect_extents = Vector2(1, 1);
};
```

### 2.2 Particle構造体

```cpp
// scene/2d/cpu_particles_2d.h 86-103行目
struct Particle {
    Transform2D transform;
    Color color;
    real_t custom[4] = {};
    real_t rotation = 0.0;
    Vector2 velocity;
    bool active = false;
    real_t angle_rand = 0.0;
    real_t scale_rand = 0.0;
    real_t hue_rot_rand = 0.0;
    real_t anim_offset_rand = 0.0;
    Color start_color_rand;
    double time = 0.0;
    double lifetime = 0.0;
    Color base_color;
    uint32_t seed = 0;
};
```

### 2.3 列挙型定義

```cpp
// scene/2d/cpu_particles_2d.h 43-80行目
enum DrawOrder {
    DRAW_ORDER_INDEX,     // インデックス順
    DRAW_ORDER_LIFETIME,  // ライフタイム順
};

enum Parameter {
    PARAM_INITIAL_LINEAR_VELOCITY,  // 初期線形速度
    PARAM_ANGULAR_VELOCITY,         // 角速度
    PARAM_ORBIT_VELOCITY,           // 軌道速度
    PARAM_LINEAR_ACCEL,             // 線形加速度
    PARAM_RADIAL_ACCEL,             // 放射状加速度
    PARAM_TANGENTIAL_ACCEL,         // 接線加速度
    PARAM_DAMPING,                  // ダンピング
    PARAM_ANGLE,                    // 角度
    PARAM_SCALE,                    // スケール
    PARAM_HUE_VARIATION,            // 色相変化
    PARAM_ANIM_SPEED,               // アニメ速度
    PARAM_ANIM_OFFSET,              // アニメオフセット
    PARAM_MAX
};

enum EmissionShape {
    EMISSION_SHAPE_POINT,           // 点
    EMISSION_SHAPE_SPHERE,          // 球
    EMISSION_SHAPE_SPHERE_SURFACE,  // 球表面
    EMISSION_SHAPE_RECTANGLE,       // 矩形
    EMISSION_SHAPE_POINTS,          // 点群
    EMISSION_SHAPE_DIRECTED_POINTS, // 方向付き点群
    EMISSION_SHAPE_RING,            // リング
    EMISSION_SHAPE_MAX,
};
```

## 3. 処理フロー

### 3.1 エミッション開始フロー

```
[set_emitting(true)]
        |
        v
+------------------+
| one_shot & !fixed|  --> set_seed(rand)
| の場合シード設定 |
+------------------+
        |
        v
+------------------+
| emitting = true  |
| _set_emitting()  |
+------------------+
        |
        v
+------------------+
| active = true    |
| set_process_     |
| internal(true)   |
+------------------+
        |
        v
+------------------+
| time == 0なら    |  --> _update_internal()
| 即座に更新       |
+------------------+
```

### 3.2 パーティクル更新フロー

```
[_update_internal()]
        |
        v
+------------------+
| delta計算        |
| (fixed_fps対応)  |
+------------------+
        |
        v
+------------------+
| _particles_      |  <-- パーティクル更新
| process(delta)   |
+------------------+
        |
        v
+------------------+
| _update_particle |  <-- バッファ更新
| _data_buffer()   |
+------------------+
        |
        v
+------------------+
| _update_render   |  <-- MultiMesh更新
| _thread()        |
+------------------+
```

### 3.3 パーティクル処理フロー

```
[_particles_process(delta)]
        |
        v
+------------------+
| 各パーティクルに |
| ついてループ     |
+------------------+
        |
        v
+------------------+
| 非アクティブなら |  --> 新規生成
| 生成判定         |
+------------------+
        |
        v
+------------------+
| velocity更新     |
| (加速度、重力)   |
+------------------+
        |
        v
+------------------+
| position更新     |
| (velocity * dt)  |
+------------------+
        |
        v
+------------------+
| color/scale更新  |
| (カーブ評価)     |
+------------------+
        |
        v
+------------------+
| 寿命チェック     |
| active = false   |
+------------------+
```

## 4. 主要メソッド詳細

### 4.1 set_amount（パーティクル数設定）

```cpp
// scene/2d/cpu_particles_2d.cpp 67-83行目
void CPUParticles2D::set_amount(int p_amount) {
    ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles must be greater than 0.");

    particles.resize(p_amount);
    {
        Particle *w = particles.ptrw();
        for (int i = 0; i < p_amount; i++) {
            w[i].active = false;
        }
    }

    // MultiMesh用データ: 8(transform) + 4(color) + 4(custom) = 16 floats
    particle_data.resize((8 + 4 + 4) * p_amount);
    RS::get_singleton()->multimesh_allocate_data(multimesh, p_amount, RS::MULTIMESH_TRANSFORM_2D, true, true);

    particle_order.resize(p_amount);
}
```

### 4.2 set_emitting（エミッション開始）

```cpp
// scene/2d/cpu_particles_2d.cpp 43-56行目
void CPUParticles2D::set_emitting(bool p_emitting) {
    if (emitting == p_emitting) {
        return;
    }

    if (p_emitting && !use_fixed_seed && one_shot) {
        set_seed(Math::rand());
    }

    emitting = p_emitting;
    if (emitting) {
        _set_emitting();
    }
}

void CPUParticles2D::_set_emitting() {
    active = true;
    set_process_internal(true);
    // 最初のフレームで1フレーム遅延を防ぐ
    if (time == 0) {
        _update_internal();
    }
}
```

### 4.3 set_param_min/max（パラメータ設定）

```cpp
// scene/2d/cpu_particles_2d.cpp 352-382行目
void CPUParticles2D::set_param_min(Parameter p_param, real_t p_value) {
    ERR_FAIL_INDEX(p_param, PARAM_MAX);

    parameters_min[p_param] = p_value;
    if (parameters_min[p_param] > parameters_max[p_param]) {
        set_param_max(p_param, p_value);
    }
}

void CPUParticles2D::set_param_max(Parameter p_param, real_t p_value) {
    ERR_FAIL_INDEX(p_param, PARAM_MAX);

    parameters_max[p_param] = p_value;
    if (parameters_min[p_param] > parameters_max[p_param]) {
        set_param_min(p_param, p_value);
    }

    update_configuration_warnings();
}
```

### 4.4 set_param_curve（カーブパラメータ設定）

```cpp
// scene/2d/cpu_particles_2d.cpp 393-421行目
void CPUParticles2D::set_param_curve(Parameter p_param, const Ref<Curve> &p_curve) {
    ERR_FAIL_INDEX(p_param, PARAM_MAX);

    curve_parameters[p_param] = p_curve;

    switch (p_param) {
        case PARAM_ANGULAR_VELOCITY:
        case PARAM_ORBIT_VELOCITY:
        case PARAM_LINEAR_ACCEL:
        case PARAM_RADIAL_ACCEL:
        case PARAM_TANGENTIAL_ACCEL:
        case PARAM_ANGLE:
        case PARAM_HUE_VARIATION:
            _adjust_curve_range(p_curve, -1, 1);
            break;
        case PARAM_DAMPING:
        case PARAM_SCALE:
        case PARAM_ANIM_SPEED:
        case PARAM_ANIM_OFFSET:
            _adjust_curve_range(p_curve, 0, 1);
            break;
    }

    update_configuration_warnings();
}
```

### 4.5 set_emission_shape（エミッション形状設定）

```cpp
// scene/2d/cpu_particles_2d.cpp 463-472行目
void CPUParticles2D::set_emission_shape(EmissionShape p_shape) {
    ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX);
    emission_shape = p_shape;
    notify_property_list_changed();
#ifdef TOOLS_ENABLED
    if (Engine::get_singleton()->is_editor_hint()) {
        queue_redraw();
    }
#endif
}
```

### 4.6 restart（再起動）

```cpp
// scene/2d/cpu_particles_2d.cpp 314-334行目
void CPUParticles2D::restart(bool p_keep_seed) {
    time = 0;
    frame_remainder = 0;
    cycle = 0;
    emitting = false;

    {
        int pc = particles.size();
        Particle *w = particles.ptrw();

        for (int i = 0; i < pc; i++) {
            w[i].active = false;
        }
    }
    if (!p_keep_seed && !use_fixed_seed) {
        seed = Math::rand();
    }

    emitting = true;
    _set_emitting();
}
```

## 5. MultiMesh連携

### 5.1 メッシュテクスチャ更新

```cpp
// scene/2d/cpu_particles_2d.cpp 181-230行目
void CPUParticles2D::_update_mesh_texture() {
    Size2 tex_size;
    if (texture.is_valid()) {
        tex_size = texture->get_size();
    } else {
        tex_size = Size2(1, 1);
    }

    // 4頂点のクワッドを生成
    Vector<Vector2> vertices = {
        -tex_size * 0.5,
        -tex_size * 0.5 + Vector2(tex_size.x, 0),
        -tex_size * 0.5 + tex_size,
        -tex_size * 0.5 + Vector2(0, tex_size.y)
    };

    // UV座標（AtlasTextureに対応）
    Vector<Vector2> uvs;
    // ...

    // メッシュを構築
    Array arr;
    arr.resize(RS::ARRAY_MAX);
    arr[RS::ARRAY_VERTEX] = vertices;
    arr[RS::ARRAY_TEX_UV] = uvs;
    arr[RS::ARRAY_COLOR] = colors;
    arr[RS::ARRAY_INDEX] = indices;

    RS::get_singleton()->mesh_clear(mesh);
    RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr);
}
```

## 6. 補間データ

```cpp
// scene/2d/cpu_particles_2d.h 191-198行目
struct InterpolationData {
    // グローバル座標モードで補間された親を追従
    bool interpolated_follow = false;

    // 補間フォロー時に毎ティック更新
    Transform2D global_xform_curr;
    Transform2D global_xform_prev;
} _interpolation_data;
```

## 7. コードリーディングガイド

### 7.1 推奨読解順序

1. **クラス構造** (cpu_particles_2d.h 38-198行目)
   - Particle構造体とメンバ変数

2. **set_amount()** (cpu_particles_2d.cpp 67-83行目)
   - パーティクル配列とMultiMeshの初期化

3. **set_emitting()/_set_emitting()** (cpu_particles_2d.cpp 43-65行目)
   - エミッション開始のフロー

4. **パラメータ設定** (cpu_particles_2d.cpp 352-427行目)
   - min/max/curveパラメータ

5. **エミッション形状** (cpu_particles_2d.cpp 463-500行目)
   - 発生形状の設定

### 7.2 読解のコツ

- `particles`配列は全パーティクルを保持（プール方式）
- `active`フラグで有効/無効を管理
- `particle_data`はMultiMesh用のフラット配列
- `explosiveness_ratio`は一度に生成するパーティクル数を制御
- `local_coords`はワールド座標/ローカル座標の切り替え

### 7.3 プログラム呼び出し階層図

```
CPUParticles2D::set_emitting(true)
    |
    +---> emitting = true
    |
    +---> _set_emitting()
              |
              +---> active = true
              |
              +---> set_process_internal(true)
              |
              +---> _update_internal() [time == 0]
                        |
                        +---> _particles_process(delta)
                        |         |
                        |         +---> 各Particleを更新
                        |         |
                        |         +---> velocity/position計算
                        |         |
                        |         +---> color/scale計算
                        |
                        +---> _update_particle_data_buffer()
                        |
                        +---> _update_render_thread()
                                  |
                                  +---> RS::multimesh_set_buffer()
```

### 7.4 データフロー図

```
+----------------+     set_amount()      +----------------+
|   GDScript     |---------------------->|CPUParticles2D  |
+----------------+                       +----------------+
                                               |
                                               v
                                        particles.resize()
                                               |
                                               v
+----------------+     multimesh_allocate   +----------------+
|RenderingServer |<-------------------------|    MultiMesh   |
|                |     _data()              |                |
+----------------+                          +----------------+
        |
        v
+----------------+
|     GPU        |
+----------------+
```

### 7.5 関連ファイル一覧

| ファイル | 役割 |
|----------|------|
| `scene/2d/cpu_particles_2d.h/cpp` | CPUParticles2D |
| `scene/2d/gpu_particles_2d.h/cpp` | GPUParticles2D |
| `scene/3d/cpu_particles_3d.h/cpp` | CPUParticles3D |
| `scene/3d/gpu_particles_3d.h/cpp` | GPUParticles3D |
| `scene/resources/particle_process_material.h` | GPU用シェーダーマテリアル |
| `servers/rendering/rendering_server.h` | MultiMesh API |

## 8. CPU vs GPU パーティクル

| 項目 | CPUParticles | GPUParticles |
|------|--------------|--------------|
| 計算場所 | CPU | GPU (Compute Shader) |
| パーティクル数 | 〜数千 | 〜数百万 |
| 柔軟性 | 高い（C++で直接制御） | 中（Shaderで制御） |
| コリジョン | 可能 | 限定的 |
| 互換性 | 高い | GPUコンピュート必須 |

## 9. 使用例

### 9.1 基本的なパーティクル設定

```gdscript
extends CPUParticles2D

func _ready():
    # 基本設定
    amount = 100
    lifetime = 2.0
    emitting = true

    # 方向と広がり
    direction = Vector2.UP
    spread = 45.0

    # 初期速度
    initial_velocity_min = 100.0
    initial_velocity_max = 200.0

    # 重力
    gravity = Vector2(0, 98)
```

### 9.2 色のグラデーション

```gdscript
extends CPUParticles2D

func _ready():
    # カラーランプ設定
    var gradient = Gradient.new()
    gradient.add_point(0.0, Color.WHITE)
    gradient.add_point(0.5, Color.YELLOW)
    gradient.add_point(1.0, Color(1, 0, 0, 0))  # 透明な赤
    color_ramp = gradient
```

### 9.3 エミッション形状

```gdscript
extends CPUParticles2D

func _ready():
    # リング形状のエミッション
    emission_shape = EMISSION_SHAPE_RING
    emission_ring_radius = 50.0
    emission_ring_inner_radius = 40.0
```
