# 通知設計書 31-NOTIFICATION_EXIT_CANVAS

## 概要

本ドキュメントは、GodotエンジンのCanvasItemクラスにおけるNOTIFICATION_EXIT_CANVAS通知の設計仕様を記載する。この通知はCanvasItemノードがキャンバスから退出する際に発火され、2Dレンダリングシステムのリソースクリーンアップを行うための重要なライフサイクルイベントである。

### 本通知の処理概要

NOTIFICATION_EXIT_CANVASは、CanvasItemノードがそのキャンバス（描画領域）から離脱する際に発行される内部通知である。この通知により、レンダリングリソースの解放、親子関係の切断、およびキャンバスグループからの削除が行われる。

**業務上の目的・背景**：2Dゲームやアプリケーションでは、ノードがシーンツリーから削除される際や、異なるキャンバスレイヤーに移動する際に、レンダリングリソースを適切に解放する必要がある。この通知により、メモリリークを防ぎ、レンダリングパイプラインの整合性を維持できる。

**通知の送信タイミング**：CanvasItemノードがシーンツリーから削除される際（NOTIFICATION_EXIT_TREEの処理中）、または親ノードの変更によりキャンバスから離脱する際に発火される。この通知は逆順（reverse）で送信され、子ノードが先に処理される。

**通知の受信者**：CanvasItemを継承するすべてのノード（Control、Node2D、およびそれらの派生クラス）が受信者となる。Light2D、CollisionObject2D、TileMapLayerなど、キャンバス固有のリソースを持つノードが特に重要な受信者である。

**通知内容の概要**：通知値は33（NOTIFICATION_EXIT_CANVAS = 33）として定義され、ノードがキャンバスから退出したことを示す。この通知はRenderingServerへの親参照解除とキャンバスグループからの削除をトリガーする。

**期待されるアクション**：受信ノードはキャンバス固有のリソース（ライトオクルーダー、コリジョン形状など）をRenderingServerから登録解除し、内部状態をクリーンアップする必要がある。派生クラスでは_notification()メソッドでこの通知を処理できる。

## 通知種別

ゲームエンジン内部通知（Object._notificationで受信）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（シーンツリー処理中に即座に発行） |
| 優先度 | 高（リソース解放に必須） |
| リトライ | なし（一度のみ発行） |

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

CanvasItemクラスまたはその派生クラスのノードがキャンバスから離脱する際、エンジン内部で自動的にnotification()が呼び出される。対象ノードの_notification()メソッドまたはObject.connect()でNOTIFICATION_EXIT_CANVASに接続されたコールバックが呼び出される。

## 通知テンプレート

### 内部通知の場合

| 項目 | 内容 |
|-----|------|
| 通知定数名 | NOTIFICATION_EXIT_CANVAS |
| 通知値 | 33 |
| 逆順送信 | true（子から親へ） |
| 形式 | 整数値（int p_what） |

### 本文テンプレート

```cpp
// _notification()での受信例
void MyCanvasItem::_notification(int p_what) {
    switch (p_what) {
        case NOTIFICATION_EXIT_CANVAS: {
            // キャンバス退出時の処理
            // リソースのクリーンアップを実行
        } break;
    }
}
```

### 添付ファイル

該当なし（内部通知のため）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| p_what | 通知種別 | notification()引数 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| シーンツリー操作 | ノード削除（queue_free/remove_child） | CanvasItem派生ノードがツリーから削除 | NOTIFICATION_EXIT_TREE処理中に発火 |
| 親変更 | 親ノード変更 | キャンバス階層が変更される場合 | 新しいキャンバスに再接続前に発火 |
| トップレベル変更 | set_as_top_level()呼び出し | トップレベルフラグが変更された場合 | キャンバス再接続のため一度退出 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| ツリー外のノード | シーンツリーに追加されていないノードには発火しない |
| 既に退出済み | 同一フレーム内で既に退出処理が完了している場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ノード削除/親変更トリガー] --> B[NOTIFICATION_EXIT_TREE発行]
    B --> C[_exit_canvas呼び出し]
    C --> D[NOTIFICATION_EXIT_CANVAS発行 reverse=true]
    D --> E[派生クラスの_notification処理]
    E --> F[RenderingServer親参照解除]
    F --> G[canvas_layer = nullptr]
    G --> H{canvas_groupが空でない?}
    H -->|Yes| I[グループから削除]
    H -->|No| J[終了]
    I --> J
