【Cocos Creator】アタッチするだけ!FlashWhite (ヒット閃光)の実装方法【TypeScript】

【Cocos Creator 3.8】FlashWhite(ヒット閃光)の実装:アタッチするだけで「ヒット時にスプライトを一瞬だけ真っ白にする」汎用スクリプト

このガイドでは、任意の Sprite / SpriteFrame を持つノードにアタッチするだけで、攻撃ヒット時などに一瞬だけ真っ白にフラッシュさせる汎用コンポーネント FlashWhite を実装します。

ヒットエフェクトや被ダメージ演出を作る際に、コードからメソッドを1回呼ぶだけで「白フラッシュ」が実行できるようになり、アニメーションやタイムラインを都度組む必要がなくなります。


コンポーネントの設計方針

機能要件の整理

  • 対象ノードに Sprite または UI / 2D マテリアルを持つレンダラーが存在すること。
  • ヒットしたタイミングで flash() を呼ぶと、一瞬だけ白くなり、徐々に元の見た目に戻る
  • 白さ(強さ)と継続時間、イージング(線形 or カーブ)などを Inspector から調整できる。
  • 外部の GameManager やシングルトンに依存せず、このコンポーネント単体で完結する。
  • マテリアルに依存しすぎないようにしつつ、標準マテリアルでも動作させる。
  • 防御的実装:必要なコンポーネント(Sprite など)が無い場合は error ログを出して、動作をスキップする。

シェーダー(マテリアル)へのアプローチ

「真っ白にする」には、以下の2通りの方法があります。

  1. 専用シェーダーを用意し、白フラッシュ用の uniform を操作する方法
  2. 標準 Sprite マテリアルの color を操作して白くする方法

このガイドでは、追加のカスタムシェーダーを用意しなくても使えるようにするため、基本は Sprite の color を操作して白フラッシュを再現します。

  • 開始時に Sprite の元の色(originalColor)を保存。
  • フラッシュ中は Color.lerp(originalColor, Color.WHITE, t) のように補間。
  • t0 → flashIntensity まで上げてから、flashIntensity → 0 に戻す。

この方法なら、標準の Sprite マテリアルだけで完結し、どのプロジェクトにもそのまま持ち込めます。

Inspector で設定可能なプロパティ設計

FlashWhite コンポーネントでは、以下のプロパティを Inspector から調整できるようにします。

  • targetNode: Node | null
    • フラッシュさせたいノード。未指定なら このコンポーネントがアタッチされたノード自身を対象にする。
    • Sprite を持つ子ノードなどを指定したい場合に使用。
  • flashDuration: number
    • 1回のフラッシュの合計時間(秒)。
    • 例: 0.15 ~ 0.3 あたりが一般的なヒットエフェクトに向く。
  • flashIntensity: number
    • 白さの強さ(0.0 ~ 1.0)。
    • 0.0 で変化なし、1.0 で完全に白。
    • 例: 0.7 くらいにすると、少しだけ色味を残した白フラッシュになる。
  • autoResetColor: boolean
    • 有効にすると、フラッシュ完了時に 必ず元の色に戻す
    • 無効にすると、連続フラッシュ中に中途半端な色で止まる可能性があるが、特殊な演出に使える。
  • allowStacking: boolean
    • 有効: フラッシュ中に再度 flash() を呼ぶと、タイマーをリセットして即座に再フラッシュ
    • 無効: フラッシュ中の再呼び出しは無視する。
  • curveType: ‘LINEAR’ | ‘EASE_OUT’ | ‘EASE_IN_OUT’(enum)
    • 白さの減衰カーブ。
    • LINEAR: 一定速度で白→元の色。
    • EASE_OUT: 最初は速く白くなり、ゆっくり戻る。
    • EASE_IN_OUT: なめらかに白くなり、なめらかに戻る。

呼び出し方は非常にシンプルで、任意のスクリプトから次のように呼ぶだけです。

// 例: ヒット判定スクリプト内
const flash = this.node.getComponent(FlashWhite);
flash?.flash();  // これだけで白フラッシュ

TypeScriptコードの実装

以下が、Cocos Creator 3.8.7 / TypeScript 用の完全な FlashWhite コンポーネントです。


import { _decorator, Component, Node, Sprite, Color, Enum } from 'cc';
const { ccclass, property } = _decorator;

/**
 * 白フラッシュの減衰カーブタイプ
 */
