# 通知設計書 32-NOTIFICATION_TRANSFORM_CHANGED

## 概要

本ドキュメントは、GodotエンジンのCanvasItemクラスにおけるNOTIFICATION_TRANSFORM_CHANGED通知の設計仕様を記載する。この通知はノードのグローバル変換（位置・回転・スケール）が変更された際に発火され、依存するオブジェクトの更新を可能にする重要なライフサイクルイベントである。

### 本通知の処理概要

NOTIFICATION_TRANSFORM_CHANGEDは、CanvasItem（2D）またはNode3D（3D）ノードのグローバルトランスフォームが変更された際にオプションで発行される通知である。この通知はデフォルトでは無効であり、set_notify_transform(true)を呼び出すことで有効化される。

**業務上の目的・背景**：ゲーム開発において、カメラ追従、コリジョン検出、パーティクルエミッター、ライティングなど多くのシステムがノードの位置変更に依存している。この通知により、関連オブジェクトがリアルタイムで変換変更に対応でき、正確なゲームロジックを実現できる。

**通知の送信タイミング**：set_notify_transform(true)が設定されたノードにおいて、自身または親ノードの変換（position/rotation/scale）が変更された際に発火される。グローバル座標系での最終的な変換が影響を受けた場合にのみ通知される。

**通知の受信者**：notify_transformフラグがtrueに設定されたCanvasItemまたはNode3Dの派生クラス。Camera2D、Light2D、CollisionObject2D、RemoteTransform2Dなどが自動的にこのフラグを有効化して使用する。

**通知内容の概要**：通知値は2000（NOTIFICATION_TRANSFORM_CHANGED = SceneTree::NOTIFICATION_TRANSFORM_CHANGED = 2000）として定義され、ノードのグローバル変換が変更されたことを示す。

**期待されるアクション**：受信ノードはグローバル変換に依存する内部状態を更新する。例えば、カメラは視錐台を再計算し、コリジョンオブジェクトは物理空間での位置を更新する。

## 通知種別

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

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（変換変更時に即座に発行） |
| 優先度 | 中（パフォーマンス考慮で選択的に有効化） |
| リトライ | なし（一度のみ発行） |

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

1. ノードがシーンツリー内に存在すること
2. set_notify_transform(true)でnotify_transformフラグが有効であること
3. block_transform_notifyフラグがfalseであること（一時的なブロックなし）
4. 上記条件を満たすノードに対して、変換変更時にnotification()が呼び出される

## 通知テンプレート

### 内部通知の場合

| 項目 | 内容 |
|-----|------|
| 通知定数名 | NOTIFICATION_TRANSFORM_CHANGED |
| 通知値 | 2000 |
| 逆順送信 | false（通常順） |
| 形式 | 整数値（int p_what） |

### 本文テンプレート

```cpp
// _notification()での受信例
void MyNode::_notification(int p_what) {
    switch (p_what) {
        case NOTIFICATION_TRANSFORM_CHANGED: {
            // グローバル変換が変更された
            Transform2D new_transform = get_global_transform();
            // 依存する処理を更新
            update_dependent_objects();
        } break;
    }
}

// GDScriptでの例
func _notification(what):
    if what == NOTIFICATION_TRANSFORM_CHANGED:
        # 変換変更時の処理
        pass
```

### 添付ファイル

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

## テンプレート変数

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

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 位置変更 | set_position() / set_global_position() | notify_transform=true | ノード位置の変更 |
| 回転変更 | set_rotation() / set_rotation_degrees() | notify_transform=true | ノード回転の変更 |
| スケール変更 | set_scale() | notify_transform=true | ノードスケールの変更 |
| 親変換変更 | 親ノードの変換変更 | notify_transform=true | 親の変換変更が子に伝播 |
| 変換行列設定 | set_transform() / set_global_transform() | notify_transform=true | 直接的な変換行列設定 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| notify_transform=false | デフォルト状態。明示的に有効化が必要 |
| block_transform_notify=true | set_block_transform_notify(true)で一時的にブロック |
| ツリー外のノード | シーンツリーに追加されていないノード |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[変換変更トリガー] --> B{is_inside_tree?}
    B -->|No| C[処理終了]
    B -->|Yes| D{notify_transform?}
    D -->|No| C
    D -->|Yes| E{block_transform_notify?}
    E -->|Yes| C
    E -->|No| F[notification TRANSFORM_CHANGED発行]
    F --> G[派生クラス_notification処理]
    G --> H[子ノードへ伝播]
    H --> I{子のnotify_transform?}
    I -->|Yes| J[子に通知発行]
    I -->|No| K[伝播のみ継続]
    J --> H
    K --> H
