Сохранить между сценами
Часть раздела Создание настоящих игр путешествия по Unity на Coddy. Урок 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 было бы два таких объекта, и новый присвоил бы себя переменной Instance, обнулив количество монет. Благодаря проверке новый объект обнаруживает, что Instance уже задан, уничтожает себя и останавливается, а сессия, прошедшая через уровни, сохраняется.
return важен, потому что Destroy ждёт до конца кадра. Без него выполнение оставшейся части Awake для нового объекта продолжилось бы: Instance = this; направил бы все скрипты на объект, который вскоре будет уничтожен.
Задание
ЛегкоСохрани один таймер работающим при каждой загрузке сцены.
- В
Awake(), еслиInstance != null, вызовиDestroy(gameObject);иreturn;. Иначе присвой значениеInstanceи вызовиDontDestroyOnLoad(gameObject);. - При загрузке уничтожается текст старого уровня, поэтому в
Update(), перед строкой с текстом, еслиclockText == null, присвойclockText = GameObject.Find("ClockText").GetComponent<TMP_Text>();.
Нажми «Играть», перейди на Level2 и обратно: один таймер продолжит отсчёт. Затем нажми «Проверить».
Попробуйте сами
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"));
}
}
Все уроки раздела Создание настоящих игр
1Текст на экране
Холст и текстПокажем счётФорматирование чиселТаймер обратного отсчётаПовторение: спидометр4Сцены и уровни
Загрузить сценуПерезапустить уровеньСледующий уровеньСохранить между сценамиПовторение: выбор уровня2Кнопки и экраны
Кнопки и onClickЛямбдыСвязи в InspectorВключение и выключение панелейШкалы здоровьяПовторение: магазин улучшений5Сохранение с помощью PlayerPrefs
Сохранение числаЗагрузка со значением по умолчаниюРекордСохранение настроекПовторение: монеты в банкеПотренируйтесь самостоятельно: Песочница Unity