Как создать змейку в Unity?
Доброго дня дорогие друзья, сегодня мы продолжаем поддержку Народного aджема материалом и сегодня поговорим о том, как создать змейку.
Для тех, кто ещё не видел, напомним. На DTF сейчас проходит Народный Джем и наша школа программирования ЯЮниор учредила две номинации:
25 000 рублей за лучшую игру на Unity
25 000 рублей за лучший код на Unity
Подробнее про джем:
Напомним, что данная серия статей нацелена на совсем начинающих!
Создание окружения
В процессе создания змейки нам потребуется графика, для этого мы возьмем бесплатный LowPoly пакет из Asset Store.
Начнем мы с построения уровня.
Для начала нужно создать саму землю, для этого нажимаем ПКМ по окну иерархии и выбираем 3D Object -> Plane, после выполнения этого действия у вас появится плоский объект, который будет играть роль земли.
Но для земли он достаточно маленького размера, чтобы это исправить нам нужно обратить внимание на окно Inspector и в компоненте Transform задать Scale по X и Y значение 40.
После этого земля стала нужного размера, но её вид оставляет желать лучшего, нужно придать ей зеленоватый цвет. Для этого в окне Project мы создаем в Asset папку Material, переходим в неё, нажимаем ПКМ и выбираем Create -> Material, после чего появляется новый материал, который мы называем Ground.
После создания материала его следует настроить, для этого нажимаем ЛКМ на материал и в поле Albedo редактируем цвет на нужный.
Далее нужно материал просто перетащить на наш Plane, после чего он станет зеленым.
Теперь пора заняться окружением, чтобы не захламлять редактор давайте создадим пустой объект, который назовем environment, он будет хранить в себе окружающие объекты.
Первым делом сделаем загон для нашей змейки, для этого в environment создаем объект куб и устанавливаем координаты в 0, если это не так.
Далее нажатием на куб в отмеченной части переходим в ортографический режим для упрощения редактирования.
И теперь при помощи переключения между осями приводим сцену к следующему виду:
Далее отдаляем камеру и устанавливаем Scale куба по X на 40
Важно! Проверьте, что куб в нулевых координатах.
Далее с выделенной стенкой нажимаем комбинацию клавиш CTRL+D(Создание копии объекта) и с зажатой клавишой CTRL передвигаем новую стенку на 40 юнитов вверх, по оси Z (или можете просто установить значение в инспекторе).
2 стены готовы, остались ещё 2.
Выделяем обе стены одновременно и снова нажимаем CTRL+D, далее выбираем инструмент для вращения и устанавливаем режим редактирования Center, чтобы поворачивать наши стены относительно центра.
Далее зажимаем Ctrl, это позволит нам вращать наши стены на строго заданный угол. Теперь у нас готова коробка.
После этого переходим обратно в перспективную проекцию(нажатием на куб в правом углу сцены) и перемещаем камеру так, чтобы картинка на превью вам понравилась.
Остается дело за малым, украсить это всё. В начале статьи была дана ссылка на графический пакет, берем из него то окружение, которое нам нравится и расставляем по сцене, главное не забудьте, что все эти объекты должны быть дочерними к объекту environment.
У меня получилась следующая картина:
Вроде бы можно на этом закончить настройку окружения, но нет. Сейчас у нас на сцене огромное количество объектов и это тяжеловато отрисовывать, давайте посмотрим на статистику.
Открываем отладчик кадров при помощи Window -> Analysis -> Frame Debugger и запускаем нашу игру. Что мы видим?
Мы видим, что на отрисовку у нас тратится 606 Draw call.
Что такое Draw Call? Это обращение к видеокарте. Когда собирается вся информация о вершинах и отправляется видеокарте на отрисовку. Во время оптимизации мы всегда следим за этим параметром. 606 для такой игры это безумно много. Как же это исправить?
Тут мы можем применить технику статического бэтчинга, это когда Unity попытается собрать воедино все объекты и отрисовать их за меньшее количество обращений. Билд наш станет кушать чуть больше оперативки, ведь хранить все собранные воедино меши где-то надо, но зато мы сильно выиграем в плане количества вызовов отрисовки.
Как мы помним, мы собрали все эти объекты в пустой объект environment.
Теперь мы выделяем его и ставим галочку Static, после чего соглашаясь сделать все дочерние объекты статическими тоже.
После этого снова запускаем игру и видим, что стало всего 40 Draw call, что гораздо меньше.
Создание змейки
Создаем простой 3D объект куб, который будет играть роль змеи.
При желании можете создать новый материал для змеи и присвоить к ней.
Как вообще строится змейка и как она двигается?
Змейка по сути своей состоит из головы и хвоста, который за ней тянется.
А её движение - это история её перемещения, т.е. с каждым ходом блоки смещаются вперед на позицию своего выше стоящего звена.
Создаем папку для скриптов и в ней скрипт Snake
Давайте разберемся, как работает наш скрипт.В Update у нас вызываются методы для поворота и движения, начнем разбор с поворота.
Метод Rotate принимает в себя скорость поворота, а после считывает, нажата ли клавиша A или D, для которых свойственен поворот(это могут быть также стрелочки или другие клавиши, если вы изменяли настройки Axis), умножается на скорость и на время прошедшее с прошлого кадра.
Зачем это домножение? У каждого игрока количество кадров разное, у кого-то 100, у кого-то 200, у кого-то 30, а это значит, что у одного Update выполнится за секунду 30 раз, а у другого 200 и змейка сдвинется на разное расстояние, будет двигаться с разной скоростью(Такое можно заметить в Half-Life, когда спидраннеры изменяют FPS для разгонов)
Домножая на Time.deltaTime мы нормализуем скорость для всех, ведь это время прошедшее с прошлого вызова Update.
Движение головы не сложное, мы просто двигаем голову вперед с учетом скорости.
А вот движение хвоста интересное, его стоит разобрать подробнее.
Обратите внимание на проверку в строке 32. Если между текущей костью и следующей костью дистанция больше, чем дистанция которая должна быть между костьми, то тогда мы подтягивает хвосты поближе. Получается, что мы постоянно меняем их местами, двигая все ближе и ближе. Если же дистанции не достигли, то мы и для других костей не достигли и можно прервать обработку.
Также нам нужна еда. Для еды попрошу создать скрипт и удалить из него методы Start и Update, чтобы он оказался пустым. Еда не выполняет ничего, скрипт нам нужен только для того, чтобы мы могли определить, что столкнулись именно с едой.
Создадим еду, создайте куб на сцене, добавьте на него красный материал, компонент Food который создали. Также на нашем кубе еды есть компонент Box Collider, в нем есть поле Is Trigger, поставьте туда галочку, после чего разместите еду по всей карте.
Чтобы мы могли сталкиваться с едой, нам нужно немного модернизировать голову. На голове уже есть колайдер, но чтобы мы могли взаимодействовать с едой - триггером нам нужно иметь компонент RIgidbody на голове. После добавления Rigidbody снимите галочку с Use Gravity и поставьте галочку напротив Is Kinematic.
Далее возвращаемся в скрипт и дописываем код поедания.
Мы проверяем, есть ли на объекте компонент еда и если есть, то создаем новый кусочек хвоста из префаба и добавляем его в список к хвосту.
В целом у нас получилось создать простейшую змейку, которая может ползать, собирать еду и разростаться.
Также можете посмотреть этот курс на нашей платформе в другом формате и с созданием менюшки, добавлением звуков!
Про static batching полезная инфа, не понимал раньше, как можно уменьшить количество draw calls
Спасибо большое автору за данный пост!)