【Unity(C#)】3Dでのフェードアウト、フェードイン

　　
　　
　
　　
この記事は

**『プログラミング完全未経験からUnityでの開発現場に迎え入れてもらえた世界一の幸せ者』**

の記事です。そのつもりでお読みください。


##Canvas、Panelを作る
フェードアウト、フェードインに必要なCanvas,Panelを作ります。
フェードアウト、フェードインは汎用性が高いので、何度でも使いまわせるように
Canvas,Panelがプレイ時に自動で生成されるようにしました。
(スクリプトでゲームオブジェクトを作る方法→[こちら](https://qiita.com/OKsaiyowa/items/dc56e3d202de23befa20))

細かい設定はこちらを参考にさせて頂きました。
→[Canvasについて](https://tech.pjin.jp/blog/2017/03/02/unity_ugui_canvas_rendermode/)

```C#
Canvas faceCanvas;

Image facePanel;

//～省略～

//キャンバス生成＆設定
        GameObject canvas_G = new GameObject("FaceCanvas");
        faceCanvas = canvas_G.AddComponent<Canvas>();
        canvas_G.AddComponent<CanvasScaler>();
        canvas_G.AddComponent<GraphicRaycaster>();

        //レンダリングをメインカメラに
        faceCanvas.renderMode = RenderMode.ScreenSpaceCamera;
        faceCanvas.worldCamera = FindObjectOfType<Camera>();

        //パネル生成＆設定
        GameObject panel_G = new GameObject("FacePanel");
        facePanel = panel_G.AddComponent<Image>();

        Color tmpColor = facePanel.color;
        tmpColor.a = 0f;
        facePanel.color = tmpColor;

        //パネルをキャンバスの子に設定
        panel_G.transform.parent = canvas_G.transform;

        //パネルのポジションを正面に調整
        Vector3 panelPosition = panel_G.transform.localPosition;
        panelPosition.x = 0;
        panelPosition.y = 0;
        panel_G.transform.localPosition = panelPosition;
```

これで、自動的にCanvasとPanelがカメラの前に現れます。


##フェードアウト、フェードイン
Alphaを徐々に変更することでフェードを再現します。

`Panel`の持つ`Image Component`の`Color`の`Alpha`です。

コルーチンでAlphaの値を変えます。
コルーチン→[こちら](https://qiita.com/OKsaiyowa/items/d0f59ae0c97b29118a80)

```C#
 IEnumerator FadeOutCoroutine()
    {
        float alpha = 1;

        while (panelColor.a < 1)
        {
            yield return new WaitForSeconds(0.1f);
            panelColor.a += alpha / (fadeTime*10);
            facePanel.color = panelColor;
        }

        panelColor.a = 1;
       
        StopCoroutine(coroutine);
        coroutine = null;
    }

    IEnumerator FadeInCoroutine()
    {
        float alpha = 1;

        while (panelColor.a > 0)
        {
            yield return new WaitForSeconds(0.1f);
            panelColor.a -= alpha / (fadeTime * 10);
            facePanel.color = panelColor;
        }

        panelColor.a = 0;
       
        StopCoroutine(coroutine);
        coroutine = null;
    }
}
```


##最終的なコード
今回は、色とフェードする時間をInspectorで変更できるようにしてます。
確認用のテストキーも用意しました。


```C#
using System.Collections;
using UnityEngine;
using UnityEngine.UI;


public class FadeInOut : MonoBehaviour
{
    Canvas faceCanvas;

    Image facePanel;

    Coroutine coroutine;

    [SerializeField]
    Color panelColor = new Color(0,0,0,0);

    [SerializeField]
    float fadeTime = 5;

    

    // Start is called before the first frame update
    void Start()
    {
        //キャンバス生成＆設定
        GameObject canvas_G = new GameObject("FaceCanvas");
        faceCanvas = canvas_G.AddComponent<Canvas>();
        canvas_G.AddComponent<CanvasScaler>();
        canvas_G.AddComponent<GraphicRaycaster>();

        //レンダリングをメインカメラに
        faceCanvas.renderMode = RenderMode.ScreenSpaceCamera;
        faceCanvas.worldCamera = FindObjectOfType<Camera>();

        //パネル生成＆設定
        GameObject panel_G = new GameObject("FacePanel");
        facePanel = panel_G.AddComponent<Image>();

        Color tmpColor = facePanel.color;
        tmpColor.a = 0f;
        facePanel.color = tmpColor;

        //パネルをキャンバスの子に設定
        panel_G.transform.parent = canvas_G.transform;

        //パネルのポジションを正面に調整
        Vector3 panelPosition = panel_G.transform.localPosition;
        panelPosition.x = 0;
        panelPosition.y = 0;
        panel_G.transform.localPosition = panelPosition;

    }

    void Update()
    {
        //キー押してない間はreturn
        if (Input.anyKey == false)
        {
            return;
        }

        if (coroutine == null)
        {
            //テスト用　フェードアウト
            if (Input.GetKeyDown(KeyCode.O) && panelColor.a == 0)
            {
                FadeOut();
            }

            //テスト用　フェードイン
            if (Input.GetKeyDown(KeyCode.I) && panelColor.a == 1)
            {
                FadeIn();
            }

        }

    }

    public void FadeOut()
    {
        if (panelColor.a == 0)
        {
            coroutine = StartCoroutine(FadeOutCoroutine());
        }
    }


    IEnumerator FadeOutCoroutine()
    {
        float alpha = 1;

        while (panelColor.a < 1)
        {
            yield return new WaitForSeconds(0.1f);
            panelColor.a += alpha / (fadeTime * 10);
            facePanel.color = panelColor;
        }

        panelColor.a = 1;
       
        StopCoroutine(coroutine);
        coroutine = null;
    }

    public void FadeIn()
    {
        if (panelColor.a == 1)
        {
            coroutine = StartCoroutine(FadeInCoroutine());
        }
    }


    IEnumerator FadeInCoroutine()
    {
        float alpha = 1;

        while (panelColor.a > 0)
        {
            yield return new WaitForSeconds(0.1f);
            panelColor.a -= alpha / (fadeTime * 10);
            facePanel.color = panelColor;
        }

        panelColor.a = 0;
       
        StopCoroutine(coroutine);
        coroutine = null;
    }
}
```
![GifCapture-201902112346425569.gif](https://qiita-image-store.s3.amazonaws.com/0/244071/677499ec-d074-dacf-7535-ba2d6eb3c586.gif)


フェードさせたい箇所で`FadeIn`,`FadeOut`を呼び出せばいけるはずです。たぶん。

本当は、UnityEventを使い、Inspectorで色や時間の引数を渡して、
違うフェードを複数呼び出せる仕様にしたかったのですが、無理でした。
(どうやら、UnityEventの引数はInspector上では一つしか登録できないようです...)