mcpField
P
phantom-camera

phantom-camera

github.com/jame581開発889117 回インストール4 日前に更新
リポジトリ

phantom-camera について

Phantom Cameraは、複数の候補ショットでカメラ動作を定義するGodot向けアドオンです。実カメラに追加したHostが優先度でショットを選び、リソースによるトランジションにも対応します。

主な機能

  1. 01優先度によるカメラ切り替え
  2. 022D・3Dのフォローモード
  3. 033Dの注視モード
  4. 04リソースベースのカメラ遷移
  5. 05Hostによる実カメラ制御
  6. 06C#ラッパーAPI

活用シーン

  1. 01ゲームエリアに応じた追従ショットの切り替え
  2. 02カットシーン専用ショットの設定
  3. 03複数ターゲットのカメラ追従
  4. 04高優先度ショットへの滑らかな遷移

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/jame581/godotprompter --skill phantom-camera

インストール後、Claude Code で/phantom-cameraを入力して読み込まれたか確認します。

同梱ファイルreferences/follow-modes.md

詳細

Phantom Camera

関連スキル: 手動で実装するカメラのパターンには camera-system、トランジションの基礎となるイージングの概念には tween-animation を参照してください。

アドオン: Phantom Camera · バージョン v0.11.0.2 · Godot 4.4+ · MIT · ソース:https://github.com/ramokz/phantom-camera · ノードは GDScript で実装されており、公式の C# ラッパー API(namespace PhantomCamera)もアドオンにソース .cs ファイルとして同梱されています。1.0 未満: マイナーバージョンの更新で API が変更される場合があります。


1. Phantom Camera と camera-system の使い分け

アプローチ最適な用途
手動実装(camera-system スキル)カメラが 1 台で、単純な追従や揺れを実装する場合。アドオンへの依存はありません
Phantom Camera優先度に基づく切り替えが必要な複数のカメラ「ショット」、デッドゾーン/グループ/パス/三人称追従ロジック、そしてリソース駆動のスムーズなトゥイーンによる切り替え — Cinemachine 形式のワークフロー

ゲームプレイ中の追従、カットシーンのフレーミング、ボス戦のグループショットなど、複数の異なるカメラ動作をシーンで使い、それらを 1 つのスクリプトで管理するのではなく、優先度に応じて自動で切り替える必要がある場合は、Phantom Camera を使ってください。Phantom Camera は Camera2D/Camera3D 自体の位置決めロジックを置き換えます。ただし、ビューポートごとに実際の Camera2D/Camera3D は引き続き 1 台だけ使用します。Phantom Camera のノード自体は描画を行いません。


2. インストールとセットアップ

Asset Library(推奨): Godot AssetLib →「Phantom Camera」を検索 → ダウンロード(phantom_camera ディレクトリのみを選択)→ Project → Project Settings → Plugins → 有効化します。

GitHub zip: addons/phantom_camera/ をプロジェクトのルートに展開し、同じ手順でプラグインを有効化します。

プラグインを有効にすると、PhantomCameraManager オートロードシングルトンが自動登録され、_enable_plugin() が実行されるたびに(初回だけでなく)エディターが再起動します。これは想定された動作であり、バグではありません。オートロードを手動で設定する必要はありません。「Create New Node」ダイアログで 6 種類のカスタムノードを使用できるようになります:PhantomCamera2D、PhantomCamera3D、PhantomCameraHost、PhantomCameraNoiseEmitter2D、PhantomCameraNoiseEmitter3D、PhantomCameraTweenDirector。

C# プロジェクト: アドオンには、公式ラッパーが addons/phantom_camera/scripts/** の下に通常の .cs ソースファイルとして同梱されています(namespace PhantomCamera)。追加する NuGet パッケージはありません。C# 対応の Godot プロジェクト(独自の .csproj と Godot.NET.Sdk を持つプロジェクト)では、アドオンフォルダーを配置するとこれらが自動的に取り込まれます。その後は using PhantomCamera; だけで使用できます(§3~§7)。


