# 通知設計書 22-NOTIFICATION_UNPAUSED

## 概要

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

### 本通知の処理概要

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

**業務上の目的・背景**：ゲーム開発において、一時停止状態からの復帰は適切に処理される必要がある。プレイヤーがゲームを再開する際、停止していた処理を適切に再開し、状態の整合性を保つ必要がある。NOTIFICATION_UNPAUSEDは、このポーズ解除状態への遷移をノードに通知し、各ノードが復帰時の適切な処理（アニメーション再開、サウンド再生再開、タイマーリセットなど）を実行できるようにする。

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

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

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

**期待されるアクション**：
- アニメーションやタイマーの再開
- サウンドの再生再開
- UI状態の更新（ポーズ画面非表示など）
- 経過時間の再計算・補正
- ゲーム状態の同期処理

## 通知種別

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

## 送信仕様

### 基本情報

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

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

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

## 通知テンプレート

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

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

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

```cpp
void MyNode::_notification(int p_notification) {
    switch (p_notification) {
        case NOTIFICATION_UNPAUSED: {
            // ポーズ解除時の処理
            _resume_processing();
        } break;
    }
}
```

```gdscript
func _notification(what):
    if what == NOTIFICATION_UNPAUSED:
        # ポーズ解除時の処理
        _on_unpaused()
```

## テンプレート変数

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

## 送信トリガー・条件

### トリガー一覧

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

### 送信抑止条件

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

## 処理フロー

### 送信フロー

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

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

### 参照データ一覧

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

### 更新データ一覧

| データ | 操作 | 概要 |
|--------|------|------|
| なし | - | 通知のみ、状態更新は受信側で実施 |

## エラー処理

### エラーケース一覧

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

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

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

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

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

## 備考

- NOTIFICATION_PAUSEDとペアで使用される対照的な通知
- Node基底クラスでは特別な処理を行わない（派生クラスでオーバーライド可能）
- GDScriptでは`_notification(NOTIFICATION_UNPAUSED)`でハンドリング可能

---

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

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

### 推奨読解順序

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

NOTIFICATION_PAUSEDと同じデータ構造を使用する。

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

**読解のコツ**: NOTIFICATION_PAUSED（14）の次の値としてUNPAUSED（15）が定義されていることを確認。

#### 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. **696-697行目**: !prev_can_process && next_can_processでUNPAUSED通知を判定
2. **727-728行目**: _propagate_pause_notification内でのUNPAUSED通知送信

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

Node基底クラスではUNPAUSED専用の処理はないが、派生クラスでの実装例を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | gpu_particles_2d.cpp | `scene/2d/gpu_particles_2d.cpp` | パーティクルのポーズ解除処理 |
| 3-2 | audio_stream_player_internal.cpp | `scene/audio/audio_stream_player_internal.cpp` | オーディオのポーズ解除処理 |

**主要処理フロー**:
- 各派生クラスで必要に応じてUNPAUSED通知をハンドリング

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

```
SceneTree::set_paused(false)
    │
    └─ Node::_propagate_pause_notification(false)
           │
           ├─ Node::_can_process(true) vs _can_process(false)
           │      └─ ProcessModeの判定
           │
           ├─ Node::notification(NOTIFICATION_UNPAUSED)
           │      └─ Node::_notification(NOTIFICATION_UNPAUSED)
           │             └─ [派生クラスでの復帰処理]
           │
           └─ 子ノードへの再帰呼び出し
                  └─ child->_propagate_pause_notification(false)

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_UNPAUSED) [条件付き]
```

### データフロー図

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

SceneTree.paused=false ──▶ _propagate_pause_notification ───▶ NOTIFICATION_UNPAUSED
       │                         │
       │                         ▼
       │                  _can_process判定
       │                         │
       ▼                         ▼
ProcessMode設定 ─────────▶ set_process_mode ────────────────▶ 子ノードへ伝播
       │                         │
       │                         ▼
       │                  状態変化検出
       │                  (!prev && next)
       │                         │
       └─────────────────────────┴───────────────────────▶ ユーザー処理実行
```

### 関連ファイル一覧

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