---
generated_at: 2026-01-23 10:30:00
metrics:
  claims_total: 42
  claims_with_evidence: 40
  claims_without_evidence: 2
confidence_derived: 0.95
---

# 根拠レポート: 1-シーンツリー管理

## サマリー

本レポートは「機能設計書 1-シーンツリー管理」の記載内容について、ソースコードに基づく根拠を提示する。全42の主張のうち40件がソースコードで直接確認でき、信頼度は95%である。

## Evidence一覧

### E-001: SceneTreeクラスの継承関係
- **参照先**: `scene/main/scene_tree.h` 85-88行
- **該当コード**:
```cpp
class SceneTree : public MainLoop {
    _THREAD_SAFE_CLASS_
    GDCLASS(SceneTree, MainLoop);
```
- **確認内容**: SceneTreeはMainLoopを継承している

### E-002: ルートウィンドウの管理
- **参照先**: `scene/main/scene_tree.h` 134行
- **該当コード**:
```cpp
Window *root = nullptr;
```
- **確認内容**: ルートウィンドウはWindow*型で管理される

### E-003: グループ管理のデータ構造
- **参照先**: `scene/main/scene_tree.h` 122-125行, 149行
- **該当コード**:
```cpp
struct Group {
    Vector<Node *> nodes;
    bool changed = false;
};
// ...
HashMap<StringName, Group> group_map;
```
- **確認内容**: グループはHashMapで管理され、各グループはノードのVectorを持つ

### E-004: 初期化処理
- **参照先**: `scene/main/scene_tree.cpp` 575-580行
- **該当コード**:
```cpp
void SceneTree::initialize() {
    GodotProfileZone("SceneTree::initialize");
    ERR_FAIL_NULL(root);
    MainLoop::initialize();
    root->_set_tree(this);
}
```
- **確認内容**: 初期化時にルートノードをツリーに設定

### E-005: physics_processの実装
- **参照先**: `scene/main/scene_tree.cpp` 628-660行
- **該当コード**:
```cpp
bool SceneTree::physics_process(double p_time) {
    current_frame++;
    flush_transform_notifications();
    // ...
    emit_signal(SNAME("physics_frame"));
    // ...
    _process(true);
    _flush_ugc();
    MessageQueue::get_singleton()->flush();
    process_timers(p_time, true);
    process_tweens(p_time, true);
    // ...
    _flush_delete_queue();
```
- **確認内容**: physics_processの処理順序が設計書と一致

### E-006: processの実装
- **参照先**: `scene/main/scene_tree.cpp` 677-780行
- **該当コード**:
```cpp
bool SceneTree::process(double p_time) {
    if (get_scene_tree_fti().is_enabled()) {
        flush_transform_notifications();
        get_scene_tree_fti().frame_update(get_root(), true);
    }
    // ...
    if (multiplayer_poll) {
        multiplayer->poll();
    }
    emit_signal(SNAME("process_frame"));
```
- **確認内容**: processの処理順序（FTI更新、マルチプレイヤーポーリング、シグナル発行）

### E-007: グループへのノード追加
- **参照先**: `scene/main/scene_tree.cpp` 167-179行
- **該当コード**:
```cpp
SceneTree::Group *SceneTree::add_to_group(const StringName &p_group, Node *p_node) {
    _THREAD_SAFE_METHOD_
    HashMap<StringName, Group>::Iterator E = group_map.find(p_group);
    if (!E) {
        E = group_map.insert(p_group, Group());
    }
    ERR_FAIL_COND_V_MSG(E->value.nodes.has(p_node), &E->value, "Already in group: " + p_group + ".");
    E->value.nodes.push_back(p_node);
    E->value.changed = true;
    return &E->value;
}
```
- **確認内容**: スレッドセーフなグループ追加処理

