UnityでFPSをつくる その10-4 [ シーン遷移 ]

2020年9月10日

前回までで、ゲームクリアーシーンが完成しました。
今回はメインシーンからゲームクリアーシーンへ遷移できるようにしていきます。

No.497

といっても、やることはMainからGameOverシーンへの遷移を実装した時と同様です。
まずは、ProjectウィンドウからMainSceneをダブルクリックしてSceneを切り替えます。

No.498

「GameClearSceneChange」と名付けたスクリプトを新たに作り、以下のコードを貼り付けてください。

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

public class GameClearSceneChange : MonoBehaviour
{
    [SerializeField] Image fadeBoard;

    //色、透明度
    float red, green, blue, alfa;

    // Start is called before the first frame update
    void Start()
    {
        
    }

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

    }

    public void ToGameClearScene() 
    {
        StartCoroutine("FadeOut");
    }

    IEnumerator FadeOut() 
    {
        yield return new WaitForSeconds(3f);

        //フェードアウト
        var isFadeOut = true;

        //何秒かけて不透明にするか
        var duration = 3f;

        //colorの個々の値は取得できても変更できない為、変数に代入する
        red = fadeBoard.color.r;

        green = fadeBoard.color.g;

        blue = fadeBoard.color.b;

        alfa = fadeBoard.color.a;

        while (isFadeOut)
        {
            //durationの時間で暗転するよう、アルファ値を加算
            alfa += Time.deltaTime / duration;

            //アルファ値以外は変更せずにcolorに値を代入
            fadeBoard.color = new Color(red, green, blue, alfa);

            //透明度が1(完全に不透明)になったら
            if (alfa >= 1)
            {
                //フェードアウト終了
                isFadeOut = false;
            }

            yield return null;
        }
        //ゲームクリアーシーンに切り替え
        SceneManager.LoadScene("GameClearScene");
    }
}

スクリプト「GameOverSceneChange」との変更点はフェードアウト前後のタイミングと、遷移先がゲームクリアーシーンという点です。

No.499
No.500

スクリプト「GameOverSceneChange」と見比べていて気付きましたが、GameOverSceneChangeの方のコルーチンの名前が「fadeOut」になっていますね。

No.501

これでもスクリプトは動くのですが、関数名は大文字から始めるという定石から外れていて違和感があるので、「f」を大文字の「F」に直しましょう。

No.502

VisualStudioにも注意されていますね。
なので、「fadeOut」にカーソルを合わせて「Ctrl + F」で検索と置換コントロールを開き、∨マークをクリック

No.503

置換後の語句の欄に「FadeOut」と入力して、すべて置換マークをクリックします。

No.504

メッセージウィンドウが表示されて「fadeOut」が「FadeOut」に置き換わりました。

No.505
No.506

少し逸れましたが、話を戻します。
スクリプト「GameClearSceneChange」をSceneManagerオブジェクトにアタッチして、Fade Boardの項目にImageオブジェクト「Fade Board」を選択します。

No.507

次に、このスクリプトを呼び出す側の実装です。
ゲームクリアーは敵を倒した時に発生するイベントなので、スクリプト「EnemyHP」に以下の行を追加します。

No.508

これにより、Enemyが消滅した瞬間にゲームクリアーシーンへの遷移が呼び出されるようになりました。

最後にシーンの登録です。
メニューバーからFile → Build Settingsを開いてください。

No.509

Build Settingsウィンドウが開いた状態でGameClearSceneを選択、「Add Open Scenes」ボタンをクリックしてシーンを追加します。

No.510

ゲームを実行してGameClearSceneに遷移するか確認してみます。

No.511

MainSceneからGameClearSceneへの遷移が完成しました。

このままフェードアウトするだけでは物足り無さがあるので、フレームイン&アウトでクリアの表記を追加してみます。
MainSceneにUI → Textオブジェクトを追加します。

No.512

このままだとTextがFadeBoardの前面表示になり、フェードアウトの際に暗くならないので、

No.513

Hierarchyウィンドウでの並び順をFadeBoardの上に位置させます。

No.514

