シーン間で保持する
CoddyのUnityジャーニー「本格的なゲームを作る」セクションの一部。レッスン 20/60。
シーンを読み込むと古いシーンのすべてのオブジェクトが破棄されますが、プレイヤーがレベル間で持ち越すコインのように、ゲーム全体を通して残しておかなければならないものもあります。DontDestroyOnLoad(gameObject)はオブジェクトをシーンから独立したシーンへ移動します。このシーンは「プレイ」中、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シーンにあります。「プレイ」すると、MenuからLevel1へ移動してからMenuに戻ります。Menuはすべてのオブジェクトをもう一度生成するため、新しいGameSessionも生成されますが、保持されていたものはまだ残っています。Awake内のチェックがなければ2つになり、新しい方がコイン0枚の状態でInstanceを上書きしてしまいます。チェックがあれば、新しい方はInstanceがすでに設定されていることに気づき、自身を破棄して処理を終了します。そのため、各レベルを引き継いできたセッションが残ります。
returnが重要なのは、Destroyがフレームの終わりまで実行を待つためです。これがなければ、新しい方ではAwakeの残りの処理も実行されます。Instance = this;によって、破棄される予定のオブジェクトをすべてのスクリプトが参照することになります。
チャレンジ
簡単すべてのシーンの読み込みを通して、1つのタイマーを動かし続けます。
Awake()で、Instance != nullの場合は、Destroy(gameObject);を呼び出してからreturn;します。それ以外の場合は、Instanceを設定し、DontDestroyOnLoad(gameObject);を呼び出します。- シーンを読み込むと前のレベルのテキストが破棄されるため、
Update()で、テキストを表示する行の前に、clockText == nullの場合は、clockText = GameObject.Find("ClockText").GetComponent<TMP_Text>();を設定します。
「プレイ」を押してLevel2に移動し、戻ります。タイマーが1つだけ動き続けます。その後、「確認」を押します。
自分で試してみよう
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"));
}
}
本格的なゲームを作るのすべてのレッスン
自分で練習してみよう: Unityプレイグラウンド