ゲーム化!tomo_manaのブログ

ゲーム化!tomo-manaのブログ

Unityでゲームを作る方法について紹介しています

Unity学習#9 (Unity 2019.4.1f1) フェードイン・アウト#1

今回はフェードイン・アウトに挑戦します。(どっちか分からなくなるので、フェードインは「画面が明るくなる」、フェードアウトは「画面が暗くなる」です)

画面を明るくする、暗くする処理と、それをワープのエフェクトに使うのと両方をする予定でしたが、後者のボリュームが大きいので2回に分けます。今回は、フェードイン・アウトの処理だけ作っておき、ゲーム開始時(Start関数)に動作を確認します。
フェードイン・アウトは、画面の手前に全体を覆う黒いパネルを用意して、透明度を変えることで表現する方法がよく使われているようです。このパネルとして、Canvas.Image を使います。Canvas は、ゲームの操作画面などを配置するもので、ステータス表示や会話、プレイヤーを操作するボタン類などに使われます。キャラクターやカメラがどこにいても、常に画面の同じ位置に表示できます。

今回はコードがほとんどになりました。

Canvas.Imageの追加

Hierarchyウィンドウで右クリック > UI > Image を選択

急にいくつかのオブジェクトが追加されますが、今は気にしないことにします。

f:id:tomo_mana:20200727195942p:plain
Canvas.Image

Canvas.ImageへのC#スクリプトの追加

スクリプトの追加は過去の記事でまとめたため、手順は省略します。
今回はフェードイン・アウトを管理するので、FadeManager という名前にします。

Canvas.Imageの色・透明度の変更

画面全体を覆うパネルが用意されました。これを黒く塗りつぶします。

(1) Hierarchyウィンドウで Canvas > Image を選択
(2) InspectorウィンドウでImage > Colorの色がついているゲージを選択
(3) Colorウィンドウが表示されるので、R, G, B, A に以下を入力します。

パラメータ 数値
R 0
G 0
B 0
A 255

※Aはアルファ値(透明度)

Canvas.Imageの大きさの変更

Imageの大きさの単位

Imageの大きさはRectTransformのWidth、Heightです。RectTransformはこれまでキャラクターやTilemapで扱ってきた Transform とは異なり、1 = 1dotです。(キャラクタやTilemapは1マス単位)

Imageの大きさを取得する

ImageのRectTransformのサイズは Vector2で取得できます。Vector2は RectTransform.sizeDelta から取得します。Vector2はキャラクターの移動時にも使用しましたが、要素は x と y で、キャラクターの移動時は「方向」と「移動量」を表していました。RectTransform.sizeDeltaでは、x, y は「四角形のサイズ」(Width, Height) を表しています。
コード

public class FadeManager : MonoBehaviour
{
    void Start()
    {
        RectTransform rectTransform = GetComponent<RectTransform>();
        Vector2 v = rectTransform.sizeDelta;

        Debug.Log("RectTransform.width = " + v.x);  // Width を表す
        Debug.Log("RectTransform.height = " + v.y);  // Height を表す
    }
}

画面の大きさを取得する

画面の解像度によってImageをリサイズするため、コードから画面サイズを取得します。
コードで大きさを取得する時に使うのはScreen.WidthとScreen.Heightです。このScreenの単位はImageと同じ単位(1 = 1dot)です。

コード

public class FadeManager : MonoBehaviour
{
    void Start()
    {
        Debug.Log("Screen.width = " + Screen.width);
        Debug.Log("Screen.height = " + Screen.height);
    }
}

前回と同様に、各画面を設定した時にどれくらいの大きさになるかを以下に示します。

解像度 X (Width) Y (Height)
16:9 424 238
16:10 386 241
5:4 301 241
4:3 321 241
3:2 362 241
960x600 960 600
standalone(1024x768) 1024 768

Image を画像の大きさにする

Vector2 RectTransform.sizeDelta も、十字キーの動きをキャラクターに反映する時と同じで、直接書き換えることができません。以下のように実装します。
コード

public class FadeManager : MonoBehaviour
{
    private float canvasMargin = 1.1f;

    void Start()
    {
        RectTransform canvas = GetComponent<RectTransform>();
        Vector2 v = canvas.sizeDelta;
        v.x = Screen.width * canvasMargin;
        v.y = Screen.height * canvasMargin;
        canvas.sizeDelta = v;
    }
}

透明度(アルファ値)の変更

フェードイン・アウトは、透明度(アルファ値)を変更します。
アルファ値は Color.a で取得します。Canvas.ImageのColorは、Imageの直下にいるので、Image.Colorで取得できます。

ピッカーでは0(透明)~255(不透明)ですが、
Color.a では0.0f(透明)~1.0f(不透明)です。

透明度を取得する

コード

public class FadeManager : MonoBehaviour
{
    void Start()
    {
        Debug.Log("alpha = " + GetComponent<Image>().color.a);
    }
}

透明度の変更

アルファ値の変更も、Vector2 と同じで、直接変更ができません。
そのため、以下のようにします。
コード

public class FadeManager : MonoBehaviour
{
    private Image image;
    private Color color;

    void Start()
    {
        image = GetComponent<Image>();    // imageへの参照を取得する
        color = image.color;    // image.color の各要素が自分の作業用のcolorにコピーされる
        color.a = 0.5f;   // 自分の作業用のcolorの値を入れ替える
        image.color = this.color;    // imageの参照先に自分のcolorをコピーする
    }
}

