Menu
CoddyTech

シーン間で保持する

CoddyのUnityジャーニー「本格的なゲームを作る」セクションの一部。レッスン 20/56。

シーンを読み込むと古いシーンのオブジェクトはすべて破棄されますが、プレイヤーがレベル間で持ち越すコインのように、ゲーム全体を通して維持しなければならないものもあります。DontDestroyOnLoad(gameObject)はオブジェクトを現在のシーンから切り離して独自のシーンに移します。このシーンはPlay中、HierarchyではDontDestroyOnLoadと呼ばれ、シーンの読み込みの影響を受けません。この処理はルートオブジェクトにのみ機能します。子オブジェクトに対して実行すると、Unityは警告をログに記録し、何も保持しません。保持されたオブジェクトの子は一緒に移動しますが、そのオブジェクトが参照しているだけのオブジェクトは移動しません。読み込み後、古いシーンのオブジェクトを指していたフィールドには破棄済みのオブジェクトが入っており、nullと等しいと判定されます。

public class GameSession : MonoBehaviour
{
    public static GameSession Instance;
    public int coins;

    void Awake()
    {
        if (Instance != null)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;
        DontDestroyOnLoad(gameObject);
    }
}

このGameSessionはMenuシーンにあります。Playすると、MenuからLevel1へ進み、その後Menuに戻ります。Menuは保持されていたGameSessionに加えて、新しいGameSessionを含むすべてのオブジェクトを再び作成します。一方、保持されていたGameSessionはそのまま存在します。Awake内のチェックがなければ2つになり、新しい方が0枚のコインでInstanceを上書きします。チェックがあれば、新しい方はInstanceがすでに設定されていることを確認し、自分を破棄して処理を止めます。各レベルを経由してきたセッションがそのまま残ります。

returnが重要なのは、Destroyがフレームの終わりまで実行されないためです。これがなければ、新しい方についてAwakeの残りの処理も実行されます。Instance = this;によって、すべてのスクリプトがまもなく破棄されるオブジェクトを参照することになります。

challenge icon

チャレンジ

簡単

スピードラン用の時計です。Level1 の RunClock オブジェクトは、プレイ全体の秒数を数え、レベルをクリアするたびにスプリットタイムを記録します。Level1 の金色の Goal は Level2 を読み込み、Level2 の Goal は再び Level1 を読み込みます。また、各 Goal は最初に RunClock.Instance.Split() を呼び出します。各レベルには ClockText を使った独自の HUD があり、Inspector では Level1 の ClockText を RunClock に割り当てています。矢印キーで Player を操作します。RunClock.cs を変更して、次のようにしてください。

  • シーンを読み込むたびに時計がリセットされることなく、動き続ける。
  • 開いているレベルの ClockText に、常に Time: 12.3 の形式で時間が表示される。
  • RunClock 自身を持つ Level1 に戻っても、時計は1つだけ残り、それまで動いていた時計が使われ、RunClock.Instance がその時計を指す。

Play を押して、Level2 に進んでから戻り、もう一度 Level1 をクリアしてから、Check を押してください。

自分で試してみよう

using UnityEngine;
using TMPro;

public class RunClock : MonoBehaviour
{
    public static RunClock Instance;
    public TMP_Text clockText;
    private float seconds;

    void Awake()
    {
        Instance = this;
    }

    void Update()
    {
        seconds += Time.deltaTime;
        clockText.text = "Time: " + seconds.ToString("0.0");
    }

    public void Split()
    {
        Debug.Log("Split: " + seconds.ToString("0.0"));
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

本格的なゲームを作るのすべてのレッスン