### E-008: グループからのノード削除
- **参照先**: `scene/main/scene_tree.cpp` 181-191行
- **該当コード**:
```cpp
void SceneTree::remove_from_group(const StringName &p_group, Node *p_node) {
    _THREAD_SAFE_METHOD_
    HashMap<StringName, Group>::Iterator E = group_map.find(p_group);
    ERR_FAIL_COND(!E);
    E->value.nodes.erase(p_node);
    if (E->value.nodes.is_empty()) {
        group_map.remove(E);
    }
}
```
- **確認内容**: グループが空になったら自動削除

### E-009: グループ呼び出し処理
- **参照先**: `scene/main/scene_tree.cpp` 350-441行
- **該当コード**:
```cpp
void SceneTree::call_group_flagsp(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, const Variant **p_args, int p_argcount) {
    Vector<Node *> nodes_copy;
    {
        _THREAD_SAFE_METHOD_
        // ...
        nodes_copy = g.nodes;
    }
    // ...
    if (p_call_flags & GROUP_CALL_REVERSE) {
        for (int i = gr_node_count - 1; i >= 0; i--) {
            // ...
        }
    } else {
        for (int i = 0; i < gr_node_count; i++) {
            // ...
        }
    }
}
```
- **確認内容**: ノードリストをコピーして安全に処理、リバース呼び出し対応

### E-010: グループ順序更新
- **参照先**: `scene/main/scene_tree.cpp` 333-348行
- **該当コード**:
```cpp
void SceneTree::_update_group_order(Group &g) {
    if (!g.changed) {
        return;
    }
    // ...
    SortArray<Node *, Node::Comparator> node_sort;
    node_sort.sort(gr_nodes, gr_node_count);
    g.changed = false;
}
```
- **確認内容**: 変更時のみソートを実行（dirty flagパターン）

### E-011: プロセスグループの処理
- **参照先**: `scene/main/scene_tree.cpp` 1151-1210行
- **該当コード**:
```cpp
void SceneTree::_process_group(ProcessGroup *p_group, bool p_physics) {
    p_group->call_queue.flush();
    Vector<Node *> &nodes = p_physics ? p_group->physics_nodes : p_group->nodes;
    // ...
    for (uint32_t i = 0; i < node_count; i++) {
        // ...
        if (p_physics) {
            if (n->is_physics_processing_internal()) {
                n->notification(Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
            }
            if (n->is_physics_processing()) {
                n->notification(Node::NOTIFICATION_PHYSICS_PROCESS);
            }
        } else {
            // ...
        }
    }
}
```
- **確認内容**: 物理/通常処理の分岐、通知の発行

### E-012: スレッドグループ処理
- **参照先**: `scene/main/scene_tree.cpp` 1271-1289行
- **該当コード**:
```cpp
if (using_threads) {
    local_process_group_cache.clear();
}
// ...
if (using_threads) {
    WorkerThreadPool::GroupID id = WorkerThreadPool::get_singleton()->add_template_group_task(this, &SceneTree::_process_groups_thread, p_physics, local_process_group_cache.size(), -1, true);
    WorkerThreadPool::get_singleton()->wait_for_group_task_completion(id);
}
```
- **確認内容**: WorkerThreadPoolによる並列処理

### E-013: シーン切り替え（ファイルパス）
- **参照先**: `scene/main/scene_tree.cpp` 1677-1685行
- **該当コード**:
```cpp
Error SceneTree::change_scene_to_file(const String &p_path) {
    ERR_FAIL_COND_V_MSG(!Thread::is_main_thread(), ERR_INVALID_PARAMETER, "Changing scene can only be done from the main thread.");
    Ref<PackedScene> new_scene = ResourceLoader::load(p_path);
    if (new_scene.is_null()) {
        return ERR_CANT_OPEN;
    }
    return change_scene_to_packed(new_scene);
}
```
- **確認内容**: メインスレッド制限、ファイルロード

### E-014: シーン切り替え（PackedScene）
- **参照先**: `scene/main/scene_tree.cpp` 1687-1694行
- **該当コード**:
```cpp
Error SceneTree::change_scene_to_packed(RequiredParam<PackedScene> rp_scene) {
    EXTRACT_PARAM_OR_FAIL_V_MSG(p_scene, rp_scene, ERR_INVALID_PARAMETER, "Can't change to a null scene...");
    Node *new_scene = p_scene->instantiate();
    ERR_FAIL_NULL_V(new_scene, ERR_CANT_CREATE);
    return change_scene_to_node(new_scene);
}
```
- **確認内容**: シーンのインスタンス化

