【Unity】フェードイン・アウトを考える

2022/10/20追記
2022/10/21新しく処理を追記


いよいよ2019始動しました。

去年からUnityの勉強を復活してボチボチ進めてきたのですが、
スクリプトも少し書けるようになってきたので、今年こそは”リリース”を目標に
頑張って行こうと思います。

平成も終わりを迎えるので、
新元号になる前に1本くらいはリリースできるといいのですが…



今年の最初の記事は、フェードイン・アウトの実装です。
今どきフェードイン・アウトの無いゲームは少ないので、
実装は必須かと思います。

フェードイン・アウトと言っても、いろいろな方法があります。

今回は、スクリプトの勉強も兼ねて自作に挑戦してみようと思います。


準備として
Android用の画面を用意
シーン移動用のボタン設置

ここからフェード用のパネルを追加します。
フェード2.jpg
PanelはCanvasサイズに依存するので、自動的にCanvasと同じ大きさになります。

追加したパネルのcollarをクリックするとパレットが開きます。
フェード3.jpg
パレットのA(alpha値)を操作すると透明度が変わるので
これをスクリプトから操作すればフェードができるかと思います。
最初はフェードインさせたいのでA値を255にしておきます。


まずは、フェードインのスクリプトを考えてみます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class FadeManager : MonoBehaviour {


public GameObject Panelfade; //フェードパネルの取得

Image fadealpha; //フェードパネルのイメージ取得変数

private float alpha; //パネルのalpha値取得変数

// Use this for initialization
void Start () {
fadealpha = Panelfade.GetComponent<Image>(); //パネルのイメージ取得
alpha = fadealpha.color.a; //パネルのalpha値を取得
}

// Update is called once per frame
void Update () {

alpha -= 0.01f;
fadealpha.color = new Color(0, 0, 0, alpha);
}
}

まずImageを操作するのでusing UnityEngine.UIが必要になります。

A値はスクリプト上から操作する時、Rangeとして入力する必要があります。
Rangeは0~1の間なので注意が必要です。

フレーム毎に0.01づつ数値を下げて行くようにしています。
この減算値を変えればフェードスピードが変わります。


一応フェードインの感触は掴めたのですが、
このままでは、問題点があります。

・alpha値の計算が無限ループしている
・パネルが最前列にあるのでボタン操作ができない

問題点を修正していきます。

まずalpha値の無限ループを止めるためにフラグを用意します。
フラグが立っている間だけフェードするようして、
alpha値が0になったらパネルを消すようにします。

public class FadeManager : MonoBehaviour {


public GameObject Panelfade; //フェードパネルの取得

Image fadealpha; //フェードパネルのイメージ取得変数

private float alpha; //パネルのalpha値取得変数

private bool fadein; //フェードインのフラグ用変数


// Use this for initialization
void Start () {
fadealpha = Panelfade.GetComponent<Image>(); //パネルのイメージ取得
alpha = fadealpha.color.a; //パネルのalpha値を取得
fadein = true; //シーン読み込み時にフェードインさせる
}

// Update is called once per frame
void Update () {
if (fadein == true)
{
FadeIn();
}
}

void FadeIn()
{
alpha -= 0.01f;
fadealpha.color = new Color(0, 0, 0, alpha);
if (alpha <= 0)
{
fadein = false;
Panelfade.SetActive(false);
}
}
}

これでパネルが透明になったら計算のループをストップして
パネルを消す事ができます。


これでフェードインは出来るようになったので、
フェードアウトを考えてみます。

フェードアウト時に必要になるのは、
・Panelfade呼び出し
・画面の移動メソッド
・フェードアウトのフラグ
・フェードアウトのメソッド

これを形にすると

void FadeOut()
{
alpha += 0.01f;
fadealpha.color = new Color(0, 0, 0, alpha);
if (alpha >= 1)
{
fadeout = false;
SceneManager.LoadScene("Fade" + SceneNo);
}
}

public void SceneMove()
{
fadeout = true;
Panelfade.SetActive(true);
}

少し説明すると、Sceneの名前をFade1とFade2としています。
SceneMoveメソッドをボタンに割り当ててフェードアウトのフラグとPanelfadeを呼び出します。

