Unity × DOTween × CanvasGroup で“実用的”なフェード付きシーン切り替え(拡張版)
— シングルトン化&非同期ロード対応まで
目次
この記事でできること
- 画面フェード(黒→表示/表示→黒)を 最小限のコード で実装
- フェード中の誤入力をブロック
- シングルトン化で全シーン共通のフェード管理
- LoadSceneAsync でローディングにも対応(任意でインジケータ接続可)
なぜ CanvasGroup なのか
- alpha を変えるだけで UI全体 を一括で透明化できる
- blocksRaycasts を true にすれば、フェード中はタップ/クリックを遮断
- DOTween の DOFade と相性がよく、1行でフェード を書ける
準備(FadePanel の作成)
- UI > Canvas を作る(Screen Space-Overlay 推奨)
- 子に UI > Image を追加し、全画面を覆う黒パネルにする
- RectTransform をストレッチ(全方向アンカー)
- Image.color は黒(#000、Alpha=1)
- 親(または同じオブジェクト)に CanvasGroup を追加
- alpha = 1(最初は真っ黒)
- interactable = true
- blocksRaycasts = true
- この 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 初期化
DOTween.Init(recycleAllByDefault: false, useSafeMode: true);
}
void Start()
{
// 起動直後のフェードイン
if (fadeInOnSceneStart)
{
fadeCanvasGroup.alpha = 1f;
fadeCanvasGroup.blocksRaycasts = true;
fadeCanvasGroup.DOFade(0f, fadeDuration)
.OnComplete(() => fadeCanvasGroup.blocksRaycasts = false);
}
// シーンロード完了時に自動フェードインしたい場合は下記を有効化
// SceneManager.sceneLoaded += (_, __) => FadeIn();
}
/// <summary>同期ロード版(軽量プロジェクト向け)</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()で重複破棄)
拡張アイデア(必要に応じて)
- ローディングスピナー連携:FadeToSceneAsync 内で op.progress をポーリング表示
- 色・曲線のカスタム:DOFade に SetEase(Ease.InOutQuad) など
- イベント通知:UnityEvent onFadeOutStarted / onFadeInCompleted を公開し、BGMのフェード等と同期
まとめ
- CanvasGroup × DOTween で最短のフェード実装
- シングルトン化で全シーン共通の入口を1本化
- 非同期ロード対応でローディングUXも整う
- フェード中は blocksRaycasts で安全に入力を遮断
訪問数 5 回, 今日の訪問数 5回






ディスカッション
コメント一覧
まだ、コメントがありません