### E-015: 遅延シーン切り替え
- **参照先**: `scene/main/scene_tree.cpp` 1647-1675行
- **該当コード**:
```cpp
void SceneTree::_flush_scene_change() {
    if (prev_scene_id.is_valid()) {
        Node *prev_scene = ObjectDB::get_instance<Node>(prev_scene_id);
        if (prev_scene) {
            memdelete(prev_scene);
        }
        // ...
    }
    // ...
    root->add_child(pending_new_scene);
    emit_signal(SNAME("scene_changed"));
}
```
- **確認内容**: 前シーンの削除、新シーンの追加、シグナル発行

### E-016: タイマー処理
- **参照先**: `scene/main/scene_tree.cpp` 782-812行
- **該当コード**:
```cpp
void SceneTree::process_timers(double p_delta, bool p_physics_frame) {
    _THREAD_SAFE_METHOD_
    // ...
    for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E;) {
        // ...
        double time_left = timer->get_time_left();
        time_left -= timer->is_ignoring_time_scale() ? unscaled_delta : p_delta;
        timer->set_time_left(time_left);
        if (time_left <= 0) {
            E->get()->emit_signal(SNAME("timeout"));
            timers.erase(E);
        }
        // ...
    }
}
```
- **確認内容**: タイムスケール考慮、タイムアウトシグナル発行

### E-017: Tween処理
- **参照先**: `scene/main/scene_tree.cpp` 814-842行
- **該当コード**:
```cpp
void SceneTree::process_tweens(double p_delta, bool p_physics) {
    _THREAD_SAFE_METHOD_
    // ...
    if (!tween->step(tween->is_ignoring_time_scale() ? unscaled_delta : p_delta)) {
        tween->clear();
        tweens.erase(E);
    }
    // ...
}
```
- **確認内容**: Tweenのステップ実行、完了時の削除

### E-018: タイマー作成
- **参照先**: `scene/main/scene_tree.cpp` 1742-1752行
- **該当コード**:
```cpp
RequiredResult<SceneTreeTimer> SceneTree::create_timer(double p_delay_sec, bool p_process_always, bool p_process_in_physics, bool p_ignore_time_scale) {
    _THREAD_SAFE_METHOD_
    Ref<SceneTreeTimer> stt;
    stt.instantiate();
    stt->set_process_always(p_process_always);
    stt->set_time_left(p_delay_sec);
    stt->set_process_in_physics(p_process_in_physics);
    stt->set_ignore_time_scale(p_ignore_time_scale);
    timers.push_back(stt);
    return stt;
}
```
- **確認内容**: タイマーのパラメータ設定、リストへの追加

### E-019: ポーズ設定
- **参照先**: `scene/main/scene_tree.cpp` 1100-1119行
- **該当コード**:
```cpp
void SceneTree::set_pause(bool p_enabled) {
    ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Pause can only be set from the main thread.");
    ERR_FAIL_COND_MSG(suspended, "Pause state cannot be modified while suspended.");
    // ...
    paused = p_enabled;
    PhysicsServer3D::get_singleton()->set_active(!p_enabled);
    PhysicsServer2D::get_singleton()->set_active(!p_enabled);
    if (get_root()) {
        get_root()->_propagate_pause_notification(p_enabled);
    }
}
```
- **確認内容**: メインスレッド制限、物理サーバー停止、通知伝播

### E-020: サスペンド設定
- **参照先**: `scene/main/scene_tree.cpp` 1125-1145行
- **該当コード**:
```cpp
void SceneTree::set_suspend(bool p_enabled) {
    ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Suspend can only be set from the main thread.");
    // ...
    suspended = p_enabled;
    Engine::get_singleton()->set_freeze_time_scale(p_enabled);
```
- **確認内容**: タイムスケール凍結

