Сохранить между сценами
Часть раздела Создание настоящих игр путешествия по Unity на Coddy. Урок 20 из 56.
Загрузка сцены уничтожает каждый объект старой сцены, но некоторые вещи должны сохраняться на протяжении всей игры, например монеты, которые игрок переносит с уровня на уровень. 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 значение с 0 монетами. С проверкой новый экземпляр обнаруживает, что Instance уже задан, уничтожает себя и завершает работу, а экземпляр сессии, прошедший через уровни, остаётся.
return здесь важен, потому что Destroy дожидается конца кадра. Без него оставшаяся часть Awake всё равно выполнилась бы для нового экземпляра: Instance = this; направил бы все скрипты на объект, который вскоре будет уничтожен.
Задание
ЛегкоСекундомер для спидрана. Объект RunClock в Level1 отсчитывает секунды всего прохождения и записывает промежуточное время каждый раз, когда уровень пройден. Золотая цель Level1 загружает Level2, а цель Level2 снова загружает Level1, и каждая цель сначала вызывает RunClock.Instance.Split(). У каждого уровня есть собственный HUD с ClockText; в Inspector объекту RunClock назначен тот, что находится в Level1. Стрелки перемещают Player. Измени RunClock.cs, чтобы:
- секундомер продолжал работать при каждой загрузке сцены, не начиная отсчёт заново;
- время всегда отображалось в
ClockTextоткрытого уровня в форматеTime: 12.3; - при возвращении в Level1, где есть собственный RunClock, оставался только один секундомер — тот, который уже работал, — и именно он был
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"));
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Создание настоящих игр
1Текст на экране
Холст и текстПокажем счётФорматирование чиселТаймер обратного отсчётаПовторение: спидометр4Сцены и уровни
Загрузить сценуПерезапустить уровеньСледующий уровеньСохранить между сценамиПовторение: выбор уровня7Управление временем
Пауза с timeScaleЗамедленное движениеНемасштабируемое времяПовторение: Bullet Time10Проект: 3D-платформер
ТрассаДвижущиеся платформы2Кнопки и экраны
Кнопки и onClickЛямбдыСвязи в InspectorВключение и выключение панелейШкалы здоровьяПовторение: магазин улучшений5Сохранение с помощью PlayerPrefs
Сохранение числаЗагрузка со значением по умолчаниюРекордСохранение настроекПовторение: монеты в банке