Управление временем на Unity.
Всем привет, сегодня я хотел бы поделиться тем, как я реализовал управление временем на Unity 3D. Думаю многие играли в Price of Percia: The sands of time. Мне показалось, что в этой игре не раскрыли весь потенциал, данной задумки. Что ж давайте подумаем, как можно это реализовать. В unity есть такая вещь, как Time. Вы можете его посмотреть настройки в Time Manager во вкладке Edit/ProjectSettings/Time
Как мы видим, здесь есть настройки Fixed Timestep - этот параметр определяет то, через какое время будет вызываться функция FixedUpdate. В этой функции выполняется обработка физики RigidBody и тому подобное. Maximum Allowed Time - Отвечает за независимый от частоты кадров отсчет времени, здесь он нам не понадобится. Time Scale - это скорость, с которой течет время, так установив этот параметр на 0 вы остановите движение времени в игре, а установив на значение больше или меньше 1 ускорите или замедлите время соответственно. Очень хорошо может применяться для создания SlowMotion или же для паузы в игре, заметим, что параметр Time Scale не может быть меньше 0, это значит, что мы не можем использовать его для наших целей, то есть можем, но не так просто.
Что же с теорией разобрались теперь давайте подумаем как нам реализовать обратную перемотку. На ум сразу же приходит идея записать позиции и поворот всех нужных нам объектов и присваивать их при нажатии на кнопку. Так и поступим.
Создадим C# скрипт и назовем его Time_. Создадим массив GameObject и назовем его Objects, создадим также двумерный массив типа Vector3 и еще один двумерный массив типа Quaternion, назовем их Positions и Rotations соответственно.
Создадим сразу переменную Index типа integer, для того чтобы ориентироваться в массиве. Ведь когда мы будем записывать позиции и поворот, мы должны сохранить это в следующем элементе. Так же создадим переменную Scale типа int, которая будет регулировать размер массивов, а следовательно и длину записи, установим ей значение 1000.
В Старте инициализируем переменные.
Objects мы будем искать все объекты на сцене по тегу "Time", давайте настроим этот тег.
Objects = GameObject.FindObjectsWithTag("Time"), далее инициализируем Positions и Rotations, устанавливая первый размер Objects.Length, а второй Scale.
Получим что-то вроде этого.
Давайте сразу пропишем в Update вычисления, если Index больше Scale, то обнуляем Index и записываем все по новой. Это будет значить, что мы возвращаем только последние несколько секунд времени, количество которых зависит от Scale. Тоже самое, только наоборот, делаем и с нулем, таким образом ограничивая Index (0,Scale).
В начале мы не просто так затронули функцию FixedUpdate, она вызывается через определенное кол-во кадров, в зависимости от TimeScale, и в ней обрабатывается физика.
Нам нет смысла обновлять позиции каждый кадр, если они не меняются. Следовательно прописываем функцию FixedUpdate() и в ней уже пишем цикл for от 0 до Objects.Length, с переменной і и в этом цикле Positions и Rotations[i,Index] присваиваем текущие позиции и повороты. после цикла в функции прибавляем к Index 1.
Теперь осталось только присвоить эти значения к текущим позиции и повороту, для этого в Update прописываем условие If(Input.GetKey(KeyKode.R)) и в нем значение TimeScale устанавливаем на 0, так мы защищаем себя от воздействия физики на объекты и перестаем записывать позиции еще раз. Теперь используя функцию Lerp присваиваем позиции и поворот нашему трансформу.
Теперь осталось просто запускать время, когда отпустим клавишу R, для этого все в том же Update пишем if(Input.GetKeyUp(KeyKode.R)) и в этом условии устанавливаем значение TimeScale на 1
Что ж, вот мы и написали небольшой код, для управления временем, он оказался довольно простым и наглядно показывает, как обновляется физика и как работает Lerp, так же практическое применение двумерных массивов в Unity. При настройке не забудьте добавить RigidBody на ваши кубики и установить тег.