Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

【Unity】コルーチンとシーン遷移

More than 1 year has passed since last update.

やりたいこと

  • コルーチンについての理解
  • コルーチンを用いたフェードイン・フェードアウトの実装

コルーチンの最小構成

コルーチンの定義

    IEnumerator  Fadeout() {
      yield return null;  
    }
  • 戻り値の型はIEnumerator
  • 戻り値は yield return ~~~;

コルーチンの呼び出し

   StartCoroutine("Fadeout");
   StartCoroutine(Fadeout());
  • メソッドを渡す。 (おそらくリフレクションを利用している。)
  • コルーチンの定義と呼び出しは同一クラスである必要がある。 (別クラスである場合、エラーが発生する。)

コルーチンの呼び出し順序

テストコード

public class Fade : MonoBehaviour
{
    void Update()
    {
        Debug.Log("BeginUpdate");
        if (Input.GetKeyDown(KeyCode.A))
        {
            Debug.Log("BeginFadeout");
            StartCoroutine("Fadeout");
            Debug.Log("EndFadeout");
        }
        Debug.Log("EndUpdate");
    }

    public IEnumerator  Fadeout()
    {
        for (int i = 1; i <= 3; i++)
        {
            Debug.Log("Fadeout : " + i + "回目");
            yield return null;
        }
    }
}

ログ

--- 1フレーム目 ---
BeginUpdate
BeginFadeout
Fadeout : 1回目
EndFadeout
EndUpdate
--- 2フレーム目 ---
BeginUpdate
EndUpdate
Fadeout : 2回目
--- 3フレーム目 ---
BeginUpdate
EndUpdate
Fadeout : 3回目

実行結果

  • 1フレーム目は通常のメソッドと同じ振る舞いをする。
  • 2フレーム以降は自動で実行され、順序はUpdate()とは別のタイミングである。

コルーチンについての理解を深める。

1フレームに一度実行する。

  yield return null;

コルーチンを一定時間ごとに実行する。

 yield return new WaitForSeconds(1.0f); // 1秒ごと

コルーチンを途中で終了する。(以降の処理は呼ばれない。)

  yield break;

全レンダリング完了後に実行する。

  yield return new WaitForEndOfFrame();

すべてのコルーチンを停止する。

  StopAllCoroutines();

※すべてのというのはそのクラス内(MonoBeheiver)ということ。別のクラスやオブジェクトには影響しない。

フェードイン・フェードアウトの実装

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

public class FadeSceneManager : MonoBehaviour
{
    private static Canvas canvas;
    private static Image image;

    // シングルトン
    private static FadeSceneManager singlton;
    public static FadeSceneManager Instance
    {
        get {
            if (singlton == null)
            {
                Init();
            }
            return singlton;
        }
    }
    private FadeSceneManager() { }
    private static void Init() {
        // Canvas作成
        GameObject canvasObject = new GameObject("CanvasFade");
        canvas = canvasObject.AddComponent<Canvas>();
        canvas.renderMode = RenderMode.ScreenSpaceOverlay;
        canvas.sortingOrder = 100;
        // 用途不明 (3Dになった際に必要になる?)
        // canvasObject.AddComponent<GraphicRaycaster>();

        // Image作成
        image = new GameObject("ImageFade").AddComponent<Image>();
        image.transform.SetParent(canvas.transform, false);
        // 画面中央をアンカーとし、Imageのサイズをスクリーンサイズに合わせる。
        image.rectTransform.anchoredPosition = Vector3.zero;
        Camera camera = GameObject.Find("Main Camera").GetComponent<Camera>();
        image.rectTransform.sizeDelta = new Vector2(Screen.width, Screen.height);

        // 遷移先シーンでもオブジェクトを破棄しない。
        DontDestroyOnLoad(canvas.gameObject);

        // シングルトンオブジェクトを保持する。
        // newの場合、オブジェクトが正しく初期化されない可能性があるので、
        // Add - GetComponentを通して、オブジェクトを取得する。
        canvasObject.AddComponent<FadeSceneManager>();
        singlton = canvasObject.GetComponent<FadeSceneManager>();
    }

    // 画面遷移を行う。
    // interval - フェードイン,フェードアウトに要する時間(秒)
    public void LoadScene(float interval, string sceneName)
    {
        StartCoroutine(Fade(interval, sceneName));
    }

    private IEnumerator Fade(float interval, string sceneName)
    {
        float time = 0f;
        canvas.enabled = true;

        // フェードイン
        while (time <= interval)
        {
            float fadeAlpha = Mathf.Lerp(0f, 1f, time / interval);
            image.color = new Color(0.0f, 0.0f, 0.0f, fadeAlpha);
            time += Time.deltaTime;
            yield return null;
        }

        // シーン非同期ロード
        yield return SceneManager.LoadSceneAsync(sceneName);

        // フェードアウト
        time = 0f;
        while (time <= interval)
        {
            float fadeAlpha = Mathf.Lerp(1f, 0f, time / interval);
            image.color = new Color(0.0f, 0.0f, 0.0f, fadeAlpha);
            time += Time.deltaTime;
            yield return null;
        }
        // 描画を更新しない。
        canvas.enabled = false;
    }
}

ほとんど参考サイトの通りです。
メリット : ゲームオブジェクトを動的に作成するため、初期配置が不要。

参考サイト

コルーチン
C#におけるyieldの挙動

【Unity】シーン遷移時のフェードイン・フェードアウトを実装してみた
Unityシーン間のフェードインアウトを2行で実現できる簡単スクリプト

ogawa-to
ゲームプログラマに転職すべく基本独学で勉強中。 Unity, UnrealEngineを用いて作成したゲームをポートフォリオとする予定。 ロックマンや悪魔城のような横スクロールが大好物。 FPSやスマホゲームなど、ほぼプレイ経験がないので、食わず嫌いせず触れていきたい。 Twitter : @mezofuchi
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away