Unity上で移動先Sceneのナンバーを入力できるようにして、
Update関数からフェードアウトのフラグを検知できるようにすれば完成です。

最終的にできたのがこちら

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class FadeManager : MonoBehaviour
{


public GameObject Panelfade; //フェードパネルの取得

Image fadealpha; //フェードパネルのイメージ取得変数

private float alpha; //パネルのalpha値取得変数

private bool fadeout; //フェードアウトのフラグ変数
private bool fadein;    //フェードインのフラグ変数

public int SceneNo; //シーンの移動先ナンバー取得変数


// Use this for initialization
void Start()
{
fadealpha = Panelfade.GetComponent<Image>(); //パネルのイメージ取得
alpha = fadealpha.color.a; //パネルのalpha値を取得
fadein = true; //シーン読み込み時にフェードインさせる
}

// Update is called once per frame
void Update()
{

if (fadein == true)
{
FadeIn();
}

if (fadeout == true)
{
FadeOut();
}
}

void FadeIn()
{
alpha -= 0.01f;
fadealpha.color = new Color(0, 0, 0, alpha);
if (alpha <= 0)
{
fadein = false;
Panelfade.SetActive(false);

}
}

void FadeOut()
{
alpha += 0.01f;
fadealpha.color = new Color(0, 0, 0, alpha);
if (alpha >= 1)
{
fadeout = false;
SceneManager.LoadScene("Fade" + SceneNo);
}
}

public void SceneMove()
{
fadeout = true;
Panelfade.SetActive(true);
}
}

スクリプトができたので、エディターでSceneを追加しFade2とします。

移動先のSceneナンバーを設定したらプレイです。


無事にフェードイン・アウトするようになりました。
フェードパネル単体で稼働させるようにすれば、Game部分のスクリプトと分離できるかと

ざっくりと作ったので、まだまだ修正できる部分があるかと思います。

上のスクリプトをコピペするとfadealpha = Panelfade.GetComponent<Image>();
Imageを挟む<>が全角になっているのでエラーが掛かります。

半角の<>にすると消えてしまうので、全角で書いています。


このくらい修正できないでどうするの(~-~;)ヾ(-_-;) オイオイ
まだまだ先が思いやられます。
【><。】 エーン


2019/5/11更新
コード内の<>を半角に修正しました。
コピペしても大丈夫かと思います。


2022/10/20追記
シーン移動時のフェードを簡単に行えるAsset、
FadeCamera2を新記事にて紹介しています。

FadeCamera2 シーン移動時の演出クリックするとページが開きます。

フェードだけでなく、ルール画像を使った演出ができるので、
おすすめのAssetになります。


2022/10/21新規スクリプト更新

記事を読み返して、
説明不足・スクリプトの修正が必要と感じたので、
新しく処理を作りました。

以下にまとめます。

・シーンの作成
フェード①.jpg
Androidプラットフォームで作成しています。

Canvasを追加して、
・背景Image
・シーン遷移ボタン
・シーン名テキスト
・パネル

Canvas内に4つのUIを設定しました。

パネルは、フェード用なので、他のUIより前面に配置します。
これをFade1シーンとして保存します。

続いて、シーン追加からFade2シーンを作成します。
フェード②.jpg
Fade1と同じ構成で、シーンを作ります。
背景は、分かりやすいように色を変えておきます。

各シーン、真ん中のボタンを押すとフェード処理後にシーンを移動させます。

