# 通知設計書 21-NOTIFICATION_PAUSED

## 概要

本ドキュメントは、Godot EngineのNodeクラスにおける`NOTIFICATION_PAUSED`通知の設計仕様を記載する。この通知はノードがポーズ状態になった際に発火し、ゲームの一時停止機能を実現するための重要なライフサイクル通知である。

### 本通知の処理概要

NOTIFICATION_PAUSEDは、ノードが処理可能（can_process）な状態から処理不可能な状態に遷移した際に発行されるシステム通知である。この通知を受けることで、ノードはポーズ状態に適切に対応した処理を実行できる。

**業務上の目的・背景**：ゲーム開発において、一時停止機能は必須の機能である。プレイヤーがゲームを中断したい場合や、メニュー画面を表示する際に、ゲームの進行を一時的に停止させる必要がある。NOTIFICATION_PAUSEDは、この一時停止状態への遷移をノードに通知し、各ノードがポーズ時の適切な処理（アニメーション停止、サウンドミュート、物理補間リセットなど）を実行できるようにする。

**通知の送信タイミング**：以下のイベントで送信される。
1. SceneTreeのpausedプロパティがtrueに設定された時
2. ノードのprocess_modeがPROCESS_MODE_PAUSABLEで、親ノードがポーズ状態に変化した時
3. ノードのprocess_modeが変更され、処理可能な状態から処理不可能な状態に遷移した時

**通知の受信者**：ポーズの影響を受けるすべてのNodeおよびその派生クラス。具体的には、process_modeがPROCESS_MODE_PAUSABLEまたはPROCESS_MODE_INHERITで継承元がPAUSABLEのノード。

**通知内容の概要**：通知IDは整数値14（NOTIFICATION_PAUSED = 14）。追加のパラメータは含まない。

**期待されるアクション**：
- アニメーションやタイマーの一時停止
- サウンドの一時停止またはミュート
- 物理補間状態のリセット
- UI状態の更新（ポーズ画面表示など）
- ネットワーク通信の一時停止処理

## 通知種別

エンジン内部通知（Engine Internal Notification）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 高（ライフサイクル通知） |
| リトライ | 無し |

### 送信先決定ロジック

1. ノードツリーを走査し、process_ownerを確認
2. _can_process()がtrueからfalseに変化するノードを特定
3. 該当ノードにNOTIFICATION_PAUSEDを送信
4. 子ノードに対しても再帰的に伝播（_propagate_pause_notification）

## 通知テンプレート

### システム通知の場合

| 項目 | 内容 |
|-----|------|
| 通知ID | 14 |
| 通知名 | NOTIFICATION_PAUSED |
| 定義箇所 | scene/main/node.h |

### 通知ハンドリング例

```cpp
void Node::_notification(int p_notification) {
    switch (p_notification) {
        case NOTIFICATION_PAUSED: {
            // ポーズ時の処理
            if (is_physics_interpolated_and_enabled() && is_inside_tree()) {
                reset_physics_interpolation();
            }
        } break;
    }
}
```

```gdscript
func _notification(what):
    if what == NOTIFICATION_PAUSED:
        # ポーズ時の処理
        _on_paused()
```

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| p_notification | 通知ID（14） | エンジン内部 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API呼び出し | SceneTree.paused = true | ノードがcan_process可能だった | ツリー全体のポーズ |
| API呼び出し | Node.set_process_mode() | prev_can_process && !next_can_process | プロセスモード変更 |
| 内部伝播 | _propagate_pause_notification(true) | _can_process(false) && !_can_process(true) | 親からの伝播 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| process_mode == PROCESS_MODE_ALWAYS | 常に処理を継続するノードには送信されない |
| process_mode == PROCESS_MODE_WHEN_PAUSED | ポーズ中のみ処理するノードには送信されない |
| process_mode == PROCESS_MODE_DISABLED | 既に無効化されているノードには影響なし |
| ノードがツリー外 | is_inside_tree() == false の場合は送信されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[SceneTree.paused = true または process_mode変更] --> B{prev_can_process?}
    B -->|Yes| C{next_can_process?}
    B -->|No| D[通知不要]
    C -->|Yes| D
    C -->|No| E[NOTIFICATION_PAUSED送信]
    E --> F[_notification処理実行]
    F --> G{物理補間有効?}
    G -->|Yes| H[reset_physics_interpolation]
    G -->|No| I[終了]
    H --> I
    E --> J[子ノードへ伝播]
    J --> K{子ノードのprocess_mode?}
    K -->|INHERIT| L[再帰的に伝播]
    K -->|その他| M[個別判定]