enum FlashCurveType {
    LINEAR = 0,
    EASE_OUT = 1,
    EASE_IN_OUT = 2,
}

Enum(FlashCurveType);

@ccclass('FlashWhite')
export class FlashWhite extends Component {

    @property({
        type: Node,
        tooltip: 'フラッシュさせたい対象ノード。\n未指定の場合、このコンポーネントが付いているノード自身を対象にします。'
    })
    public targetNode: Node | null = null;

    @property({
        tooltip: '1回のフラッシュにかける合計時間(秒)。\n例: 0.15 ~ 0.3 あたりが一般的です。'
    })
    public flashDuration: number = 0.2;

    @property({
        tooltip: '白さの強さ(0.0 ~ 1.0)。\n0.0 で変化なし、1.0 で完全に白になります。'
    })
    public flashIntensity: number = 1.0;

    @property({
        tooltip: 'フラッシュが終わったときに必ず元の色に戻すかどうか。\n通常は ON のままを推奨します。'
    })
    public autoResetColor: boolean = true;

    @property({
        tooltip: 'フラッシュ中に再度 flash() が呼ばれたときの挙動。\nON: タイマーをリセットして再フラッシュ。\nOFF: フラッシュ中の呼び出しは無視します。'
    })
    public allowStacking: boolean = true;

    @property({
        type: FlashCurveType,
        tooltip: '白さの減衰カーブタイプ。\nLINEAR: 一定速度で白から戻る。\nEASE_OUT: 最初に強く、徐々に元に戻る。\nEASE_IN_OUT: なめらかに白くなり、なめらかに戻ります。'
    })
    public curveType: FlashCurveType = FlashCurveType.EASE_OUT;

    // 内部状態
    private _sprite: Sprite | null = null;
    private _originalColor: Color | null = null;
    private _isFlashing = false;
    private _elapsed = 0;

    onLoad() {
        // 対象ノードが指定されていなければ、自分自身を対象にする
        const node = this.targetNode ?? this.node;

        // Sprite コンポーネントを取得
        this._sprite = node.getComponent(Sprite);

        if (!this._sprite) {
            console.error(
                '[FlashWhite] 対象ノードに Sprite コンポーネントが見つかりません。',
                '\n対象ノード:', node.name,
                '\nFlashWhite を使用するには、対象ノードに Sprite を追加してください。'
            );
            return;
        }

        // 元の色を保存
        this._originalColor = this._sprite.color.clone();
    }

    start() {
        // 念のため、start 時にも元色を再保存(onLoad 時に色を変更している場合に対応)
        if (this._sprite && this._originalColor == null) {
            this._originalColor = this._sprite.color.clone();
        }
    }

    update(deltaTime: number) {
        if (!this._isFlashing || !this._sprite || !this._originalColor) {
            return;
        }

        // 経過時間を更新
        this._elapsed += deltaTime;

        // 終了判定
        if (this._elapsed >= this.flashDuration) {
            this._isFlashing = false;
            this._elapsed = 0;

            if (this.autoResetColor) {
                // 最後に元の色へ完全に戻す
                this._sprite.color = this._originalColor.clone();
            }

            return;
        }

        // 0.0 ~ 1.0 の正規化時間
        const t = this._elapsed / this.flashDuration;

        // カーブに応じた係数を計算
        const factor = this._evaluateCurve(t);

        // factor を 0.0 ~ flashIntensity にスケール
        const intensity = this.flashIntensity * factor;

        // intensity = 0 のとき: originalColor
        // intensity = 1 のとき: Color.WHITE
        const newColor = new Color();
        Color.lerp(newColor, this._originalColor, Color.WHITE, intensity);

        this._sprite.color = newColor;
    }

    /**
     * 外部から呼び出して白フラッシュを開始するメソッド。
     * 例: this.node.getComponent(FlashWhite)?.flash();
     */
    public flash(): void {
        if (!this._sprite) {
            console.warn('[FlashWhite] Sprite が見つからないため flash() を実行できません。');
            return;
        }

        if (!this._originalColor) {
            this._originalColor = this._sprite.color.clone();
        }

        // 既にフラッシュ中で stacking を許可しない場合は無視
        if (this._isFlashing && !this.allowStacking) {
            return;
        }

        // タイマーをリセットしてフラッシュ開始
        this._isFlashing = true;
        this._elapsed = 0;
    }

