Привет. Таймер — базовая механика в разработке игр. Они запускаются перед сбросом ежедневного задания или бонусного сундука, когда мы посадили картошку, начали строить здание или разбирать завалы. Посмотрите на любимые игры и увидите таймеры повсюду.
В Unity есть простой способ создания таймера, который я сегодня и покажу. А ещё покажу его альтернативный вариант и вариант с графическим индикатором вместо текста.
Самый простой таймер
Его реализация очень простая. Указываем время в секундах и отнимает от него detlaTime пока оно не будет равным нулю. Пока таймер работает – регулярно обновляем текст.
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 |
using UnityEngine; using UnityEngine.UI; public class SimpleTimer: MonoBehaviour { [SerializeField] private float time; [SerializeField] private Text timerText; private float _timeLeft = 0f; private bool _timerOn = false; private void Start() { _timeLeft = time; _timerOn = true; } private void Update() { if (_timerOn) { if (_timeLeft > 0) { _timeLeft -= Time.deltaTime; UpdateTimeText(); } else { _timeLeft = time; _timerOn = false; } } } private void UpdateTimeText() { if (_timeLeft < 0) _timeLeft = 0; float minutes = Mathf.FloorToInt(_timeLeft / 60); float seconds = Mathf.FloorToInt(_timeLeft % 60); timerText.text = string.Format("{0:00} : {1:00}", minutes, seconds); } } |
В данному случае главная проблема в том, что таймер находится в Update функции. Т.е. этот скрипт добавит ещё одну функцию, которую нужно выполнять каждый кадр. Как по мне, так более удачным решением будет использование корутин.
Простой, но с использованием Coroutine
Код будет практически такой же, но нам не нужно держать булеву переменную для запуска таймера. Вместо этого мы будем запускать корутину.
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 |
using System.Collections; using UnityEngine; using UnityEngine.UI; public class CoroutineTimer: MonoBehaviour { [SerializeField] private float time; [SerializeField] private Text timerText; private float _timeLeft = 0f; private IEnumerator StartTimer() { while (_timeLeft > 0) { _timeLeft -= Time.deltaTime; UpdateTimeText(); yield return null; } } private void Start() { _timeLeft = time; StartCoroutine(StartTimer()); } private void UpdateTimeText() { if (_timeLeft < 0) _timeLeft = 0; float minutes = Mathf.FloorToInt(_timeLeft / 60); float seconds = Mathf.FloorToInt(_timeLeft % 60); timerText.text = string.Format("{0:00} : {1:00}", minutes, seconds); } } |
Работает аналогично, но в корутине, и не привязан к обновлению кадра.
Графический таймер
Иногда нам нужен не текст, а картинка, которая будет отображать прогресс чего-то. Вроде навыков с кд в играх. Такого эффекта достичь тоже очень легко. Сначала заменим Text на Image. Вместо функции обновления текста мы будем указывать процент заполненности изображения от 0 до 1.
Для получения соотношения делим оставшееся время на изначальное. Можно использовать Clamp, чтобы убедиться, что это число точно будет в заданных рамках. И указываем это значение для Image.
В редакторе указываем, что выбранный Image будет иметь тип Filled:
Что приятно: один и тот же скрипт подходит для всех вариантов заполнения картинки. Удобно.
И в итоге получаем что-то такое:
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 |
using System.Collections; using UnityEngine; using UnityEngine.UI; public class ImageTimer : MonoBehaviour { [SerializeField] private float time; [SerializeField] private Image timerImage; private float _timeLeft = 0f; private IEnumerator StartTimer() { while (_timeLeft > 0) { _timeLeft -= Time.deltaTime; var normalizedValue = Mathf.Clamp(_timeLeft / time, 0.0f, 1.0f); timerImage.fillAmount = normalizedValue; yield return null; } } private void Start() { _timeLeft = time; StartCoroutine(StartTimer()); } } |
И итоговая сцена у меня выглядит так. Первый текстовый таймер сделан через Update, а второй через корутину.
На идею натолкнул short «How to Create a Simple Countdown Timer in Unity»