```

## データベース参照・更新仕様

### 参照データ一覧

| データ | 用途 | 備考 |
|--------|------|------|
| Node::data.process_mode | プロセスモードの判定 | enum ProcessMode |
| Node::data.process_owner | プロセスオーナーの参照 | 継承元の特定 |
| SceneTree::paused | ツリー全体のポーズ状態 | bool |

### 更新データ一覧

| データ | 操作 | 概要 |
|--------|------|------|
| 物理補間状態 | リセット | reset_physics_interpolation()実行時 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ツリー外アクセス | is_inside_tree() == false | 通知をスキップ |
| 無効なprocess_owner | process_owner == nullptr | デフォルト値（PAUSABLE）を使用 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（ゲーム実行中いつでも発生可能）

## セキュリティ考慮事項

- この通知はエンジン内部でのみ使用され、外部からの直接呼び出しは想定されていない
- スクリプトからnotification()を直接呼び出すことは可能だが、状態の不整合を招く可能性がある
- マルチスレッド環境では、メインスレッドからのみ安全にアクセス可能

## 備考

- NOTIFICATION_SUSPENDEDと同じcase文で処理される（物理補間リセット）
- GDScriptでは`_notification(NOTIFICATION_PAUSED)`でハンドリング可能
- エディタ環境（TOOLS_ENABLED）では、tree_process_mode_changedシグナルも発行される

---

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

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、ノードのプロセスモードに関するデータ構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | node.h | `scene/main/node.h` | ProcessMode enumの定義（75-81行目）、NOTIFICATION_PAUSED定数の定義（455行目） |
| 1-2 | node.h | `scene/main/node.h` | Data構造体のprocess_mode、process_ownerフィールド（227-228行目、242行目） |

**読解のコツ**: ProcessModeの5つの状態（INHERIT, PAUSABLE, WHEN_PAUSED, ALWAYS, DISABLED）の違いを理解することが重要。

#### Step 2: エントリーポイントを理解する

処理の起点となる関数を特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | node.cpp | `scene/main/node.cpp` | set_process_mode関数（663-719行目）でのポーズ通知判定ロジック |
| 2-2 | node.cpp | `scene/main/node.cpp` | _propagate_pause_notification関数（721-736行目）での伝播処理 |

**主要処理フロー**:
1. **663-667行目**: process_modeの変更チェック
2. **674-675行目**: 変更前のcan_processとis_enabled状態を保存
3. **694-698行目**: ポーズ通知の判定（prev && !next → PAUSED, !prev && next → UNPAUSED）
4. **708行目**: _propagate_process_ownerで子ノードへ伝播

#### Step 3: 通知ハンドラを理解する

通知を受け取った際の処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | node.cpp | `scene/main/node.cpp` | _notification関数のNOTIFICATION_PAUSEDケース（235-240行目） |

**主要処理フロー**:
- **237-239行目**: 物理補間が有効かつツリー内の場合、reset_physics_interpolation()を呼び出し

#### Step 4: can_process判定ロジックを理解する

ポーズ状態の判定に使われる内部関数を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | node.cpp | `scene/main/node.cpp` | _can_process関数（906-933行目）のポーズ判定ロジック |
| 4-2 | node.cpp | `scene/main/node.cpp` | can_process関数（901-904行目）の公開API |

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

```
SceneTree::set_paused(true)
    │
    └─ Node::_propagate_pause_notification(true)
           │
           ├─ Node::_can_process(false) vs _can_process(true)
           │      └─ ProcessModeの判定
           │
           ├─ Node::notification(NOTIFICATION_PAUSED)
           │      └─ Node::_notification(NOTIFICATION_PAUSED)
           │             └─ reset_physics_interpolation() [条件付き]
           │
           └─ 子ノードへの再帰呼び出し
                  └─ child->_propagate_pause_notification(true)

Node::set_process_mode(new_mode)
    │
    ├─ prev_can_process = can_process()
    ├─ data.process_mode = new_mode
    ├─ next_can_process = can_process()
    │
    └─ _propagate_process_owner(owner, pause_notification, enabled_notification)
           └─ notification(NOTIFICATION_PAUSED) [条件付き]
```

### データフロー図

```
[入力]                    [処理]                         [出力]

SceneTree.paused ───────▶ _propagate_pause_notification ───▶ NOTIFICATION_PAUSED
       │                         │
       │                         ▼
       │                  _can_process判定
       │                         │
       ▼                         ▼
ProcessMode設定 ─────────▶ set_process_mode ────────────────▶ 子ノードへ伝播
       │                         │
       │                         ▼
       │                  状態変化検出
       │                  (prev && !next)
       │                         │
       └─────────────────────────┴───────────────────────▶ 物理補間リセット
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| node.h | `scene/main/node.h` | ヘッダー | Node基底クラス定義、ProcessMode enum、通知定数 |
| node.cpp | `scene/main/node.cpp` | ソース | ポーズ通知の送信・処理ロジック実装 |
| scene_tree.h | `scene/main/scene_tree.h` | ヘッダー | SceneTreeクラス定義、pausedプロパティ |
| scene_tree.cpp | `scene/main/scene_tree.cpp` | ソース | ツリー全体のポーズ制御 |
| audio_stream_player_internal.cpp | `scene/audio/audio_stream_player_internal.cpp` | ソース | オーディオのポーズ処理例 |
| video_stream_player.cpp | `scene/gui/video_stream_player.cpp` | ソース | ビデオのポーズ処理例 |