Textオブジェクトを「CLEARED」にリネームし、RectTransformコンポーネントの値を以下のようにします。

No.515

続いて、Textコンポーネントの値を以下のようにします。

No.516

Add ComponentでUI → Effects → Outlineコンポーネントを追加します。

No.517

値を以下のようにします。

No.518

さらにAdd ComponentでUI → Effects → Shadowコンポーネントを追加します。

No.519

値を以下のようにします。

No.520

Textの見た目が以下のように変わりました。

No.521

スクリプトでこのTextを動かしていきます。
既存のGameClearSceneChangeスクリプトに追記して、以下のようにしてください。

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

public class GameClearSceneChange : MonoBehaviour
{
    [SerializeField] Image fadeBoard;

    [SerializeField] Text cleared;//追記

    //色、透明度
    float red, green, blue, alfa;

    // Start is called before the first frame update
    void Start()
    {
        
    }

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

    }

    public void ToGameClearScene() 
    {
        StartCoroutine("FadeOut");

        StartCoroutine("FrameInAndOut");//追記
    }

    IEnumerator FadeOut() 
    {
        yield return new WaitForSeconds(3f);

        //フェードアウト
        var isFadeOut = true;

        //何秒かけて不透明にするか
        var duration = 3f;

        //colorの個々の値は取得できても変更できない為、変数に代入する
        red = fadeBoard.color.r;

        green = fadeBoard.color.g;

        blue = fadeBoard.color.b;

        alfa = fadeBoard.color.a;

        while (isFadeOut)
        {
            //durationの時間で暗転するよう、アルファ値を加算
            alfa += Time.deltaTime / duration;

            //アルファ値以外は変更せずにcolorに値を代入
            fadeBoard.color = new Color(red, green, blue, alfa);

            //透明度が1(完全に不透明)になったら
            if (alfa >= 1)
            {
                //フェードアウト終了
                isFadeOut = false;
            }

            yield return null;
        }
        //ゲームクリアーシーンに切り替え
        SceneManager.LoadScene("GameClearScene");
    }

    //以下、追記部分
    IEnumerator FrameInAndOut() 
    {
        yield return new WaitForSeconds(1.5f);
            
        var duration = 0.3f;

        var x = cleared.transform.localPosition.x;

        while (cleared.transform.localPosition.x > 0f) 
        {
            cleared.transform.localPosition -= new Vector3(x * Time.deltaTime / duration, 0f);

            yield return null;
        }

        cleared.transform.localPosition = new Vector3(0f, 0f);

        yield return new WaitForSeconds(2.5f);

        while (cleared.transform.localPosition.x > -x)
        {
            cleared.transform.localPosition -= new Vector3(x * Time.deltaTime / duration, 0f);

            yield return null;
        }
    }
}

追記した箇所を見ていきます。
11行目にInspectorからTextを選択できるようText型変数clearedを宣言しています。

No.522

32行目でFadeOutコルーチン同様、Enemyが倒された時に呼び出されて開始するようToGameClearSceneメソッド内にFrameInAndOutコルーチンを記述しています。

No.523

76行目からFrameInAndOutコルーチンの定義をしています。
WaitForSecondsで指定した秒数待機させてから、duration分の時間をかけてTextオブジェクトを現在位置からCanvasの中央位置まで移動させています。

No.524
No.525

フレームレートが一定で無いため、whileループを抜けて停止する位置はバラバラです。
そこで、91行目で現在位置を強制的に「0」にしています。

No.526

これにより、中央の位置でピタッと止まる動きではなく、中央から左に少しズレた位置で止まって、また中央に戻るブレの動きを表現しています。

No.527

クリアシーンのスケールアップでやっていたことをポジションでやっているわけですね。

No.528

「0」で中央の位置に戻したらWaitForSecondsで指定した秒数待機、フェードアウトが始まってからフレームアウトをduration時間分かけて行っています。

No.529

ゲームを実行して確認してみます。

No.530

フェードアウトにかかるようにフレームイン&アウトの演出を加えることができました。

長くなってきたので続きは次回にしたいと思います、おつかれさまでした!

FPS

Posted by kenji