Unityを触りはじめると、つい何でもかんでも Update() に書いてしまいがちですよね。「攻撃判定も」「エフェクトも」「UI更新も」全部ひとつのスクリプトで面倒を見ると、最初は楽ですが、あとから
・どこで何が起きているか分かりづらい
・似た処理を別キャラで使い回したいのにコピペ地獄になる
・ちょっとした仕様変更でも巨大クラスを開いてゴリゴリ修正…
といった問題が出てきます。

そこで今回は「攻撃ヒット時にスプライトを一瞬だけ真っ白にする」処理を、単機能のコンポーネントとして切り出した 「FlashWhite」コンポーネントを用意しました。
プレイヤーでも敵でも、SpriteRenderer を持っているオブジェクトにアタッチするだけで、「被弾時に白くフラッシュする」表現を簡単に再利用できます。

【Unity】被弾演出をコンポーネント化!「FlashWhite」コンポーネント

このコンポーネントは、次のような設計になっています。

  • 責務は「一時的にスプライトを白くする」だけ
  • 外部からは PlayFlash() を呼ぶだけでOK(攻撃ヒット時など)
  • SpriteRenderermaterial を一時的に差し替え → 一定時間後に元に戻す
  • 複数回連続ヒットしても破綻しないよう制御

ここでは 専用の「白フラッシュ用マテリアル」 を用意し、それに切り替える方式で実装します。
(URP/HDRP/ビルトインいずれでも、「Sprite用シェーダー+白テクスチャ or カラー指定」のマテリアルを作ればOKです)

FlashWhite.cs(フルコード)


using UnityEngine;

namespace Sample.Effects
{
    /// <summary>
    /// 攻撃ヒット時などに、スプライトを一瞬だけ真っ白にフラッシュさせるコンポーネント。
    /// 
    /// 責務は「白フラッシュ演出」のみ。
    /// ダメージ計算やノックバックなどは、別コンポーネントで行い、
    /// それらから public メソッド PlayFlash() を呼び出す想定です。
    /// </summary>
    [RequireComponent(typeof(SpriteRenderer))]
    public class FlashWhite : MonoBehaviour
    {
        // 白フラッシュに使うマテリアル(Sprite用シェーダーを利用したもの)
        [SerializeField]
        private Material flashMaterial;

        // フラッシュさせる時間(秒)
        [SerializeField]
        [Min(0.01f)]
        private float flashDuration = 0.08f;

        // フラッシュ中に点滅させたい場合のオプション(今回はシンプルに1回のみ)
        [SerializeField]
        private bool allowOverrideWhileFlashing = true;

        // 内部用:SpriteRenderer の参照
        private SpriteRenderer spriteRenderer;

        // 元のマテリアルを保持(フラッシュ終了後に戻す)
        private Material originalMaterial;

        // 現在フラッシュ中かどうか
        private bool isFlashing = false;

        // 残りフラッシュ時間
        private float remainingTime = 0f;

        private void Awake()
        {
            // 必須コンポーネントを取得
            spriteRenderer = GetComponent<SpriteRenderer>();

            // 実行中にマテリアルインスタンスが変わることもあるので、
            // Awake 時点での material を「元マテリアル」として保持しておきます。
            originalMaterial = spriteRenderer.material;

            // flashMaterial が未設定の場合は警告を出す
            if (flashMaterial == null)
            {
                Debug.LogWarning(
                    $"[FlashWhite] flashMaterial が設定されていません。白フラッシュは動作しません。 <GameObject: {gameObject.name}>",
                    this
                );
            }
        }

        private void OnEnable()
        {
            // 再有効化時に、念のため元のマテリアルに戻しておく
            ResetMaterial();
        }

        private void OnDisable()
        {
            // 無効化されるときも元に戻しておく(シーン切り替え時などの保険)
            ResetMaterial();
        }

        private void Update()
        {
            if (!isFlashing)
            {
                return;
            }

            remainingTime -= Time.unscaledDeltaTime; // タイムスケールに影響されないよう unscaled を使用

            if (remainingTime <= 0f)
            {
                EndFlash();
            }
        }

        /// <summary>
        /// 外部から呼び出す用の API。
        /// ダメージを受けた瞬間などで呼び出してください。
        /// </summary>
        public void PlayFlash()
        {
            // マテリアル未設定なら何もしない
            if (flashMaterial == null)
            {
                return;
            }

            // すでにフラッシュ中で、上書き禁止なら無視
            if (isFlashing && !allowOverrideWhileFlashing)
            {
                return;
            }

            StartFlashInternal();
        }

        /// <summary>
        /// フラッシュを開始する内部処理。
        /// </summary>
        private void StartFlashInternal()
        {
            // すでにフラッシュ中でも、ここに来た時点で上書き許可されている
            isFlashing = true;

            // フラッシュ時間をリセット
            remainingTime = flashDuration;

            // 現在の material を originalMaterial として再保持しておく
            // (他の処理でマテリアルが差し替えられている可能性に対応)
            originalMaterial = spriteRenderer.material;

            // フラッシュ用マテリアルに切り替え
            spriteRenderer.material = flashMaterial;
        }

        /// <summary>
        /// フラッシュ終了処理。
        /// </summary>
        private void EndFlash()
        {
            isFlashing = false;
            remainingTime = 0f;

            // 元のマテリアルに戻す
            ResetMaterial();
        }

