phaser-fx について
phaser-fxは、フィルター、マスク、ライティング、ティント、Beamレンダラーを扱うPhaser 4開発者向けのリファレンススキルです。Phaser 3からのAPI変更と、エフェクトや性能に関する実践的な選択肢を説明します。
主な機能
- 01Phaser 4のフィルター一覧
- 02内部・外部フィルターの使い分け
- 03マスクとステンシルの手法
- 04ティントモードと色効果
- 05ライティングとコーンライト
- 06Phaser 3からの移行情報
活用シーン
- 01ゲームオブジェクトやカメラへの効果実装
- 02Phaser 3のマスクやFXの置き換え
- 03ライティングや視野コーンの作成
- 04フィルターの性能上の選択肢の検討
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ yakoub-ai/ phaser4-gamedev --skill phaser-fxインストール後、Claude Code で/phaser-fxを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/filters-api.mdlighting.mdrenderer-and-shaders.md詳細
Phaser 4 のフィルター、マスク、ライト、Beam レンダラー
Phaser 4 では v3 のレンダラーが全面的に置き換えられました。v3 では互換性のない 2 つの別個のシステムだった FX とマスクは、現在では Filters と呼ばれる単一の システムとなり、すべてのゲームオブジェクトとすべてのカメラで例外なく利用できます。
v3 のコードを変換する場合は、下部の変換表から始めてください。新しいコードを 書く場合は、ここから始めてください。
誰もが引っかかる唯一のルール
ゲームオブジェクトでは、まず enableFilters() が必要です。カメラでは不要です。
// Game object — filters is null until you enable it
sprite.enableFilters();
sprite.filters!.internal.addGlow(0xff00ff, 4, 0, 1);
// Camera — filters is always there
this.cameras.main.filters.external.addVignette(0.5, 0.5, 0.5, 0.5);
生成直後のスプライトに対して sprite.filters.internal.addBlur() を呼び出すと、
filters が null であるため例外が発生します。これは Phaser 4 のエフェクトで
最もよくあるエラーであり、そのメッセージ(Cannot read properties of null)は
原因を指し示していません。
内部 vs 外部
すべてのフィルターリストには 2 つの半分があり、間違った方を選ぶことが 2 番目に よくある間違いです。
filters.internal | filters.external | |
|---|---|---|
| 空間 | オブジェクト自身の空間 | レンダリングコンテキスト、通常は全画面 |
| オブジェクトと一緒に移動する | はい | いいえ |
| 解像度 | オブジェクトのサイズ | キャンバス全体 |
| コスト | より安価 | より高価 |
| 用途 | スプライトのグロー、パネルのマスキング | 画面全体のカラーグレーディング、ビネット |
// A glow that follows the enemy: internal.
enemy.enableFilters();
enemy.filters!.internal.addGlow(0xff0000, 8, 0, 1);
// A full-screen red wash when the player is hurt: external, on the camera.
this.cameras.main.filters.external.addColorMatrix();
一部のオブジェクトは内部空間を定義できず、自動的に外部へフォールバックします。
幅や高さがないオブジェクトや、ストロークが報告された境界を超えて広がる Shape
オブジェクトがこれに該当します。シェイプに対する内部フィルターが画面効果のよう
に振る舞う場合、これが理由です。
フィルターカタログ
そのすべては filters.internal または filters.external に対する add* 呼び出し
です。
| フィルター | 動作 |
|---|---|
addBlur(quality, x, y, strength) | ガウスブラー |
addGlow(color, outerStrength, innerStrength, scale) | アウトライングロー |
addShadow(x, y, decay, power, color, samples, intensity) | ドロップシャドウ |
addBokeh(radius, amount, contrast) | 被写界深度風のブラー |
addPixelate(amount) | ピクセル化 |
addBlocky(amount) | ブロック状の量子化 |
addVignette(x, y, radius, strength) | 端を暗くする |
addBarrel(amount) | レンズ歪みの圧縮/拡張 |
addDisplacement(texture, x, y) | テクスチャによる変位 — 陽炎、水 |
addColorMatrix() | カラーグレーディング(下記参照) |
addCombineColorMatrix() | 2 つのカラーマトリックスのブレンド |
addGradientMap(...) | グラデーションによる輝度の再マッピング |
addThreshold(...) | アルファ/カラーのカットオフ |
addQuantize(...) | 色数の削減 |
addMask(source, invert, viewCamera, viewTransform, scaleFactor) | マスキング |
addKey(...) | クロマキー |
addBlend(...) | WebGL の 4 つのネイティブブレンドモードを超えるブレンド |
addTiltShift(...) | チルトシフト |
addPanoramaBlur(...) | パノラマブラー |
addSampler(...) | 別のテクスチャからのサンプリング |
addImageLight(...) | イメージベースライティング |
addNormalTools(...) | ノーマルマップの操作 |
addParallelFilters(...) | 2 つのフィルターチェーンを実行して合成 |
addCustom(...) | 独自のシェーダー |
ColorMatrix にはネストされたプロパティがある
カラーメソッドはフィルター上ではなく、colorMatrix サブプロパティ上にあります。
const cm = sprite.filters!.internal.addColorMatrix();
cm.colorMatrix.sepia(); // correct
cm.colorMatrix.grayscale();
cm.colorMatrix.night(0.3);
// cm.sepia(); // wrong — this was the v3 shape
複合エフェクトは Actions にある
一部の v3 の FX は、複数のフィルターが連携する必要があるため、Actions として 再構築されました。
Phaser.Actions.AddEffectBloom(target); // was the Bloom FX
Phaser.Actions.AddEffectShine(target); // was the Shine FX
Phaser.Actions.AddMaskShape(target); // was the Circle FX
マスキング
BitmapMask はもう存在しません。createGeometryMask() と createBitmapMask() は
ゲームオブジェクトのメソッドではありません。GeometryMask はクラスとして残って
いますが、非推奨の Canvas レンダラーだけがこれを使用します — Beam の下ではまった
く何もしません。
代替手段は 2 つあり、その選択は形状に関するものです。
矩形クリップ → カメラビューポート
スクロールパネル、ミニマップ、分割画面。フィルターより安価で、ピクセル単位で 正確です。
const panelCam = this.cameras.add(x, y, width, height);
panelCam.setScroll(scrollX, scrollY);
panelCam.ignore(this.children.list.filter(c => c !== panelContent));
this.cameras.main.ignore(panelContent);
Phaser 4 には
camera.setScissor()はありません。ガイドでその呼び出しを 見つけても、そのメソッドは存在しません —setViewport()を使用してください。
その他の形状 → Mask フィルター
const shape = this.add.graphics();
shape.fillStyle(0xffffff).fillCircle(64, 64, 64);
content.enableFilters();
content.filters!.internal.addMask(shape); // GameObject or texture key
content.filters!.internal.addMask(shape, true); // inverted: hide inside, show outside
マスクのソースにはテクスチャキーまたはゲームオブジェクトを指定できます。オブジェクトを指定した場合、Phaser はそれを DynamicTexture にレンダリングして使用します。そのため、アニメーションするマスクも、フィルター出力から作られたマスクも機能します。scaleFactor はマスクの精度とメモリをトレードオフします。設定する場合は、マスクのソースを一致するようにスケーリングしてください。
ステンシル — 永続的なマスキング (4.2.0+)
多数のオブジェクトとフレームにわたって固定されたままのマスクには、マスクフィルターを再実行するよりも Stencil のほうが安価です。v3 のステンシルマスクとは異なり、これらは普遍的かつ永続的で、ピクセルを描画するものなら何でもソースとして受け付けます。
const stencil = this.add.stencil();
stencil.add(this.add.circle(400, 300, 120, 0xffffff));
モード: addLayer、subtractLayer、clear、clearRegion。add と subtract はそれぞれ反転可能です。this.add.stencilreference() は既存のステンシルを異なる設定で再レンダリングします。これがステンシルのジオメトリを再利用または削除する方法です。
通常のアルファはステンシル内では何の効果もないため、代わりにアルファは stencilAlphaStrategy で制御します (以下を参照)。stencilInvert が何もしていないように見える場合は、4.2.1 以降を使用してください。これは 4.2.0 のアルファのバグによって壊れていました。
ティント
Phaser 4 では、ティントの色とティントモードが分離されました。v3 では tintFill = true を設定していましたが、そのプロパティはもう存在しません。
sprite.setTint(0xff0000);
sprite.setTintMode(Phaser.TintModes.FILL); // was tintFill = true
モード: MULTIPLY (デフォルト)、FILL、ADD、SCREEN、OVERLAY、HARD_LIGHT、MULTIPLY_TWO。
MULTIPLY_TWO (4.2.0+) はコーナーごとに2つ目のティント色を使用し、シェーダーなしでグラデーション付きのティントを可能にします — 炎、氷、反転:
sprite.setTint(0xff2200).setTint2(0xffee00).setTintMode(Phaser.TintModes.MULTIPLY_TWO);
Mesh2D と Tile は定数の tint2 をサポートします。TilemapGPULayer はタイルのティントをまったくサポートしていません。
Shape にはティントがまったくありません。
Rectangle、Arc、TriangleなどのShapeオブジェクトは Tint コンポーネントを実装していません —setTint()とsetTintMode()はそれらのメソッドではなく、コンパイラーがそう指摘します。代わりにfillColorを変更してください:rect.fillColor = 0xff0000。これは、色付きの矩形でプロトタイピングしてから、ダメージフラッシュのパターンがなぜコンパイルされないのかと不思議に思うときによく引っかかります。
ダメージフラッシュ、すべてのアクションゲームに必要なもの:
hit() {
this.sprite.setTint(0xffffff).setTintMode(Phaser.TintModes.FILL);
this.scene.time.delayedCall(80, () => this.sprite.clearTint());
}
白フラッシュフィルターよりもこれを優先してください — ドローコール1回で、フレームバッファーも不要です。
ライティング
this.lights.enable().setAmbientColor(0x333333);
const torch = this.lights.addLight(x, y, 200, 0xffaa33, 2);
オブジェクトはライティングをオプトインする必要があります。コンポーネントとノーマルマップの設定については references/lighting.md を参照してください。
コーンライト (4.2.0+)
懐中電灯、視界コーン、ヘッドライト、サーチライト。これらは同じライティングシェーダーを通して実行されます — マスクも、2つ目のカメラも、シーンを2回レンダリングすることもありません:
const beam = this.lights.addConeLight(
x, y,
300, // radius
0xffffff, // colour
2, // intensity
rotation, // radians — the direction the cone points
0.2, // inner angle, radians
0.6, // outer angle, radians
);
beam.setConeRotation(Phaser.Math.Angle.Between(px, py, mx, my));
beam.setConeAngles(0.15, 0.5);
beam.disableCone(); // back to a normal point light
すでに Phaser のライティングで照らされているオブジェクトは、コーンライトでも照らされます。これにより、ステルスゲームの視界コーンやトーチの仕組みが v3 のアプローチよりもはるかに安価になります。
パフォーマンス
フィルターはフレームバッファ操作です。それぞれが 1 回のレンダーパスであり、コストになるのはこのパスです。
- フラッシュや色の変化には、フィルターよりもティントを優先してください。 ティントは バッチの一部ですが、フィルターは別個のパスです。
- N 個のオブジェクトフィルターよりも、1 つのカメラフィルターを優先してください。 20 体の敵が それぞれグローを持つと、20 回分の追加パスになります。画面空間エフェクトを共有できるなら、 そちらを使うべきです。
- 両方とも動作する場合は、外部よりも内部が優先です — 内部はオブジェクトのサイズで レンダリングし、外部はキャンバス全体でレンダリングします。
- フィルターはミップマップ付きでは決してレンダリングしません。 フィルター出力による ミップマップベースのぼかしは期待しないでください(4.1.0 で、誤ってそうなっていた逆の バグが修正されました)。
- フィルターはフレームごとではなく、一度だけ有効化してください。
create()でenableFilters()を呼び、その後update()でコントローラーのプロパティを調整します。 毎フレームadd*を呼び出すと、フレームバジェットがなくなるまでフィルターが積み重なります — 起こりやすい偶発的なリークであり、ロジックのバグではなくパフォーマンスのバグのように 見えます。 - アルファストラテジーは
discardを使用します。 これは設計上非効率です。ditherとthresholdはエフェクト用およびステンシル用に存在するのであって、パフォーマンスを 引き上げる手段ではありません。
これらは目視ではなく、プレイテストハーネスで検証してください — フィルターのコストは
負荷時にフレームレートの崖として現れ、1 回の計測では見逃し、sample ステップなら捉えられます:
{ action: 'sample', expression: `game.loop.actualFps`,
duration: 3000, interval: 100, expect: { stat: 'min', atLeast: 50 } }
ヘッドレス FPS は数値ではなく比較として読んでください。 ハーネスは WebGL を SwiftShader 経由で実行し、フィルターこそソフトウェアレンダリングが最も苦手とするものです。 グロー、ビネット、カラーマトリクス、ライト付きパーティクルエミッターを備えたシーンは、 ヘッドレスでは約 12~20fps を計測しますが、実際の GPU では 60 で動作します。同じマシン上の 前回の実行と比較してください。フィルターを多用するシーンに絶対的なしきい値を設定しないで くださいし、ヘッドレスの数値をゲームのパフォーマンスとして報告しないでください。
Phaser 3 からの変換
| v3 | v4 |
|---|---|
sprite.preFX.addGlow() | sprite.enableFilters(); sprite.filters!.internal.addGlow() |
sprite.postFX.addBlur() | sprite.enableFilters(); sprite.filters!.external.addBlur() |
camera.postFX.addVignette() | camera.filters.external.addVignette()(有効化の手順は不要) |
new BitmapMask(...), setMask() | filters.internal.addMask(source) |
createGeometryMask() | カメラビューポート、または addMask() |
sprite.tintFill = true | sprite.setTintMode(Phaser.TintModes.FILL) |
setPipeline('X') | レンダーノード — customRenderNodes、RenderConfig#renderNodes |
| Bloom FX | Phaser.Actions.AddEffectBloom() |
| Shine FX | Phaser.Actions.AddEffectShine() |
| Circle FX | Phaser.Actions.AddMaskShape() |
| Gradient FX | Gradient ゲームオブジェクト |
colorMatrixFilter.sepia() | filter.colorMatrix.sepia() |
Mesh / Plane | Mesh2D(4.2.0 以降) |
コードがクリーンだと決めつける前に、移行用の grep を実行してください:
grep -rn "preFX\|postFX\|BitmapMask\|createGeometryMask\|tintFill\|setPipeline\|setScissor" src/
その他のリソース
リファレンスファイル
references/filters-api.md— すべてのフィルターについて、完全なパラメーターリスト、 実例、エフェクトごとの内部/外部の判断を掲載。references/lighting.md— ライティングモデル、法線マップ、コーンライト、Lightingコンポーネント、パフォーマンスの許容範囲。references/renderer-and-shaders.md— Beam、レンダーノード、カスタムシェーダー、Mesh2D、SpriteGPULayer、Stencil、CustomContext、アルファストラテジー。
関連
skills/phaser-migrate/— v3→v4 の完全な変更リストとリリースノートskills/phaser-particles/— パーティクルエフェクト。通常はこれらと組み合わせて使用しますskills/phaser-analyze/references/performance-playbook.md— エフェクトがフレームを消費する場合