Unity × DOTween × CanvasGroup で“実用的”なフェード付きシーン切り替え(拡張版)

2026年5月14日

広告

— シングルトン化&非同期ロード対応まで

事前準備:DOTween の導入

本記事のコードは DOTween(無料版で可) を使用します。まだ導入していない場合は、Unity Asset Store から「DOTween (HOTween v2)」をインポートしてください。

インポート後、メニュー Tools > Demigiant > DOTween Utility Panel を開き、「Setup DOTween…」ボタンを押して初期設定を完了させてください。この操作で DOTween Settings アセットが生成され、初期化が自動化されます。

⚠️ DOTween Utility Panel でセットアップ済みであれば、コード内で DOTween.Init() を呼ぶ必要はありません。

この記事でできること

  • 画面フェード(黒→表示/表示→黒)を 最小限のコード で実装
  • フェード中の誤入力をブロック
  • シングルトン化で全シーン共通のフェード管理
  • LoadSceneAsync でローディングにも対応(任意でインジケータ接続可)

なぜ CanvasGroup なのか

  • alpha を変えるだけで UI全体 を一括で透明化できる
  • blocksRaycasts を true にすれば、フェード中はタップ/クリックを遮断
  • DOTween の DOFade と相性がよく、1行でフェード を書ける

準備(FadePanel の作成)

  1. UI > Canvas を作る(Screen Space-Overlay 推奨)
  2. 子に UI > Image を追加し、全画面を覆う黒パネルにする。RectTransform をストレッチ(全方向アンカー)、Image.color は黒(#000、Alpha=1)
  3. 親(または同じオブジェクト)に CanvasGroup を追加。alpha = 1(最初は真っ黒)、interactable = true、blocksRaycasts = true
  4. この CanvasGroup を SceneFader にアサインする

実装:シングルトン+即戦力コード

どのシーンにも 1個だけ 置く(最初のシーンに配置)。以降のシーンには置かないでOK(DontDestroyOnLoad)。

using UnityEngine;
using UnityEngine.SceneManagement;
using DG.Tweening;

public class SceneFader : MonoBehaviour
{
    public static SceneFader Instance { get; private set; }

    [SerializeField] private CanvasGroup fadeCanvasGroup;
    [SerializeField] private float fadeDuration = 1.0f;
    [SerializeField] private bool fadeInOnSceneStart = true;

    bool isFading;

    void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;
        DontDestroyOnLoad(gameObject);

        // DOTween.Init() はここでは呼ばない。
        // DOTween Utility Panel(Tools > Demigiant > DOTween Utility Panel)で
        // 「Setup DOTween...」を実行済みであれば自動初期化されます。
    }

    void Start()
    {
        if (fadeInOnSceneStart)
        {
            fadeCanvasGroup.alpha = 1f;
            fadeCanvasGroup.blocksRaycasts = true;
            fadeCanvasGroup.DOFade(0f, fadeDuration)
                .OnComplete(() => fadeCanvasGroup.blocksRaycasts = false);
        }

        // ※ 下記を有効にすると FadeToSceneAsync 内の op.completed と二重になります。
        //    FadeToSceneAsync を使う場合は有効化しないでください。
        // SceneManager.sceneLoaded += (_, __) => FadeIn();
    }

    /// <summary>
    /// 同期ロード版(学習・小規模プロジェクト専用)
    /// 本番環境では FadeToSceneAsync を推奨。
    /// </summary>
    public void FadeToScene(string sceneName)
    {
        if (isFading) return;
        isFading = true;

        fadeCanvasGroup.DOFade(1f, fadeDuration)
            .OnStart(() => fadeCanvasGroup.blocksRaycasts = true)
            .OnComplete(() =>
            {
                SceneManager.LoadScene(sceneName);
                FadeIn();
            });
    }

    /// <summary>非同期ロード版(推奨)</summary>
    public void FadeToSceneAsync(string sceneName)
    {
        if (isFading) return;
        isFading = true;

        fadeCanvasGroup.DOFade(1f, fadeDuration)
            .OnStart(() => fadeCanvasGroup.blocksRaycasts = true)
            .OnComplete(() =>
            {
                var op = SceneManager.LoadSceneAsync(sceneName);
                op.completed += _ => FadeIn();
            });
    }

    /// <summary>外部からフェードインだけ使いたいとき用</summary>
    public void FadeIn()
    {
        fadeCanvasGroup.alpha = 1f;
        fadeCanvasGroup.DOFade(0f, fadeDuration)
            .OnComplete(() =>
            {
                fadeCanvasGroup.blocksRaycasts = false;
                isFading = false;
            });
    }
}

ここがポイント

  • 多重実行防止:isFading で二度押し・連打を無効化
  • 入力制御:フェード中は blocksRaycasts = true で誤操作を遮断
  • 即フェードイン:シーン切替直後に FadeIn() を呼んで自然な復帰
  • 非同期版推奨:LoadSceneAsync はローディングUIと組み合わせやすい

呼び出し例(ボタンから)

using UnityEngine;

public class TitleMenu : MonoBehaviour
{
    public void OnClickStart()
    {
        // 小規模なら同期版でもOK(学習用途)
        // SceneFader.Instance.FadeToScene("GameScene");

        // 実運用は非同期版推奨
        SceneFader.Instance.FadeToSceneAsync("GameScene");
    }
}

Button.onClick に OnClickStart を登録。


よくある落とし穴

  • フェードが見えない→ FadePanel の Image.color が黒・パネルが最前面・CanvasのSort順が適切か確認
  • クリックが貫通する→ フェード中に blocksRaycasts = true にしているか
  • 二重ロードされる→ isFading でガードしているか
  • シーンに複数の SceneFader→ 最初のシーンだけに置き、以降のシーンには置かない(Awake()で重複破棄)
  • フェードインが2回走る→ Start() の SceneManager.sceneLoaded と FadeToSceneAsync の op.completed を同時に有効にしていないか確認

拡張アイデア(必要に応じて)

  • ローディングスピナー連携:FadeToSceneAsync 内で op.progress をポーリング表示
  • 色・曲線のカスタム:DOFade に SetEase(Ease.InOutQuad) など
  • イベント通知:UnityEvent onFadeOutStarted / onFadeInCompleted を公開し、BGMのフェード等と同期

まとめ

  • CanvasGroup × DOTween で最短のフェード実装
  • シングルトン化で全シーン共通の入口を1本化
  • 非同期ロード対応でローディングUXも整う
  • フェード中は blocksRaycasts で安全に入力を遮断
  • DOTween.Init() はコード内で呼ばず、DOTween Utility Panel でのセットアップに任せる
訪問数 53 回, 今日の訪問数 1回

広告

C#

Posted by hidepon