```

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

### 参照テーブル一覧

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

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

該当なし

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 無限ループ | 通知ハンドラ内で変換を変更し再帰的に通知が発生 | block_transform_notifyで一時ブロック |
| パフォーマンス低下 | 多数のノードでnotify_transformが有効 | 必要なノードのみで有効化 |
| スレッド競合 | マルチスレッドアクセス | MTFlagによる同期制御 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし（フレームごとに多数発生可能） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

エンジン実行中いつでも発火可能。ただし、物理補間が有効な場合はフレーム境界での発火タイミングに注意。

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

エンジン内部通知のため、外部からの直接的なセキュリティリスクはない。ただし、頻繁な変換変更による計算負荷がDoS的な状況を引き起こす可能性があるため、パフォーマンス監視が推奨される。

## 備考

- Camera2D、Light2D、CollisionObject2Dなどは内部で自動的にset_notify_transform(true)を呼び出す
- NOTIFICATION_LOCAL_TRANSFORM_CHANGED（値35）とは異なり、グローバル座標系での変換変更を通知
- 値2000はSceneTree::NOTIFICATION_TRANSFORM_CHANGEDとして定義され、2D/3D共通で使用

---

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

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

### 推奨読解順序

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | canvas_item.h | `scene/main/canvas_item.h` | NOTIFICATION_TRANSFORM_CHANGED = SceneTree::NOTIFICATION_TRANSFORM_CHANGED定義（210行目）、notify_transformフラグ（116行目） |
| 1-2 | scene_tree.h | `scene/main/scene_tree.h` | SceneTree::NOTIFICATION_TRANSFORM_CHANGED = 2000定義 |

**読解のコツ**: CanvasItemの通知定数はSceneTreeからエイリアスされている。値2000は2D/3D共通。

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

変換通知のトリガーメカニズムを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | canvas_item.h | `scene/main/canvas_item.h` | _notify_transform()インライン関数（173-178行目） |
| 2-2 | canvas_item.cpp | `scene/main/canvas_item.cpp` | _notify_transform(CanvasItem*)メソッド |

**主要処理フロー**:
1. **173行目**: _notify_transform()呼び出し
2. **174-177行目**: ローカル変換通知の条件チェックと発行

#### Step 3: 通知の有効化を理解する

set_notify_transform()の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | canvas_item.cpp | `scene/main/canvas_item.cpp` | set_notify_transform()メソッド |
| 3-2 | canvas_item.cpp | `scene/main/canvas_item.cpp` | is_transform_notification_enabled()メソッド |

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

Camera2Dなどの派生クラスでの具体的な使用パターンを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | camera_2d.cpp | `scene/2d/camera_2d.cpp` | NOTIFICATION_TRANSFORM_CHANGED処理 |
| 4-2 | light_2d.cpp | `scene/2d/light_2d.cpp` | NOTIFICATION_TRANSFORM_CHANGED処理 |
| 4-3 | remote_transform_2d.cpp | `scene/2d/remote_transform_2d.cpp` | NOTIFICATION_TRANSFORM_CHANGED処理 |

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

```
Node2D::set_position() / set_rotation() / set_scale()
    │
    └─ CanvasItem::_notify_transform()
           │
           ├─ _notify_transform(this)
           │      │
           │      ├─ global_invalid = true (マーク)
           │      │
           │      └─ xform_change_list.add() (遅延処理登録)
           │
           └─ notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED)
                  │ (notify_local_transform=trueの場合)
                  │
                  └─ 派生クラス::_notification()

SceneTree::_flush_transform_notifications()
    │
    └─ 各登録ノードに対して
           │
           └─ notification(NOTIFICATION_TRANSFORM_CHANGED)
                  │ (notify_transform=trueの場合)
                  │
                  └─ 派生クラス::_notification()
```

### データフロー図

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

position/rotation   ───▶ _notify_transform() ───▶ global_invalid=true
scale変更                  │
                           ├─▶ xform_change_list登録
                           │
                           └─▶ フレーム終了時
                                  │
                                  └─▶ NOTIFICATION_TRANSFORM_CHANGED
                                         │
                                         └─▶ 派生クラス処理
                                               (カメラ更新等)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| canvas_item.h | `scene/main/canvas_item.h` | ヘッダ | CanvasItemクラス定義、NOTIFICATION定数 |
| canvas_item.cpp | `scene/main/canvas_item.cpp` | ソース | _notify_transform()、set_notify_transform()実装 |
| scene_tree.h | `scene/main/scene_tree.h` | ヘッダ | NOTIFICATION_TRANSFORM_CHANGED = 2000定義 |
| scene_tree.cpp | `scene/main/scene_tree.cpp` | ソース | xform_change_list処理 |
| camera_2d.cpp | `scene/2d/camera_2d.cpp` | ソース | カメラでの通知処理例 |
| light_2d.cpp | `scene/2d/light_2d.cpp` | ソース | ライトでの通知処理例 |
| remote_transform_2d.cpp | `scene/2d/remote_transform_2d.cpp` | ソース | リモート変換での通知処理例 |
| collision_object_2d.cpp | `scene/2d/physics/collision_object_2d.cpp` | ソース | コリジョンでの通知処理例 |
| node_3d.h | `scene/3d/node_3d.h` | ヘッダ | 3D版のNOTIFICATION_TRANSFORM_CHANGED |
| node_3d.cpp | `scene/3d/node_3d.cpp` | ソース | 3D版の変換通知実装 |
| CanvasItem.xml | `doc/classes/CanvasItem.xml` | ドキュメント | 公式APIドキュメント |
