cameras について
Phaser 4 のゲームでカメラを実装する開発者向けスキルです。カメラ管理、移動、エフェクト、複数ビュー、操作方法を解説します。
主な機能
- 01シーン内のカメラ管理
- 02ビューポート、スクロール、ズーム、境界の設定
- 03デッドゾーンを使ったターゲット追従
- 04フェード、フラッシュ、シェイク、パン、回転の適用
- 05複数カメラと除外リストの設定
- 06キーボードによるカメラ操作
活用シーン
- 01メインビューと並ぶミニマップの作成
- 02プレイヤーを滑らかに追従するカメラ
- 03カメラを分けたHUDとゲーム世界の描画
- 04ポインター座標からワールド座標への変換
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ phaserjs/ phaser --skill camerasインストール後、Claude Code で/camerasを入力して読み込まれたか確認します。
同梱ファイルreferences/REFERENCE.md
詳細
カメラ
Phaser 4 のカメラシステム -- CameraManager、メインカメラ、ビューポートとスクロール、ズーム、境界、スプライトの追従、カメラエフェクト(フェード、フラッシュ、シェイク、パン、zoomTo、rotateTo)、無視リスト、フィルター、キーボード操作。
主要なソースパス: src/cameras/2d/CameraManager.js、src/cameras/2d/BaseCamera.js、src/cameras/2d/Camera.js、src/cameras/2d/effects/、src/cameras/controls/
関連スキル: ../game-setup-and-config/SKILL.md、../sprites-and-images/SKILL.md、../filters-and-postfx/SKILL.md
クイックスタート
// In a Scene's create() method:
// Access the default camera (created automatically)
const cam = this.cameras.main;
// Scroll the camera to look at a different part of the world
cam.setScroll(200, 100);
// Center camera on a world coordinate
cam.centerOn(400, 300);
// Zoom in (2x) -- values < 1 zoom out, > 1 zoom in
cam.setZoom(2);
// Follow a sprite with smooth lerp
cam.startFollow(player, false, 0.1, 0.1);
// Constrain the camera to the world bounds
cam.setBounds(0, 0, 2048, 2048);
// Fade in from black over 1 second
cam.fadeIn(1000);
// Add a filter to the camera (v4 feature)
cam.filters.external.addBlur(1, 2);
基本概念
CameraManager
すべてのシーンには this.cameras でアクセスできる CameraManager があります。これはそのシーンのすべてのカメラを管理し、'CameraManager' というキーのプラグインとして登録されます。
// The manager is at this.cameras (not this.camera)
this.cameras // CameraManager instance
this.cameras.cameras // Array of Camera objects (render order)
this.cameras.main // Reference to the "main" camera (first one by default)
this.cameras.default // Un-transformed utility camera (not in the cameras array)
CameraManager の主要メソッド:
| メソッド | シグネチャ | 説明 |
|---|---|---|
add | (x?, y?, width?, height?, makeMain?, name?) | 新しいカメラを作成します。デフォルトでは 0,0 の位置にゲームの全サイズで作成されます。Camera を返します。 |
addExisting | (camera, makeMain?) | 事前に構築された Camera インスタンスを追加します。Camera、またはすでに存在する場合は null を返します。 |
remove | (camera, runDestroy?) | Camera または Camera の配列を削除し、オプションで破棄します。メインが削除された場合は cameras[0] にリセットされます。 |
getCamera | (name) | name 文字列で Camera を検索します。Camera または null を返します。 |
getTotal | (isVisible?) | カメラを数えます。true を渡すと可視のものだけを数えます。 |
fromJSON | (config) | 設定オブジェクトまたは配列からカメラを作成します。シーンレベルのカメラ設定に使用します。 |
resetAll | () | すべてのカメラを破棄し、新しいデフォルトカメラを 1 つ作成します。 |
resize | (width, height) | すべてのカメラを指定されたサイズに変更します。 |
カメラの上限: マネージャーは、Game Object の除外に ignore() を使用できる最大 32 台のカメラをサポートします(ID はビットマスクです)。32 台を超えるカメラは ID 0 となり、オブジェクトを除外できません。
メインカメラ
main プロパティは、通常 cameras[0] である Camera への便利な参照です。これは以下の場合に自動的に設定されます:
- シーンが起動したとき(最初に作成されたカメラがメインになります)
add()またはaddExisting()にmakeMain: trueを渡したとき- 現在のメインカメラが削除されたとき(
cameras[0]にフォールバックします)
ビューポートとワールド(スクロール)
カメラには 2 つの独立した座標の概念があります:
-
ビューポート -- カメラがレンダリングするキャンバス上の物理的な矩形。
setPosition(x, y)、setSize(w, h)、またはsetViewport(x, y, w, h)で制御します。デフォルトでは、ゲームキャンバス全体を占めます。 -
スクロール -- ゲームワールド内でカメラが「見ている」位置。
scrollX/scrollYプロパティまたはsetScroll(x, y)で制御します。スクロールはビューポートの矩形には影響しません。
// Viewport: a 320x200 mini-map in the top-right corner
const miniCam = this.cameras.add(480, 0, 320, 200);
// Scroll: make the mini-map look at a different world area
miniCam.setScroll(1000, 500);
// Zoom: the mini-cam shows more of the world
miniCam.setZoom(0.25);
worldView は毎フレーム更新される読み取り専用の Rectangle で、スクロール、ズーム、境界を考慮して、カメラが現在見ることができるワールドの領域を反映します。カリングや交差判定に使用します。
const view = cam.worldView; // { x, y, width, height }
一般的なパターン
カメラのスクロール
// Direct property access
cam.scrollX = 100;
cam.scrollY = 200;
// Chainable setter
cam.setScroll(100, 200);
// Center the camera on a world coordinate
cam.centerOn(500, 400);
// Get the scroll values needed to center on a point (without moving)
const point = cam.getScroll(500, 400); // returns Vector2
スプライトの追従
// Instant follow (lerp = 1, the default)
cam.startFollow(player);
// Smooth follow with lerp (0..1, lower = smoother)
cam.startFollow(player, false, 0.1, 0.1);
// Full signature:
// startFollow(target, roundPixels?, lerpX?, lerpY?, offsetX?, offsetY?)
cam.startFollow(player, true, 0.05, 0.05, 0, -50);
// Change lerp or offset after starting follow
cam.setLerp(0.08, 0.08);
cam.setFollowOffset(0, -50);
// Dead zone: camera only scrolls when target leaves this rectangle
cam.setDeadzone(200, 150);
// Stop following
cam.stopFollow();
startFollow は x と y プロパティを持つ任意のオブジェクトを受け付けます -- Game Object である必要はありません。Lerp が 1 の場合は即座にスナップし、0.1 の場合は滑らかに追従します。いずれかの軸で Lerp が 0 の場合は、その軸での追従が無効になります。
デッドゾーンが設定されている場合、ターゲットがデッドゾーンの矩形内にとどまっている間はカメラはスクロールしません。デッドゾーンは毎フレーム、カメラの中点を中心に再配置されます。
ズーム
// Uniform zoom
cam.setZoom(2); // 2x zoom in
cam.setZoom(0.5); // zoom out (see twice as much)
// Independent horizontal/vertical zoom
cam.setZoom(2, 1); // stretch horizontally
// Read current zoom
cam.zoom; // shortcut -- reads zoomX (assumes uniform)
cam.zoomX;
cam.zoomY;
ズームを 0 に設定しないでください。 最小値は 0.001 にクランプされます。
境界
// Constrain scrolling to a world area
cam.setBounds(0, 0, worldWidth, worldHeight);
// Center on the new bounds immediately
cam.setBounds(0, 0, 2048, 2048, true);
// Temporarily disable bounds without removing them
cam.useBounds = false;
// Remove bounds entirely
cam.removeBounds();
// Read the current bounds
const rect = cam.getBounds(); // returns a new Rectangle copy
境界はスクロールを制限するだけです。Game Object が境界の外に配置されるのを防ぐことはなく、ビューポートの位置にも影響しません。
複数のカメラ
// Full-screen main camera
const main = this.cameras.main;
// Mini-map in top-right corner
const minimap = this.cameras.add(600, 0, 200, 150).setZoom(0.2).setName('minimap');
minimap.setScroll(0, 0);
minimap.setBackgroundColor('rgba(0,0,0,0.5)');
// HUD camera that doesn't scroll (ignores world objects, shows HUD layer only)
const hudCam = this.cameras.add(0, 0, 800, 600).setName('hud');
hudCam.setScroll(0, 0);
// Make the main camera ignore HUD objects
main.ignore(hudGroup);
// Make the HUD camera ignore world objects
hudCam.ignore(worldGroup);
// Find a camera by name
const found = this.cameras.getCamera('minimap');
// Remove a camera
this.cameras.remove(minimap);
カメラエフェクト
すべてのエフェクトは Camera クラスにあります(BaseCamera ではありません)。それぞれがチェーン用に this を返します。すでに実行中のエフェクトは、force: true を渡さない限り再開されません。
フェード
// Fade out to black over 1 second
cam.fadeOut(1000);
// Fade out to red
cam.fadeOut(1000, 255, 0, 0);
// Fade in from black over 500ms
cam.fadeIn(500);
// Lower-level: fade (out direction) and fadeFrom (in direction)
// with a force parameter
cam.fade(1000, 0, 0, 0, true); // force start even if running
cam.fadeFrom(1000, 0, 0, 0, true);
// With per-frame callback
cam.fadeOut(1000, 0, 0, 0, (cam, progress) => {
// progress goes from 0 to 1
});
フェードの方向: fadeOut / fade は透明から色へ進みます。fadeIn / fadeFrom は色から透明へ進みます。
Flash
// White flash over 250ms (default)
cam.flash(250);
// Red flash over 500ms
cam.flash(500, 255, 0, 0);
// Full signature: flash(duration?, r?, g?, b?, force?, callback?, context?)
cam.flash(300, 255, 255, 255, true, (cam, progress) => {});
Shake
// Default shake: 100ms at intensity 0.05
cam.shake(100);
// Stronger shake for 500ms
cam.shake(500, 0.02);
// Independent x/y intensity using a Vector2
cam.shake(300, new Phaser.Math.Vector2(0.1, 0.02));
// Full signature: shake(duration?, intensity?, force?, callback?, context?)
intensity 値は小さな浮動小数点数です。デフォルトの 0.05 は、カメラがビューポートサイズの最大 5% まで移動することを意味します。
Pan
// Pan camera center to world coordinate (400, 300) over 2 seconds
cam.pan(400, 300, 2000);
// With easing
cam.pan(400, 300, 2000, 'Power2');
// Full signature: pan(x, y, duration?, ease?, force?, callback?, context?)
cam.pan(800, 600, 1500, 'Sine.easeInOut', false, (cam, progress, x, y) => {});
Pan はカメラをスクロールし、そのビューポート中心が指定されたワールド座標で終わるようにします。
ZoomTo
// Animate zoom to 2x over 1 second
cam.zoomTo(2, 1000);
// With easing
cam.zoomTo(0.5, 2000, 'Cubic.easeOut');
// Full signature: zoomTo(zoom, duration?, ease?, force?, callback?, context?)
RotateTo
// Rotate camera to 45 degrees (in radians) over 1 second
cam.rotateTo(Phaser.Math.DegToRad(45), false, 1000);
// Shortest path rotation
cam.rotateTo(Math.PI, true, 1500, 'Quad.easeInOut');
// Full signature: rotateTo(angle, shortestPath?, duration?, ease?, force?, callback?, context?)
角度はラジアンです。最短の回転方向を取るには、shortestPath を true に設定します。
すべてのエフェクトをリセット
cam.resetFX(); // stops and resets all running effects (rotate, pan, shake, flash, fade)
キーボード操作
Phaser は 2 つの組み込みカメラコントロールクラスを提供しています。どちらもシーンの update メソッドで update(delta) を呼び出す必要があります。
FixedKeyControl
フレームごとに固定速度で移動します。スムージングはありません。
// In create():
const cursors = this.input.keyboard.createCursorKeys();
this.camControl = new Phaser.Cameras.Controls.FixedKeyControl({
camera: this.cameras.main,
left: cursors.left,
right: cursors.right,
up: cursors.up,
down: cursors.down,
speed: 0.5 // can also be { x: 0.5, y: 0.3 }
});
// In update(time, delta):
this.camControl.update(delta);
SmoothedKeyControl
滑らかなカメラ移動のために、加速度、ドラッグ、最大速度を適用します。
this.camControl = new Phaser.Cameras.Controls.SmoothedKeyControl({
camera: this.cameras.main,
left: cursors.left,
right: cursors.right,
up: cursors.up,
down: cursors.down,
zoomIn: this.input.keyboard.addKey('Q'),
zoomOut: this.input.keyboard.addKey('E'),
zoomSpeed: 0.02,
acceleration: 0.06,
drag: 0.0005,
maxSpeed: 1.0
});
// In update(time, delta):
this.camControl.update(delta);
どちらのコントロールも zoomIn と zoomOut キー、および zoomSpeed 設定値をサポートしています。
無視リスト
ignore メソッドはゲームオブジェクトの cameraFilter ビットマスクを更新し、カメラがそのオブジェクトのレンダリングをスキップするようにします。
// Ignore a single object
cam.ignore(uiText);
// Ignore an array
cam.ignore([scoreText, livesIcon, pauseButton]);
// Ignore all children in a Group
cam.ignore(uiGroup);
// Ignore a Layer and all its children
cam.ignore(uiLayer);
これは HUD スタイルのセットアップにおける主要な仕組みです。一方のカメラはワールドオブジェクトを無視し、もう一方は HUD オブジェクトを無視します。
カメラのデッドゾーン
デッドゾーンは、フォロー対象の周囲にカメラがスクロールしない矩形領域を定義します。カメラは対象がこの矩形から出たときにのみ移動します。
// Set a deadzone of 200x150 pixels centered on the camera viewport
cam.setDeadzone(200, 150);
// Access the deadzone rectangle (read-only, updated internally)
console.log(cam.deadzone); // Phaser.Geom.Rectangle or null
// Remove the deadzone
cam.setDeadzone();
ワールド座標変換
スクロール、ズーム、回転を考慮して、スクリーン(ポインター)座標をワールド座標に変換します。
const worldPoint = cam.getWorldPoint(pointer.x, pointer.y);
// Reuse an output object to avoid allocation
const output = new Phaser.Math.Vector2();
cam.getWorldPoint(pointer.x, pointer.y, output);
スクロール/ズームされたカメラを扱う際に不可欠です。生のポインター座標はスクリーン空間であり、ワールド空間ではありません。
カメラのレンダリングリスト
毎フレーム、renderList にこのカメラから見えるゲームオブジェクトが格納されます。毎フレーム再構築されます。
const visible = cam.renderList; // array of GameObjects rendered this frame
強制コンポジット(オフスクリーンフレームバッファ)
カメラにオフスクリーンフレームバッファへのレンダリングを強制します。CaptureFrame や類似の機能に必要です。
cam.setForceComposite(true); // enable offscreen framebuffer
cam.setForceComposite(false); // disable
フィルターはフレームバッファレンダリングを自動的に有効にします。フィルターなしで必要な場合は setForceComposite(true) を使用します。
カメラのフィルター(v4)
Phaser 4 では、Camera に 2 つの FilterList インスタンスを持つ filters プロパティがあります。
cam.filters.internal // FilterList -- applied by the system
cam.filters.external // FilterList -- for user-added filters
ゲームオブジェクトに追加するのと同じ方法で、カメラにポストプロセッシングエフェクトを追加します。
// Add a blur filter to the camera
cam.filters.external.addBlur(1, 2);
// Add a glow
cam.filters.external.addGlow(0xff0000, 4, 0, false, 0.1, 10);
// Add a color matrix filter
const fx = cam.filters.external.addColorMatrix();
fx.grayscale();
// Remove all external filters
cam.filters.external.clear();
フィルターには WebGL が必要です。フィルターが有効なとき、カメラはフレームバッファ経由でレンダリングする必要があります。フィルターなしでもこれを明示的に有効にするには setForceComposite(true) を参照してください。
イベント
カメラのイベントは Camera インスタンス自体で発行されます(EventEmitter を継承しています)。cam.on(event, handler) でリッスンします。
| イベント定数 | 発行されるタイミング |
|---|---|
Phaser.Cameras.Scene2D.Events.FADE_IN_START | fadeIn / fadeFrom が開始されたとき |
Phaser.Cameras.Scene2D.Events.FADE_IN_COMPLETE | フェードインが完了したとき |
Phaser.Cameras.Scene2D.Events.FADE_OUT_START | fadeOut / fade が開始されたとき |
Phaser.Cameras.Scene2D.Events.FADE_OUT_COMPLETE | フェードアウトが完了したとき |
Phaser.Cameras.Scene2D.Events.FLASH_START | フラッシュが開始されたとき |
Phaser.Cameras.Scene2D.Events.FLASH_COMPLETE | フラッシュが完了したとき |
Phaser.Cameras.Scene2D.Events.SHAKE_START | シェイクが開始されたとき |
Phaser.Cameras.Scene2D.Events.SHAKE_COMPLETE | シェイクが完了したとき |
Phaser.Cameras.Scene2D.Events.PAN_START | パンが開始されたとき |
Phaser.Cameras.Scene2D.Events.PAN_COMPLETE | パンが完了したとき |
Phaser.Cameras.Scene2D.Events.ZOOM_START | ズームエフェクトが開始されたとき |
Phaser.Cameras.Scene2D.Events.ZOOM_COMPLETE | ズームエフェクトが完了したとき |
Phaser.Cameras.Scene2D.Events.ROTATE_START | RotateTo が開始されたとき |
Phaser.Cameras.Scene2D.Events.ROTATE_COMPLETE | RotateTo が完了したとき |
Phaser.Cameras.Scene2D.Events.FOLLOW_UPDATE | カメラがフォロー位置を更新したとき(フォロー中は毎フレーム)。引数: (camera, target) |
Phaser.Cameras.Scene2D.Events.PRE_RENDER | カメラがレンダリングする前 |
Phaser.Cameras.Scene2D.Events.POST_RENDER | カメラがレンダリングした後 |
Phaser.Cameras.Scene2D.Events.DESTROY | カメラが破棄されたとき |
cam.on(Phaser.Cameras.Scene2D.Events.FADE_OUT_COMPLETE, () => {
this.scene.start('GameOver');
});
詳細な設定オプション、API リファレンスの表、ソースファイルのマップについては、リファレンスガイドを参照してください。