    /**
     * 現在のフラッシュを強制終了し、元の色に戻します。
     */
    public stopFlash(): void {
        if (!this._sprite || !this._originalColor) {
            return;
        }

        this._isFlashing = false;
        this._elapsed = 0;
        this._sprite.color = this._originalColor.clone();
    }

    /**
     * 0~1 の t に対して、選択されたカーブに応じた係数を返す。
     */
    private _evaluateCurve(t: number): number {
        switch (this.curveType) {
            case FlashCurveType.LINEAR:
                return 1.0 - t; // 単純に線形で減衰

            case FlashCurveType.EASE_OUT:
                // t が進むほどゆっくり減衰(イージングアウト)
                // f(t) = 1 - (1 - t)^2
                return 1.0 - (1.0 - t) * (1.0 - t);

            case FlashCurveType.EASE_IN_OUT:
                // なめらかな S 字カーブ
                // f(t) = 0.5 * (1 - cos(pi * t))
                return 0.5 * (1.0 - Math.cos(Math.PI * t));

            default:
                return 1.0 - t;
        }
    }

    /**
     * Editor 上でノードが無効化されたり、シーン遷移などで破棄されるときに
     * 可能なら元の色に戻しておく(安全策)。
     */
    onDisable() {
        if (this._sprite && this._originalColor && this.autoResetColor) {
            this._sprite.color = this._originalColor.clone();
        }
        this._isFlashing = false;
        this._elapsed = 0;
    }
}

コードのポイント解説

  • onLoad
    • targetNode が未設定なら、自身のノードを対象にする。
    • 対象ノードから Sprite を取得し、存在しなければ console.error で明示的に通知。
    • Sprite があれば、その color をクローンして _originalColor に保存。
  • update
    • _isFlashingtrue のときだけ処理を行う。
    • _elapseddeltaTime を足して、flashDuration と比較して終了判定。
    • 終了時には autoResetColortrue なら必ず元の色に戻す。
    • 進行度 t = elapsed / flashDuration を計算し、_evaluateCurve で 0~1 の係数に変換。
    • Color.lerp を使い、originalColor から Color.WHITE へ補間。
  • flash()
    • 外部から呼び出す公開メソッド。
    • Sprite が無い場合は警告を出し、何もしない。
    • 既にフラッシュ中で allowStacking = false の場合は再実行しない。
    • それ以外の場合は _isFlashing = true とし、_elapsed = 0 でタイマーリセット。
  • stopFlash()
    • 外部から強制的にフラッシュを終了させたいときに使用。
    • 元の色に戻し、内部状態をリセット。
  • onDisable()
    • ノードが無効化される/シーンがアンロードされるときに呼ばれる。
    • 安全策として、autoResetColor が有効なら元の色に戻す。

使用手順と動作確認

1. スクリプトファイルの作成

  1. エディタ上部メニュー、または Assets パネルで操作します。
    • Assets パネルで 右クリック → Create → TypeScript を選択。
    • ファイル名を FlashWhite.ts に変更します。
  2. 作成した FlashWhite.ts をダブルクリックしてエディタ(VSCode など)で開き、中身をすべて削除して、上記のコードを丸ごと貼り付けます。
  3. 保存します。

2. テスト用ノード(Sprite)の作成

  1. Hierarchy パネルで 右クリック → Create → 2D Object → Sprite を選択し、テスト用のスプライトノードを作成します。
  2. 作成されたノードを選択し、Inspector で以下を確認します。
    • Sprite コンポーネントが追加されていること。
    • Sprite の SpriteFrame に画像が設定されていること(任意の画像で可)。

3. FlashWhite コンポーネントをアタッチ

  1. テスト用の Sprite ノードを選択した状態で、Inspector 下部の 「Add Component」 ボタンをクリックします。
  2. 「Add Component → Custom → FlashWhite」 を選択します。
    • Custom の中に見つからない場合は、スクリプトのコンパイルがまだ終わっていない可能性があるので、少し待つかエディタを再起動してください。
  3. Inspector に FlashWhite コンポーネントが追加されたことを確認します。

4. プロパティの設定例

Inspector 上で、FlashWhite の各プロパティを次のように設定してみます。

  • Target Node: 空欄(None)のまま
    • → 自身の Sprite ノードが自動的に対象になります。
  • Flash Duration: 0.2
  • Flash Intensity: 1.0
  • Auto Reset Color: チェック ON
  • Allow Stacking: チェック ON
  • Curve Type: EASE_OUT

