В каждой аркаде для подсчета очков учитывается такой компонент как таймер/время. Это время может относиться к любой части вашей игры: таймер с обратным отчетом, время прохождения уровня, время прохождения игры и т.д. Безусловно стандартный интерфейс в Unity очень полезная штука, но в рамках кастомизации и при наличии своего интерфейса необходимо оперировать объектами — кодом. В прошлой статье вы научились вращать объекты кодом. Сегодня мы научимся писать таймер, который задействует текстовые объекты Unity.
Пишем таймер в Unity
Я не особо — то дизайнер… Но стандартный вид мне не нравился, поэтому я создал свой интерфейс, примитивно конечно, но выглядит лучше, чем было:
Если вы обратили внимание на ветку «All Panels», наверняка заметили, что в иерархии имеется 3 объекта: TimeText, Current Seconds и Current Minutes. В эту панельку так же влетел спидометр, что не есть хорошо, но это был первый опыт, поэтому не судите строго. Приведу пример от Current Seconds, так как это самая динамичная единица в любом таймере (если нет миллисекунд). Это текстовый объект со значением: 00 (два нуля). Думаю воспроизвести подобную панельку вам труда не составит, поэтому переходим к коду.
Во-первых: скрипт с работой таймера находится в папке ScriptableObjects.
Во-вторых: изменение текстового значение идет через метод.
А вот и сам код таймера:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
using System; using UnityEngine; using UnityEngine.UI; public class Timer : MonoBehaviour { private float timeInSecondsP; public static int minutsP; public static int secondsP; public Text minutes; public Text seconds; internal void Update() { if (PlayerController._gameover == false) { if (Teach.DoneTeach == true) { timeInSecondsP += Time.deltaTime; secondsP = (int)(timeInSecondsP % 60); minutsP = (int)(timeInSecondsP / 60); if (minutsP < 10) { minutes.text = 0 + minutsP.ToString(); if (secondsP < 10) { seconds.text = 0 + secondsP.ToString(); } else { seconds.text = secondsP.ToString(); } } else { minutes.text = 0 + minutsP.ToString(); if (secondsP < 10) { seconds.text = 0 + secondsP.ToString(); } else { seconds.text = secondsP.ToString(); } } } else { string secondsP; string minutsP; } } } } |
Сложна? Сложна. Хотелось сделать так, чтобы таймер начинался только после закрытия экрана обучения. Соответственно можно увидеть флаги DoneTeach, как раз отвечающие за этот экран. Давайте разбираться. Думаю с переменными все понятно.
Кусок:
1 2 3 4 |
timeInSecondsP += Time.deltaTime; secondsP = (int)(timeInSecondsP % 60); minutsP = (int)(timeInSecondsP / 60); |
Во-первых первая строчка отвечает за одну единицу времени, и ее увеличение. Далее мы обозначаем что secondsP это 60% от первой переменной, к которой постоянно прибавляется время. Минуты соответственно разделенное на 60. Окей, на этом можно было остановиться, но только в том случае, если был интерфейс от Unity… В кастомном интерфейсе все сложнее, поэтому пришлось создавать условия.
Таймер через интерфейс
Условия эти заключались в том, что кастомный таймер при тестах вел себя не так как надо. А именно вид у него становился такой: 00: 1 — это сами понимаете никуда не годится. Было принято решение принудительно дорисовывать нуль к самой переменной, но далее возникла проблема, когда секунд становилось более 10, таймер принимал вид 00:010 — это тоже ни в какие ворота. Соответственно, чтобы исправить данную ситуацию появились такие зависимости:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
if (minutsP < 10) { minutes.text = 0 + minutsP.ToString(); if (secondsP < 10) { seconds.text = 0 + secondsP.ToString(); } else { seconds.text = secondsP.ToString(); } } else { minutes.text = 0 + minutsP.ToString(); if (secondsP < 10) { seconds.text = 0 + secondsP.ToString(); } else { seconds.text = secondsP.ToString(); } } |
То есть если значение больше 10, то нуль, который мы дописывали принудительно — исчезает. После этого все встало на свои места и таймер начал нормально работать в виде 01:02 без каких-либо ошибок и сбоев. Если вы обратили внимание, то мы не просто работаем с переменными — мы работаем с их компонентами — «minutes.text». Далее мы каждый раз при изменении значений minutes или seconds приводим их к виду строки, используя встроенный метод ToString(), таким образом текстовое значение, которое мы видим в самой игре — меняется.
Хочу себе такой же таймер в Unity!
Хорошо, что нужно сделать:
- Создать 2 объекта типа текст.
- Назвать их Current Seconds и Current Minutes.
- Создать пустой объект.
- Назвать его Time.
- В пустом объекте нажимаем Add Component -> New Script — называем Timer.
- Сворачиваем открывшийся редактор и возвращаемся к самому первому скрипту в этой статье.
- Полностью копируем его и вставляем в редактор.
- Убираем строчки (не забудьте в нижней части скрипта убрать 2 закрывающие закрывающие фигурные скобки, иначе скрипт работать не будет!):
1234567<strong>if (PlayerController._gameover == false){if (Teach.DoneTeach == true){</strong>Тело внутри этих скобок не удалять! То что помечено жирным - удалить!<strong> }}</strong> - Сохраняем.
- Возвращаемся в редактор Unity.
- На пустом объекте Time в окне с компонентом «Timer(Script)» должны были появиться 2 новые строчки: Minutes, Seconds.
- Из иерархии вашей сцены тянем объект Current Minutes в поле Minutes.
- Повторить пункт 12 для Current Seconds/Seconds.
- Нажать кнопку Play.
- Радоваться, что все работает 🙂
Итоги.
Честно говоря, не думал, что получится такая большая статья про таймер в Unity. Если у вас возникли ошибки при попытке запустить режим Play в едиторе, значит вы что-то сделали не так. Можете оставить ошибку в комментариях, поможем. Теперь вы умеете создавать красивый кастомный таймер в Unity. Естестсвенно теперь можете изменять графический компонент текста этих объектов как захотите, они привязаны в скрипте и это все, что требовалось сделать для его корректной работы (главное ничего не удалять). Ждем вас в нашей группе в ВК и на Youtube-канале!
public class Timer2
{
private TimeSpan timer = new TimeSpan();
public Text minutes;
public Text seconds;
internal void Update()
{
if (!PlayerController._gameover && Teach.DoneTeach)
{
timer = timer.Add(TimeSpan.FromSeconds(Time.deltaTime));
minutes.text = timer.Minutes.ToString(«00»);
seconds.text = timer.Seconds.ToString(«00»);
}
}
}
Отличный пример! Спасибо!