Unityを触りはじめると、つい何でもかんでも Update() に書いてしまいがちですよね。「攻撃判定も」「エフェクトも」「UI更新も」全部ひとつのスクリプトで面倒を見ると、最初は楽ですが、あとから
・どこで何が起きているか分かりづらい
・似た処理を別キャラで使い回したいのにコピペ地獄になる
・ちょっとした仕様変更でも巨大クラスを開いてゴリゴリ修正…
といった問題が出てきます。
そこで今回は「攻撃ヒット時にスプライトを一瞬だけ真っ白にする」処理を、単機能のコンポーネントとして切り出した 「FlashWhite」コンポーネントを用意しました。
プレイヤーでも敵でも、SpriteRenderer を持っているオブジェクトにアタッチするだけで、「被弾時に白くフラッシュする」表現を簡単に再利用できます。
【Unity】被弾演出をコンポーネント化!「FlashWhite」コンポーネント
このコンポーネントは、次のような設計になっています。
- 責務は「一時的にスプライトを白くする」だけ
- 外部からは
PlayFlash()を呼ぶだけでOK(攻撃ヒット時など) SpriteRendererのmaterialを一時的に差し替え → 一定時間後に元に戻す- 複数回連続ヒットしても破綻しないよう制御
ここでは 専用の「白フラッシュ用マテリアル」 を用意し、それに切り替える方式で実装します。
(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などで同様に真っ白カラーのマテリアル
「色を白に固定」しておくことで、元スプライトの色に関係なく白フラッシュさせられます。
(より凝った表現をしたい場合は、専用シェーダーで「白ブレンド」するのもアリです)
使い方の手順
ここでは「プレイヤーが敵に攻撃を当てたときに、敵が白フラッシュする」例で説明します。
-
マテリアルを作成する
- Project ウィンドウで右クリック →
Create > Material - 名前を
Mat_WhiteFlashなどにする - Shader をスプライト用(例:
Sprites/Default)に設定 - Color を真っ白(R=1, G=1, B=1, A=1)に設定
- Project ウィンドウで右クリック →
-
敵キャラに FlashWhite をアタッチする
- 敵プレハブ(またはシーン上の敵オブジェクト)を選択
Add ComponentからFlashWhiteを追加Flash Materialに先ほど作成したMat_WhiteFlashをドラッグ&ドロップFlash Durationは 0.05~0.1 秒くらいが分かりやすいです
-
攻撃ヒット時に 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); } } -
プレイヤーの攻撃スクリプトから 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 を足す」スタイルで安全に拡張していけます。
ぜひ自分のプロジェクトでも、「白フラッシュ専用コンポーネント」として取り入れてみてください。