5. フラッシュを実行する簡単なテストスクリプト

エディタ上で動作を確認するために、スペースキーを押したときにフラッシュするテストスクリプトを用意します。

  1. Assets パネルで 右クリック → Create → TypeScript を選択し、FlashWhiteTester.ts を作成。
  2. 以下のコードを貼り付けます。

import { _decorator, Component, input, Input, EventKeyboard, KeyCode } from 'cc';
import { FlashWhite } from './FlashWhite';
const { ccclass } = _decorator;

@ccclass('FlashWhiteTester')
export class FlashWhiteTester extends Component {

    private _flash: FlashWhite | null = null;

    onLoad() {
        this._flash = this.node.getComponent(FlashWhite);
        if (!this._flash) {
            console.error('[FlashWhiteTester] FlashWhite コンポーネントが同じノードに見つかりません。');
        }
    }

    start() {
        input.on(Input.EventType.KEY_DOWN, this._onKeyDown, this);
    }

    onDestroy() {
        input.off(Input.EventType.KEY_DOWN, this._onKeyDown, this);
    }

    private _onKeyDown(event: EventKeyboard) {
        if (event.keyCode === KeyCode.SPACE) {
            this._flash?.flash();
        }
    }
}

テスターのアタッチ

  1. 先ほど FlashWhite を付けた Sprite ノードを選択します。
  2. Inspector の Add Component → Custom → FlashWhiteTester を選択して追加します。
  3. FlashWhiteTester は特にプロパティ設定不要です(同じノードの FlashWhite を自動取得します)。

6. 再生して動作確認

  1. エディタ上部の 「▶︎」(Play) ボタンを押して、ゲームをプレビューします。
  2. ゲームビューがフォーカスされている状態で、スペースキー を押します。
  3. Sprite が 一瞬だけ真っ白になり、すぐに元の色に戻れば成功です。
  4. 連打しても、allowStacking の設定に応じて挙動が変わることを確認してみてください。
    • ON の場合: 連打すると何度もフラッシュ。
    • OFF の場合: フラッシュ中は無視される。

7. 実際のゲームコードへの組み込み例

攻撃スクリプトやダメージ判定スクリプトからは、次のように呼び出します。


// 例: 敵がダメージを受けたとき
import { _decorator, Component } from 'cc';
import { FlashWhite } from './FlashWhite';
const { ccclass } = _decorator;

@ccclass('Enemy')
export class Enemy extends Component {

    private _flash: FlashWhite | null = null;

    onLoad() {
        this._flash = this.node.getComponent(FlashWhite);
    }

    public takeDamage(amount: number) {
        // HP 処理など...

        // 白フラッシュを実行
        this._flash?.flash();
    }
}

このように、FlashWhite をアタッチしておけば、どのスクリプトからでも簡単にヒット閃光を呼び出せます


まとめ

  • FlashWhite コンポーネントは、Sprite を持つ任意のノードにアタッチするだけで、攻撃ヒット時の白フラッシュ演出を簡単に追加できます。
  • 外部の GameManager やシングルトンに依存せず、この1ファイルだけで完結するため、プロジェクト間の持ち回りも容易です。
  • Inspector から
    • フラッシュ時間(flashDuration
    • 白さの強さ(flashIntensity
    • 減衰カーブ(curveType
    • スタック許可(allowStacking

    を調整できるので、アーティストやレベルデザイナーが見た目を直接チューニングできます。

  • 標準の Sprite マテリアルと Color 操作のみで実現しているため、追加のシェーダーファイル不要で導入が容易です。

このコンポーネントをベースに、例えば「赤フラッシュ」「透明度を落とす被ダメージ演出」「点滅」なども同様のパターンで汎用スクリプト化できます。
攻撃・被弾エフェクト周りをコンポーネントとして切り出しておくことで、複数キャラクターや敵への演出の横展開が非常に楽になるので、ぜひプロジェクトの共通ライブラリとして活用してみてください。

Godot 4ゲーム制作 実践ドリル 100本ノック

新品価格
¥1,250から
(2025/12/13 21:27時点)

脱・初心者!Godot 4 ゲーム開発の「2歩目」

新品価格
¥831から
(2025/12/13 21:29時点)

Godot4ローグライク開発入門 ~ダンジョン自動生成~

新品価格
¥831から
(2025/12/13 21:33時点)

URLをコピーしました!