```

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

### 参照テーブル一覧

該当なし（ゲームエンジン内部処理のためデータベースは使用しない）

### テーブル別参照項目詳細

該当なし

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 二重解放 | 同一ノードに対して複数回EXIT_CANVASが発行された場合 | canvas_group空チェックで防御 |
| 無効なRID | RenderingServerリソースが既に解放済みの場合 | RID有効性チェック |
| ツリー外呼び出し | is_inside_tree()がfalseの状態での呼び出し | 事前条件チェック |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし（エンジン内部処理） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

エンジン実行中いつでも発火可能（メインスレッドで同期処理）

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

エンジン内部通知のため、外部からの直接的なセキュリティリスクはない。ただし、_notification()ハンドラ内での不適切な処理がメモリ破壊やクラッシュを引き起こす可能性があるため、派生クラスでの実装には注意が必要。

## 備考

- NOTIFICATION_ENTER_CANVASとペアで使用される
- 値33はCanvasItem固有の通知定数として予約されている
- 逆順送信（reverse=true）により、子ノードが先に処理される

---

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

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

### 推奨読解順序

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

まず、CanvasItemクラスの構造と通知定数の定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | canvas_item.h | `scene/main/canvas_item.h` | NOTIFICATION_EXIT_CANVAS = 33の定義（214行目）、canvas_layer/canvas_groupメンバ変数 |

**読解のコツ**: C++のenumでNOTIFICATION定数が定義されている。値33がEXIT_CANVASに対応。

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

処理の起点となる_exit_canvas()メソッドを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | canvas_item.cpp | `scene/main/canvas_item.cpp` | _exit_canvas()メソッド（287-295行目） |

**主要処理フロー**:
1. **287行目**: _exit_canvas()メソッド開始
2. **288行目**: NOTIFICATION_EXIT_CANVAS発行（reverse=true）
3. **289行目**: RenderingServer::canvas_item_set_parent()で親参照解除
4. **290行目**: canvas_layer = nullptr
5. **291-294行目**: canvas_groupからの削除処理

#### Step 3: 通知発行トリガーを理解する

_notification()内でのEXIT_TREE処理から_exit_canvas()が呼ばれる流れを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | canvas_item.cpp | `scene/main/canvas_item.cpp` | _notification() NOTIFICATION_EXIT_TREE処理（387-393行目） |

**主要処理フロー**:
- **393行目**: _exit_canvas()呼び出し

#### Step 4: 派生クラスでの処理例を理解する

Light2Dなどの派生クラスでの具体的な処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | light_2d.cpp | `scene/2d/light_2d.cpp` | NOTIFICATION_EXIT_CANVAS処理でのライトリソース解放 |
| 4-2 | collision_object_2d.cpp | `scene/2d/physics/collision_object_2d.cpp` | NOTIFICATION_EXIT_CANVAS処理でのコリジョン解放 |

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

```
Node::queue_free() / Node::remove_child()
    │
    └─ CanvasItem::_notification(NOTIFICATION_EXIT_TREE)
           │
           └─ CanvasItem::_exit_canvas()
                  │
                  ├─ notification(NOTIFICATION_EXIT_CANVAS, true)
                  │      │
                  │      └─ 派生クラス::_notification(NOTIFICATION_EXIT_CANVAS)
                  │             └─ リソースクリーンアップ
                  │
                  ├─ RenderingServer::canvas_item_set_parent(RID())
                  │
                  └─ remove_from_group(canvas_group)
```

### データフロー図

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

ノード削除 ───▶ _exit_canvas() ───▶ RenderingServer
リクエスト        │                    親参照解除
                  ├─ notification(33)
                  │     │
                  │     └─▶ 派生クラス
                  │           リソース解放
                  │
                  └─▶ グループ管理
                       グループ削除
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| canvas_item.h | `scene/main/canvas_item.h` | ヘッダ | CanvasItemクラス定義、NOTIFICATION定数 |
| canvas_item.cpp | `scene/main/canvas_item.cpp` | ソース | _exit_canvas()、_notification()実装 |
| light_2d.cpp | `scene/2d/light_2d.cpp` | ソース | 派生クラスでの通知処理例 |
| light_occluder_2d.cpp | `scene/2d/light_occluder_2d.cpp` | ソース | オクルーダーリソース解放例 |
| collision_object_2d.cpp | `scene/2d/physics/collision_object_2d.cpp` | ソース | 物理オブジェクトリソース解放例 |
| tile_map_layer.cpp | `scene/2d/tile_map_layer.cpp` | ソース | タイルマップリソース解放例 |
| control.cpp | `scene/gui/control.cpp` | ソース | UIコントロールでの通知処理 |
| CanvasItem.xml | `doc/classes/CanvasItem.xml` | ドキュメント | 公式APIドキュメント |