UIの準備ができたので、スクリプトを作成します。
新規スクリプトを立ち上げて、FadeManagerとしておきます。
FadeManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class FadeManager : MonoBehaviour
{
[SerializeField]
private GameObject panelFade; //フェードパネル

[SerializeField,Range(0,1)]
private float alpha; //アルファ値、0~1にRangeを設定

private Image panel_fadeImage; //フェードパネルのImage

private bool fadeout, fadein; //フェードのフラグ

private int scenNumber; //シーンナンバー


// Start is called before the first frame update
void Start()
{
panel_fadeImage = panelFade.GetComponent<Image>();
PanelEnabled();

FadeIn();
}

// Update is called once per frame
void Update()
{
if (fadein)
FadeInOperation();

if (fadeout)
FadeOutOperation();
}

//フェードイン呼び出し
private void FadeIn()
{
if (alpha != 1)
alpha = 1f;

fadein = true;
}

//フェードアウト呼び出し
private void FadeOut()
{
if (alpha != 0)
alpha = 0f;

fadeout = true;
}

//フェードイン操作
private void FadeInOperation()
{
alpha -= 0.01f;

var tempColor = panel_fadeImage.color;

tempColor.a = alpha;
panel_fadeImage.color = tempColor;

PanelEnabled();

if (alpha <= 0)
fadein = false;

}

//フェードアウト操作とシーン遷移
private void FadeOutOperation()
{
alpha += 0.01f;

var tempColor = panel_fadeImage.color;

tempColor.a = alpha;
panel_fadeImage.color = tempColor;

PanelEnabled();

if (alpha >= 1)
{
fadeout = false;
SceneManager.LoadScene("Fade" + scenNumber);
}
}

//フェードパネルの表示状態管理
private void PanelEnabled()
{
if (alpha <= 0)
panelFade.SetActive(false);

else
panelFade.SetActive(true);
}

//シーン遷移時のボタン操作
public void SceneMove(int num)
{
scenNumber = num;
FadeOut();
}
}

以前の処理で足りなかった部分を追加しました。

足りなかった点
・FadePanelをOFFにする処理が、FadeIn関数内にしか無かった
・alpha値が0~1の間で止まった場合の処理がない


FadePaneの表示・非表示
フェードイン・アウトは、全面に設定したパネルの透明度を操作する事で、
フェード処理を行っています。

パネルが表示状態だと、パネルより後面のUIにアクセスできません。
ボタンやEventTriggerを設定する場合は、パネルを非表示にする必要があります。

以前の処理では、FadeInさせた時だけパネルが非表示になる仕様だったので、
処理を追加しました。

//フェードパネルの表示状態管理
private void PanelEnabled()
{
if (alpha <= 0)
panelFade.SetActive(false);

else
panelFade.SetActive(true);
}

alpha値を使って、パネルの表示・非表示をコントロールします。
0以下なら非表示。
0より大きければ表示。

この関数を、Start内から呼び出します。
シーン開始時は、alpha値が0から始まるので、自動的にパネルを非表示にしてくれます。
これで、FadeIn関数を使わなくても、パネルがない状態でスタートできます。

以前の処理では、フェード処理中にパネルは表示されてる前提で処理していたので、
新しく、alpha値の計算後にパネルの状態を管理できるようにしました。

//フェードイン操作
private void FadeInOperation()
{
alpha -= 0.01f;

var tempColor = panel_fadeImage.color;

tempColor.a = alpha;
panel_fadeImage.color = tempColor;

PanelEnabled(); ←この部分

if (alpha <= 0)
fadein = false;

}

//フェードアウト操作とシーン遷移
private void FadeOutOperation()
{
alpha += 0.01f;

var tempColor = panel_fadeImage.color;

tempColor.a = alpha;
panel_fadeImage.color = tempColor;

PanelEnabled(); ←この部分

if (alpha >= 1)
{
fadeout = false;
SceneManager.LoadScene("Fade" + scenNumber);
}
}

これでフェード処理中にパネルの表示トラブルが回避できると思います。


フェード処理前のalpha値の管理
フェード処理開始時にalpha値がズレていたら…
機能が不完全に作動する事になります。

手動で数値を変えたなどです。

そこで、フェード処理の前に数値が必ず、0か1になるようにしてから
フェード処理に入るように変更しました。

//フェードイン呼び出し
private void FadeIn()
{
if (alpha != 1)
alpha = 1f;

fadein = true;
}

//フェードアウト呼び出し
private void FadeOut()
{
if (alpha != 0)
alpha = 0f;

fadeout = true;
}

これで必ず、どちらかの数値になるようにできます。
安定して処理が行えるかと思います。


ボタンを使ってシーン遷移させる説明が不十分だったので、
説明を追加しておきます。

シーン遷移は、フェードアウト後に遷移する事を前提にしてるので、
フェードアウト処理内に組み込んでいます。