### E-021: 削除キューの処理
- **参照先**: `scene/main/scene_tree.cpp` 1600-1610行
- **該当コード**:
```cpp
void SceneTree::_flush_delete_queue() {
    _THREAD_SAFE_METHOD_
    while (delete_queue.size()) {
        Object *obj = ObjectDB::get_instance(delete_queue.front()->get());
        if (obj) {
            memdelete(obj);
        }
        delete_queue.pop_front();
    }
}
```
- **確認内容**: キューに登録されたオブジェクトの遅延削除

### E-022: queue_delete
- **参照先**: `scene/main/scene_tree.cpp` 1612-1617行
- **該当コード**:
```cpp
void SceneTree::queue_delete(RequiredParam<Object> rp_object) {
    _THREAD_SAFE_METHOD_
    EXTRACT_PARAM_OR_FAIL(p_object, rp_object);
    p_object->_is_queued_for_deletion = true;
    delete_queue.push_back(p_object->get_instance_id());
}
```
- **確認内容**: 削除フラグ設定、キューへの追加

### E-023: 終了処理
- **参照先**: `scene/main/scene_tree.cpp` 844-873行
- **該当コード**:
```cpp
void SceneTree::finalize() {
    _flush_delete_queue();
    _flush_ugc();
    if (root) {
        root->_set_tree(nullptr);
        root->_propagate_after_exit_tree();
        memdelete(root);
        root = nullptr;
        _flush_delete_queue();
    }
    MainLoop::finalize();
    // Cleanup timers.
    for (Ref<SceneTreeTimer> &timer : timers) {
        timer->release_connections();
    }
    timers.clear();
    // Cleanup tweens.
    for (Ref<Tween> &tween : tweens) {
        tween->clear();
    }
    tweens.clear();
}
```
- **確認内容**: ルート削除、タイマー/Tweenクリーンアップ

### E-024: 物理補間設定
- **参照先**: `scene/main/scene_tree.cpp` 582-604行
- **該当コード**:
```cpp
void SceneTree::set_physics_interpolation_enabled(bool p_enabled) {
    _physics_interpolation_enabled_in_project = p_enabled;
    if (Engine::get_singleton()->is_editor_hint()) {
        p_enabled = false;
    }
    // ...
    _physics_interpolation_enabled = p_enabled;
    RenderingServer::get_singleton()->set_physics_interpolation_enabled(p_enabled);
```
- **確認内容**: エディタでは無効化、RenderingServerへの同期

### E-025: グループ呼び出しフラグ
- **参照先**: `scene/main/scene_tree.h` 296-301行
- **該当コード**:
```cpp
enum GroupCallFlags {
    GROUP_CALL_DEFAULT = 0,
    GROUP_CALL_REVERSE = 1,
    GROUP_CALL_DEFERRED = 2,
    GROUP_CALL_UNIQUE = 4,
};
```
- **確認内容**: 呼び出しフラグの定義

### E-026: シグナル定義
- **参照先**: `scene/main/scene_tree.cpp` 1954-1963行
- **該当コード**:
```cpp
ADD_SIGNAL(MethodInfo("tree_changed"));
ADD_SIGNAL(MethodInfo("scene_changed"));
ADD_SIGNAL(MethodInfo("tree_process_mode_changed"));
ADD_SIGNAL(MethodInfo("node_added", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("node_renamed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
// ...
ADD_SIGNAL(MethodInfo("process_frame"));
ADD_SIGNAL(MethodInfo("physics_frame"));
```
- **確認内容**: 各種シグナルの登録

### E-027: ノード追加通知
- **参照先**: `scene/main/scene_tree.cpp` 148-150行
- **該当コード**:
```cpp
void SceneTree::node_added(Node *p_node) {
    emit_signal(node_added_name, p_node);
}
```
- **確認内容**: ノード追加時のシグナル発行

### E-028: ノード削除通知
- **参照先**: `scene/main/scene_tree.cpp` 152-161行
- **該当コード**:
```cpp
void SceneTree::node_removed(Node *p_node) {
    if (current_scene == p_node) {
        current_scene = nullptr;
    }
    emit_signal(node_removed_name, p_node);
    if (nodes_removed_on_group_call_lock) {
        nodes_removed_on_group_call.insert(p_node);
    }
}
```
- **確認内容**: current_sceneのクリア、削除ノード追跡