3. Host とカメラのモデル

2 種類のノードが連携します。

  • PhantomCameraHost — 実際の Camera2D/Camera3D の子として追加します(逆ではありません)。シーン内で最も優先度の高い PhantomCamera2D/3D を読み取り、毎フレーム、実際のカメラのトランスフォームを駆動します。カメラごとに、最初の PhantomCameraHost 子ノードのみが使用されます。
  • PhantomCamera2D/PhantomCamera3D — シーンツリー内の別の場所(プレイヤーの兄弟ノード、トリガーエリア内、カットシーン用リグなど)に配置します。任意の数を配置でき、それぞれが priority、追従モード、(3D のみ)注視モードで候補となる「ショット」を定義します。ノード自体は描画を行いません。
# Scene tree:
# Camera2D (or Camera3D)
#   └─ PhantomCameraHost
# Player (CharacterBody2D)
#   └─ PhantomCamera2D   (priority 0, follow_mode = SIMPLE, follow_target = Player)
# BossArena
#   └─ PhantomCamera2D   (priority 10, follow_mode = GROUP, follow_targets = [Player, Boss])
# CameraRig.gd — on the Camera2D/Camera3D
extends Camera2D

@onready var host: PhantomCameraHost = $PhantomCameraHost

func _ready() -> void:
    # host.camera_2d / host.camera_3d are populated automatically from get_parent()
    var active := host.get_active_pcam()
    print("Active PCam: ", active.name if active else "none")
// CameraRig.cs — on the Camera2D/Camera3D
using PhantomCamera;

public partial class CameraRig : Camera2D
{
    private PhantomCameraHost _host;

    public override void _Ready()
    {
        // Host.Camera2D / Host.Camera3D are populated automatically from GetParent()
        _host = GetNode<Node>("PhantomCameraHost").AsPhantomCameraHost();
        var active = _host.GetActivePhantomCamera();
        GD.Print("Active PCam: ", active is PhantomCamera2D p ? p.Node2D.Name.ToString() : "none");
    }
}