シーン遷移は、SceneManager.LoadScene関数を使いますが、
ストリング形式でシーン名を指定する必要があります。

今回は、Fade1・Fade2とシーンを用意しました。
このシーン名の数値部分を半角で登録した場合、"Fade"+数値で指定する事ができます。

なので、int型のsceneNumberを設定しました。

SceneManager.LoadScene("Fade" + scenNumber)



ボタンから呼び出す関数は、

//シーン遷移時のボタン操作
public void SceneMove(int num)
{
scenNumber = num;
FadeOut();
}

SceneMove関数に引数を設定しました。
この引数は、Inspector上で設定します。
フェード④.jpg
ボタンのクリック時に割り当てを行いますが、
SceneMove関数を設定すると、関数名の下に数値が入力できるようになります。
これが引数numです。

ここを遷移させたいシーン番号にすれば、sceneNumberに登録できます。
あとは、FadeOut関数を呼び出せば、フェードアウト処理が実行されます。


今回の追加処理は以上となります。

使いたい所で、FadeIn・FadeOut関数を呼び出せば、発動するはずです。

FadeIn関数は、Startで呼び出していますが、
別になくてもOKになります。

ただ、PanelEnabled関数は、必ずStartで呼び出して下さい。
パネルが消えずに残る事になります。

以前の処理よりは使いやすくなったのではないかと思います。
なにかあればコメント頂ければ幸いでっす。m(_ _)m


この記事へのコメント

  • ぴーなっつ

    はじめまして。
    現在、CanvasにButtonとフェードアウト用のPanelを作成し、Buttonにスクリプトをアタッチして、ボタンがクリックされるとフェードアウト→シーン遷移というものをやろうとしているのですが、うまくいきません…
    動画を見るとボタンを押すことでフェードが開始されているように見えるのですが、そのコードはどの部分でしょうか…?
    2022年10月19日 15:37
  • ぴーなっつ

    先ほどコメントした者です。たびたびすみません。先ほどのボタンのコードに関しては解決いたしました。

    フェードアウトのみ行いたいので、フェードアウトのコードのみ記述して実行しているのですが、ボタンを押しても何も反応しません…

    この記事と同様、ボタンを押すとフェードアウトをtrueにし、Update部分にif(fadeout == true){FadeOut()}で実行できるようにしています。

    ボタンを押す動作を介さなければフェードしてくれるのですが、ボタンを押すことを挟むとうまくいきません。
    説明だけだとわかりにくくて申し訳ありませんが、何か対処法はありますでしょうか…?
    2022年10月19日 16:06
  • kero

    コメントありがとうございます。m(_ _)m
    ボタンを押すと上手く行かないとの事ですが、

    考えられる原因
    ・ボタンにスクリプトの割り当てができてない
    ・ビルド設定にシーンの登録ができてない
    ・SceneNoの変数が設定できてない
    この辺りがあやしいかと思います。

    少し記事を読み返して、
    説明不足・スクリプトの修正が必要と感じたので、
    追記記事を発行予定です。

    解決の手がかりになればいいのですが、
    追記するまで少々お待ちください。
    2022年10月20日 08:27
  • kero

    ぴーなっつさんお待たせしました。
    追加記事をアップしました。

    追加記事を書いてる時に気付いたのですが、
    フェードインを使わないとの事で、フェードパネルが表示状態になってるのではないでしょうか?

    パネルが前面にあると後面のUIにアクセスできなくなります。
    追加記事にも書いておいてので、その辺りが解決策になるかと思います。

    上手く回避できたらコメント頂けると嬉しいです。
    2022年10月21日 18:22
  • ぴーなっつ

    追加記事ありがとうございます!
    あの後何度かやってみたところ、うまく動いてくれるようになりました。わかりやすい記事で、とても助かりました。ありがとうございます!
    2022年10月26日 14:23
  • kero

    ぴーなっつさん返信ありがとうございます。
    無事に解決できたみたいで、なによりです。

    また何かあれば気軽にコメント頂ければ嬉しいです。
    それでは、よりよいunityライフを。
    2022年10月27日 00:44