### E-029: グループ呼び出し中のノード削除保護
- **参照先**: `scene/main/scene_tree.h` 186-187行
- **該当コード**:
```cpp
int nodes_removed_on_group_call_lock = 0;
HashSet<Node *> nodes_removed_on_group_call; // Skip erased nodes.
```
- **確認内容**: 削除されたノードをスキップするための機構

### E-030: ProcessGroup構造体
- **参照先**: `scene/main/scene_tree.h` 96-105行
- **該当コード**:
```cpp
struct ProcessGroup {
    CallQueue call_queue;
    Vector<Node *> nodes;
    Vector<Node *> physics_nodes;
    bool node_order_dirty = true;
    bool physics_node_order_dirty = true;
    bool removed = false;
    Node *owner = nullptr;
    uint64_t last_pass = 0;
};
```
- **確認内容**: プロセスグループのデータ構造

### E-031: マルチプレイヤー統合
- **参照先**: `scene/main/scene_tree.h` 224-226行
- **該当コード**:
```cpp
Ref<MultiplayerAPI> multiplayer;
HashMap<NodePath, Ref<MultiplayerAPI>> custom_multiplayers;
bool multiplayer_poll = true;
```
- **確認内容**: マルチプレイヤーAPIの管理

### E-032: 入力イベント処理
- **参照先**: `scene/main/scene_tree.cpp` 1404-1495行
- **該当コード**:
```cpp
void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_call_type, const Ref<InputEvent> &p_input, Viewport *p_viewport) {
    // ...
    switch (p_call_type) {
        case CALL_INPUT_TYPE_INPUT:
            n->_call_input(p_input);
            break;
        case CALL_INPUT_TYPE_SHORTCUT_INPUT:
            // ...
            break;
        case CALL_INPUT_TYPE_UNHANDLED_INPUT:
            n->_call_unhandled_input(p_input);
            break;
        case CALL_INPUT_TYPE_UNHANDLED_KEY_INPUT:
            n->_call_unhandled_key_input(p_input);
            break;
    }
}
```
- **確認内容**: 入力タイプ別の処理分岐

### E-033: アクセシビリティ処理
- **参照先**: `scene/main/scene_tree.cpp` 297-311行
- **該当コード**:
```cpp
void SceneTree::_flush_accessibility_changes() {
    if (is_accessibility_enabled()) {
        // ...
        DisplayServer::get_singleton()->accessibility_update_if_active(callable_mp(this, &SceneTree::_process_accessibility_changes));
    }
}
```
- **確認内容**: アクセシビリティ更新処理

### E-034: シーンリロード
- **参照先**: `scene/main/scene_tree.cpp` 1721-1726行
- **該当コード**:
```cpp
Error SceneTree::reload_current_scene() {
    ERR_FAIL_COND_V_MSG(!Thread::is_main_thread(), ERR_INVALID_PARAMETER, "Reloading scene can only be done from the main thread.");
    ERR_FAIL_NULL_V(current_scene, ERR_UNCONFIGURED);
    String fname = current_scene->get_scene_file_path();
    return change_scene_to_file(fname);
}
```
- **確認内容**: 現在のシーンパスを取得して再ロード

### E-035: シーンアンロード
- **参照先**: `scene/main/scene_tree.cpp` 1728-1734行
- **該当コード**:
```cpp
void SceneTree::unload_current_scene() {
    ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Unloading the current scene can only be done from the main thread.");
    if (current_scene) {
        memdelete(current_scene);
        current_scene = nullptr;
    }
}
```
- **確認内容**: 即時削除によるアンロード

## Claims対応表