PhantomCameraHost.interpolation_mode(C#:InterpolationMode、列挙値 Auto/Idle/Physics/Manual)は、Host が実際のカメラを更新するタイミングを制御します。 AUTO(デフォルト — アクティブな PCam のターゲットに応じて物理処理またはアイドル処理を選択)、IDLE、PHYSICS、または MANUAL(各ティックで host.process(delta) を自分で呼び出します)。

host_layers(レンダーレイヤーフラグ:2D は Host と PhantomCamera2D、3D は PhantomCamera3D に設定)は、各 Host が対象とする PCam を制限します。PCam の host_layers ビットマスクが Host のものと重なる場合に限り、その PCam が対象になります。


4. 優先度に基づく切り替え

すべての PhantomCamera2D/3D は priority: int = 0 を持ちます。シーンの実カメラにアタッチされた PhantomCameraHost は、自身と host_layers のビットを共有する PCam のうち、最も優先度の高いものに常に追従します。実行時に set_priority(value) で priority を変更し、get_priority() で読み取れます。値は >= 0 にクランプされます。

# TriggerArea.gd — raise priority while the player is inside, restore on exit
extends Area2D

@export var area_pcam: PhantomCamera2D

func _ready() -> void:
    area_entered.connect(_on_entered)
    area_exited.connect(_on_exited)

func _on_entered(area: Area2D) -> void:
    if area.get_parent() is CharacterBody2D:
        area_pcam.set_priority(20)

func _on_exited(area: Area2D) -> void:
    if area.get_parent() is CharacterBody2D:
        area_pcam.set_priority(0)
using PhantomCamera;

public partial class TriggerArea : Area2D
{
    [Export] private Node2D _areaPCamNode;
    private PhantomCamera2D _areaPCam;

    public override void _Ready()
    {
        _areaPCam = _areaPCamNode.AsPhantomCamera2D();
        AreaEntered += a => { if (a.GetParent() is CharacterBody2D) _areaPCam.Priority = 20; };
        AreaExited  += a => { if (a.GetParent() is CharacterBody2D) _areaPCam.Priority = 0; };
    }
}

各 PCam ラッパーで利用できる便利なイベント:BecameActive、BecameInactive、TweenStarted、遷移中に毎フレーム発生する IsTweening、優先度の高い PCam によってこのトゥイーンが中断されたときの TweenInterrupted(引数は割り込んだノード)、TweenCompleted。+= で購読します。GDScript のシグナルと同じ PascalCase の名前です。

priority_override: bool は、priority に触れずにショットをすばやくプレビューするためのエディター専用の「プレビューを強制」切り替えです。エクスポートされたビルドでは自動的に無効になるため、ゲームプレイロジックには使用しないでください。


5. フォローモード

PhantomCamera2D/PhantomCamera3D は、FollowMode 列挙型を通じてターゲットに追従します。モードは GLUED、SIMPLE、GROUP、PATH、FRAMED、および THIRD_PERSON(3D のみ)です。リファレンスでは各モードのプロパティ、GDScript と C# による設定、GROUP の自動リフレーム、フォローオプションの follow_axis_lock、rotate_with_target、lookahead(後者 2 つは 2D のみ)、さらに is_following() と teleport_position() を説明しています。

モードの一覧、設定例、共通のフォローオプションについては、references/follow-modes.md を参照してください。


6. 注視モード(3D のみ)

PhantomCamera2D には注視システムがなく、rotate_with_target(§5)のみを使用できます。PhantomCamera3D には次の機能があります。

enum LookAtMode { NONE = 0, MIMIC = 1, SIMPLE = 2, GROUP = 3 }
モード動作
MIMICターゲットの回転を直接コピーします。
SIMPLElook_at_target(単一の Node3D)をまっすぐ見ます。
GROUPlook_at_targets: Array[Node3D] の重心を見ます。
extends PhantomCamera3D

func _ready() -> void:
    look_at_mode = LookAtMode.SIMPLE
    look_at_target = get_node("../Boss")
    look_at_damping = true
    look_at_damping_value = 0.25  # single scalar, not per-axis
    up_target = get_node("../GroundNormalMarker")  # overrides `up` continuously
using PhantomCamera;

public partial class BossLookAtSetup : Node
{
    [Export] private Node3D _pCamNode; // has a PhantomCamera3D node/script attached
    [Export] private Node3D _boss;
    [Export] private Node3D _groundNormalMarker;

    public override void _Ready()
    {
        // LookAtMode has no wrapper setter (getter-only) — set it on the underlying node.
        _pCamNode.Set("look_at_mode", (int)LookAtMode.Simple);

        var pCam = _pCamNode.AsPhantomCamera3D();
        pCam.LookAtTarget = _boss;
        pCam.LookAtDamping = true;
        pCam.LookAtDampingValue = 0.25f; // single scalar, not per-axis
        pCam.UpTarget = _groundNormalMarker;
    }
}

注意点(アドオン自体の実行時警告より): 同じ PhantomCamera3D で follow_mode を NONE 以外に設定し、look_at_mode も NONE 以外に設定すると、「Using both Look At and Follow Mode on the same PCam3D has not been fully tested yet, proceed with caution!」と表示されます。この組み合わせは実験的なものとして扱い、リリース前に手動で検証してください。


7. カメラ間のトゥイーン

各 PCam は tween_resource: PhantomCameraTween を所有します(これは Resource です。同じタイミング設定を再利用するには、複数の PCam で 1 つの .tres を共有するか、それぞれに既定のインスタンスを持たせます)。

enum TransitionType {
    LINEAR = 0, SINE = 1, QUINT = 2, QUART = 3, QUAD = 4, EXPO = 5,
    ELASTIC = 6, CUBIC = 7, CIRC = 8, BOUNCE = 9, BACK = 10,
}
enum EaseType { EASE_IN = 0, EASE_OUT = 1, EASE_IN_OUT = 2, EASE_OUT_IN = 3 }

@export var duration: float = 1.0
@export var transition: TransitionType = TransitionType.LINEAR
@export var ease: EaseType = EaseType.EASE_IN_OUT

これらは Godot に組み込まれている Tween.TransitionType/Tween.EaseType の名前に 1 対 1 で対応します(TRANS_/EASE_ の接頭辞を除く)。各カーブの形状については tween-animation を参照してください。

# Cutscene PCam: slow, elastic-eased transition when it takes priority
extends PhantomCamera3D

func _ready() -> void:
    tween_resource = PhantomCameraTween.new()
    tween_duration = 1.5          # passthrough — writes tween_resource.duration
    # TransitionType/EaseType live on PhantomCameraTween — qualify them:
    tween_transition = PhantomCameraTween.TransitionType.ELASTIC
    tween_ease = PhantomCameraTween.EaseType.EASE_OUT
using PhantomCamera;

public partial class CutsceneCamSetup : Node
{
    [Export] private Node3D _pCamNode; // has a PhantomCamera3D node/script attached

    public override void _Ready()
    {
        var pCam = _pCamNode.AsPhantomCamera3D();
        pCam.TweenResource = PhantomCameraTween.New();
        pCam.TweenDuration = 1.5f;   // passthrough — writes TweenResource.Duration
        pCam.TweenTransition = TransitionType.Elastic;
        pCam.TweenEase = EaseType.EaseOut;
    }
}

tween_on_load: bool = true は、この PCam が実行時のインスタンス化時点ですでに最優先である場合、ロード時にカメラを所定の位置へトゥイーンさせます。代わりに瞬時に切り替えるには false に設定してください。tween_resource が null の場合、get_tween_duration() は 0.0 を返します(瞬時に切り替わります)。


実装チェックリスト

  • 実際の Camera2D/Camera3D ごとに PhantomCameraHost が必ず1つあり、そのカメラの子として追加されている
  • 各 PhantomCamera2D/3D が、追跡対象とする Host と host_layers のビットを共有している
  • 優先度の変更には set_priority() または priority プロパティを使用する(どちらもセッター経由で処理され、Host に通知されます)
  • is_following() に依存する前に follow_target/follow_targets を割り当てている
  • GROUP 追従モードでは follow_target(単一ノード)ではなく、follow_targets(配列)を使用する
  • 3D の THIRD_PERSON 回転セッター(set_third_person_rotation、set_third_person_rotation_degrees、set_third_person_quaternion)は、follow_mode == THIRD_PERSON の場合にのみ処理し、それ以外では何もせずエラーを出力する — set_follow_distance/set_spring_length/set_collision_mask(_value)/set_shape にはこのようなガードがなく、何も出力しない
  • 1つの PhantomCamera3D で follow_mode と look_at_mode を組み合わせた場合の動作を手動でテストしている(アドオンでは未テストとされています)
  • 複数の PCam を同じように遷移させる場合は、tween_resource を意図的に共有している(同じ .tres)
  • C# では AsPhantomCamera2D()/AsPhantomCamera3D()/AsPhantomCameraHost()/AsPhantomCameraTween() を使ってラッパーを取得する — これらはノードをラップする通常のクラスであり、Node のサブクラスではないため、class MyCam : PhantomCamera2D のように記述しない
  • C# の列挙型名:次元を示す接尾辞が付くのは FollowMode/FollowLockAxis のみ(FollowMode2D、FollowLockAxis3D)。LookAtMode、TransitionType、EaseType、InterpolationMode には付きません
  • ラッパー上の FollowMode/LookAtMode はゲッターのみ — 基底ノードの .Set("follow_mode", (int)FollowMode2D.Simple) を使って設定する
  • アドオンのバージョンを plugin.cfg/バージョン管理で固定する — 1.0 未満では、マイナーバージョンの更新で API に互換性がなくなる可能性があります

コメント