フェードイン

フェードイン処理については、以下のサイトを参考にしました。
kenko-san.com

●外からフェードイン・アウトを指定できるようにする
●今フェードイン・アウト中かをわかるようにする
●フェードイン・アウトの時間をオブジェクト毎に変更できるようにする
(1つのコードで複数のフェードイン・アウトを作れるようにする)
という仕様にしようと思います。

それぞれの実装方法についてまとめます。

フェードインの処理

コード

public class FadeManager : MonoBehaviour
{
    private Image image;
    private Color color;
    private float fadeTime = 1.0f;

    void Start()
    {
        image = GetComponent<Image>();
        color = image.color;
        isFadeIn = true;    // ←起動時にフェードイン(真っ暗→明るく)
    }
    void Update()
    {
        if (isFadeIn){
            color.a -= Time.deltaTime / fadeTime;
            if (color.a <= 0.0f){
                isFadeIn = false;
                color.a = 0.0f;
            }
            image.color = this.color;
        }
    }
}

フェードイン中かどうか

コード

public class FadeManager : MonoBehaviour
{
    private bool isFadeIn;

    public bool IsFading()
    {
        bool r = false;
        
        if( isFadeIn == true )
        {
            r = true;
        }
        return r;
    }
}

フェードインにかかる時間を画面から指定する。

第x回に書いた、public または [SerializeField] を使うことで、フェードインにかかる時間を外から入力できます。設定が無い時はフェードイン・アウトが一瞬で完了するようにします。

コード

public class FadeManager : MonoBehaviour
{
    [SerializeField] float fadeTime;

    // Start is called before the first frame update
    void Start()
    {
        if( fadeTime == 0 ){
            fadeTime = Time.deltaTime;
        }
    }
}

フェードイン関連の全処理

コード

public class FadeManager : MonoBehaviour
{
    private Image image;
    private Color color;
    [SerializeField] float fadeTime;
    
    private bool isFadeIn;
    
    
    void Start()
    {
        // 透明度変更の準備
        image = GetComponent<Image>();
        color = image.color;
        isFadeIn = true;    // ←起動時にフェードイン(真っ暗→明るく)
        
        // フェードイン・アウト速度の初期化
        if( fadeTime == 0 ){
            fadeTime = Time.deltaTime;
        }
    }
    
    // フェードイン・アウト中か確認
    public bool IsFading()
    {
        bool r = false;
        
        if( isFadeIn == true )
        {
            r = true;
        }
        return r;
    }
    
    void Update()
    {
        if (isFadeIn){
            color.a -= Time.deltaTime / fadeTime;
            if (color.a <= 0.0f){
                isFadeIn = false;
                color.a = 0.0f;
            }
            image.color = this.color;
        }
    }
}

フェードアウト

フェードアウトの追加

これまでに調べたことを使って、フェードインと対称的な処理を追加したら、フェードアウト処理も追加できます。
コード

public class FadeManager : MonoBehaviour
{
    private Image image;
    private Color color;
    [SerializeField] float fadeTime;
    
    private bool isFadeIn, isFadeOut;
    
    void Start()
    {
        // 透明度変更の準備
        image = GetComponent<Image>();
        color = image.color;
        isFadeIn  = false;    // ←起動時にフェードイン(真っ暗→明るく)
        isFadeOut = false;    // ←起動時にフェードアウト(明るい→真っ暗)
        
        // フェードイン・アウト速度の初期化
        if( fadeTime == 0 ){
            fadeTime = Time.deltaTime;
        }
    }
    
    public void FadeIn()
    {
        if ( !IsFading() ){
            isFadeIn = true;
        }
    }
    
    public void FadeOut()
    {
        if ( !IsFading() ){
            isFadeOut = true;
        }
    }
    
    // フェードイン・アウト中か確認
    public bool IsFading()
    {
        bool r = false;
        
        if( (isFadeIn == true) || (isFadeOut == true)  )
        {
            r = true;
        }
        return r;
    }
    
    void Update()
    {
        if (isFadeIn){
            color.a -= Time.deltaTime / fadeTime;
            if (color.a <= 0.0f){
                isFadeIn = false;
                color.a = 0.0f;
            }
            image.color = this.color;
        } else
        if (isFadeOut){
            color.a += Time.deltaTime / fadeTime;
            if (color.a >= 1.0f){
                isFadeOut = false;
                color.a = 1.0f;
            }
            image.color = this.color;
        }
    }
}

フェードイン・アウトを外から指定する(インタフェースの確認)

フェードイン・アウトには時間がかかるので、ワープ側でフェードイン・アウトしているのか、またフェードイン・アウトの指示を出せるようにします。
コード

// 他のファイルからの呼び出し
private FadeManager fader;

// 処理
if ( fader.IsFading() == false ){
    fader.FadeIn();
}

名前空間を設定していないので、他のファイルからFadeManagerという文字(あるいは自分が付けた名前)を呼び出せば良い(名前空間を設定していないと、同じ名前が使えないので注意が必要)

次回、上記のインターフェースを使ってワープ中のフェードイン・アウトを追加します。

次回やること

ワープ時にフェードイン・アウト効果を追加する