        /// <summary>
        /// SpriteRenderer のマテリアルを元に戻す。
        /// </summary>
        private void ResetMaterial()
        {
            // originalMaterial が null の場合は何もしない
            if (spriteRenderer == null || originalMaterial == null)
            {
                return;
            }

            spriteRenderer.material = originalMaterial;
        }

#if UNITY_EDITOR
        private void OnValidate()
        {
            // インスペクター上で値を編集した時に、最低値を守るための保険
            if (flashDuration < 0.01f)
            {
                flashDuration = 0.01f;
            }
        }
#endif
    }
}

シェーダー/マテリアルについて

このスクリプトは「白く表示されるマテリアル」が 1 つあれば動作します。

  • ビルトインレンダーパイプラインなら、Sprites/Default シェーダーで Color = (1,1,1,1) にしたマテリアル
  • URP なら Universal Render Pipeline/2D/Sprite-Lit などで同様に真っ白カラーのマテリアル

「色を白に固定」しておくことで、元スプライトの色に関係なく白フラッシュさせられます。
(より凝った表現をしたい場合は、専用シェーダーで「白ブレンド」するのもアリです)


使い方の手順

ここでは「プレイヤーが敵に攻撃を当てたときに、敵が白フラッシュする」例で説明します。

  1. マテリアルを作成する
    • Project ウィンドウで右クリック → Create > Material
    • 名前を Mat_WhiteFlash などにする
    • Shader をスプライト用(例:Sprites/Default)に設定
    • Color を真っ白(R=1, G=1, B=1, A=1)に設定
  2. 敵キャラに FlashWhite をアタッチする
    • 敵プレハブ(またはシーン上の敵オブジェクト)を選択
    • Add Component から FlashWhite を追加
    • Flash Material に先ほど作成した Mat_WhiteFlash をドラッグ&ドロップ
    • Flash Duration は 0.05~0.1 秒くらいが分かりやすいです
  3. 攻撃ヒット時に PlayFlash() を呼び出す
    例えば、敵にアタッチされた「ダメージ処理コンポーネント」から呼ぶようにします。
    
    using UnityEngine;
    using Sample.Effects;
    
    public class EnemyHealth : MonoBehaviour
    {
        [SerializeField]
        private int maxHp = 10;
    
        private int currentHp;
    
        // 同じ GameObject に付いている FlashWhite を参照
        private FlashWhite flashWhite;
    
        private void Awake()
        {
            currentHp = maxHp;
            flashWhite = GetComponent<FlashWhite>();
        }
    
        // 例: プレイヤーの攻撃から呼ばれる想定
        public void TakeDamage(int damage)
        {
            currentHp -= damage;
    
            // HP が減ったら白フラッシュ
            if (flashWhite != null)
            {
                flashWhite.PlayFlash();
            }
    
            if (currentHp <= 0)
            {
                Die();
            }
        }
    
        private void Die()
        {
            // 死亡処理(アニメーション再生や Destroy など)
            Destroy(gameObject);
        }
    }
        
  4. プレイヤーの攻撃スクリプトから EnemyHealth.TakeDamage を呼ぶ
    例として、シンプルなトリガーヒット処理を示します。
    
    using UnityEngine;
    
    public class PlayerAttack : MonoBehaviour
    {
        [SerializeField]
        private int damage = 1;
    
        private void OnTriggerEnter2D(Collider2D other)
        {
            // 当たった相手に EnemyHealth があればダメージ
            EnemyHealth enemyHealth = other.GetComponent<EnemyHealth>();
            if (enemyHealth != null)
            {
                enemyHealth.TakeDamage(damage);
            }
        }
    }
        

    このように、「ダメージ計算」と「白フラッシュ演出」を別コンポーネントに分けることで、
    ・ダメージ処理だけ変えたい
    ・演出だけ変えたい/追加したい
    といったときにも柔軟に差し替えられます。


メリットと応用

FlashWhite をコンポーネントとして切り出すメリットはかなり大きいです。

  • プレハブ単位で演出を完結できる
    敵プレハブにあらかじめ FlashWhite を仕込んでおけば、
    シーン側では「敵を配置するだけ」で被弾演出が揃います。
    レベルデザイナーやステージ担当が、スクリプトに触らずに 演出付きの敵を量産できるのがポイントです。
  • 責務が明確なのでテストしやすい
    「白フラッシュがちゃんと戻るか」「連続ヒットで破綻しないか」などを、
    このコンポーネント単体に絞って確認できます。バグの切り分けがかなり楽になります。
  • 別キャラ・別エフェクトへの使い回しが容易
    プレイヤー、ボス、動くトラップなど、SpriteRenderer を持っているものなら何でも流用できます。
    「ボスだけフラッシュ時間を長くする」「ザコは短くする」といった調整もインスペクターから簡単です。

さらに、応用(改造)案として、例えば「フラッシュ強度をアニメーションカーブで変化させる」ようなバージョンも考えられます。
下のスニペットは、FlashWhite に追加することで「フラッシュを途中で手動キャンセルできる」機能の例です。


        /// <summary>
        /// 外部からフラッシュを強制終了させたい場合に呼び出す。
        /// 例: ダウン状態に入った瞬間にフラッシュを止める、など。
        /// </summary>
        public void StopFlash()
        {
            if (!isFlashing)
            {
                return;
            }

            EndFlash();
        }

このように、小さなコンポーネント単位で機能を分けておくと、
「必要になったときにだけ、ちょっとした API を足す」スタイルで安全に拡張していけます。
ぜひ自分のプロジェクトでも、「白フラッシュ専用コンポーネント」として取り入れてみてください。