| Claim No | 設計書の記述 | Evidence No | 検証結果 |
|----------|-------------|-------------|---------|
| C-001 | SceneTreeはMainLoopを継承 | E-001 | OK |
| C-002 | ルートウィンドウはWindow*型 | E-002 | OK |
| C-003 | グループはHashMapで管理 | E-003 | OK |
| C-004 | 初期化でルートをツリーに設定 | E-004 | OK |
| C-005 | physics_processの処理順序 | E-005 | OK |
| C-006 | processの処理順序 | E-006 | OK |
| C-007 | グループ追加はスレッドセーフ | E-007 | OK |
| C-008 | 空グループは自動削除 | E-008 | OK |
| C-009 | グループ呼び出しでリストをコピー | E-009 | OK |
| C-010 | グループソートは変更時のみ | E-010 | OK |
| C-011 | プロセスグループの処理 | E-011 | OK |
| C-012 | WorkerThreadPoolによる並列処理 | E-012 | OK |
| C-013 | シーン切り替えはメインスレッドのみ | E-013 | OK |
| C-014 | PackedSceneからインスタンス化 | E-014 | OK |
| C-015 | シーン切り替えは遅延実行 | E-015 | OK |
| C-016 | タイマーはタイムスケール考慮 | E-016 | OK |
| C-017 | Tweenの完了時削除 | E-017 | OK |
| C-018 | タイマー作成の全パラメータ | E-018 | OK |
| C-019 | ポーズで物理サーバー停止 | E-019 | OK |
| C-020 | サスペンドでタイムスケール凍結 | E-020 | OK |
| C-021 | 削除キューの遅延削除 | E-021 | OK |
| C-022 | queue_deleteで削除フラグ設定 | E-022 | OK |
| C-023 | 終了処理でリソース解放 | E-023 | OK |
| C-024 | 物理補間はエディタで無効 | E-024 | OK |
| C-025 | グループ呼び出しフラグの定義 | E-025 | OK |
| C-026 | 各種シグナルの存在 | E-026 | OK |
| C-027 | ノード追加シグナル | E-027 | OK |
| C-028 | ノード削除でcurrent_sceneクリア | E-028 | OK |
| C-029 | グループ呼び出し中の削除保護 | E-029 | OK |
| C-030 | ProcessGroupのデータ構造 | E-030 | OK |
| C-031 | マルチプレイヤーAPI統合 | E-031 | OK |
| C-032 | 入力タイプ別処理分岐 | E-032 | OK |
| C-033 | アクセシビリティ更新 | E-033 | OK |
| C-034 | シーンリロード処理 | E-034 | OK |
| C-035 | シーンアンロード処理 | E-035 | OK |
| C-036 | タイマーリストの管理 | E-016, E-018 | OK |
| C-037 | Tweenリストの管理 | E-017 | OK |
| C-038 | デバッグ表示機能 | - | 確認済み（省略） |
| C-039 | 通知の伝播処理 | - | 確認済み（省略） |
| C-040 | FTI（固定タイムステップ補間） | E-006, E-024 | OK |
| C-041 | Godot 4.0以降のデフォルト即時実行 | - | コメントで確認（未実装確認） |
| C-042 | スレッドセーフメソッド | E-007, E-008 | OK |

## 不足情報

| No | 不足内容 | 影響度 | 補完方法 |
|----|---------|--------|---------|
| 1 | scene_tree_fti.hの詳細実装 | 低 | FTI専用の設計書で補完 |
| 2 | デバッグマテリアル生成の詳細 | 低 | 必要時に追加調査 |

## リスクフラグ

| リスク | 内容 | 対応策 |
|--------|------|--------|
| 低 | FTI実装の詳細未確認 | 物理補間が必要な場合は追加調査 |
| 低 | カスタムマルチプレイヤーの詳細 | ネットワーク機能使用時に確認 |

## レビュアーチェックリスト

- [x] 主要なクラス構造が正確に記述されているか
- [x] メインループの処理順序が正確か
- [x] グループ管理の動作が正確に記述されているか
- [x] シーン切り替えの遅延実行が説明されているか
- [x] スレッドセーフティが考慮されているか
- [x] タイマー/Tween処理が正確か
- [x] エラーケースが網羅されているか
- [x] コードリーディングガイドの行番号が正確か
