Если вы еще не знакомы с компонентом твердого тела Rigidbody(2D), то сначала стоит прочитать материал по ссылке: https://dzen.ru/a/Zj4DQvmpzwqzaFAM
Теперь, когда наш персонаж известен физической системе благодаря компоненту Rigidbody(2D), мы сталкиваемся с проблемой.
В играх персонажи и предметы окружения чаще всего имеют очень сложную форму, и графический движок без проблем отрисует их. Но, если физический движок начнет обсчитывать перемещения и столкновения большого количества этих непростых форм, то вычисления станут очень сложными и трудозатратными.
При этом часть спрайтов может вообще не являться твердым телом. Например, перо на шляпе, косички в прическе или развевающийся плащ персонажа не должны мешать перемещению и вызывать ненужные столкновения.
Поэтому наша следующая задача – это сообщить физической системе, какая часть игрового объекта является «твердой». Именно эта часть будет участвовать в коллизиях (столкновениях) с другими объектами на сцене.
Для этого в Unity есть специальные компоненты, которые называются коллайдерами (Collider). Коллайдеры представляют собой простые формы, такие как квадраты или круги, которые физическая система принимает за приблизительную форму игрового объекта, чтобы выполнять свои расчеты столкновений.
Рассмотрим пока простейшие типы коллайдеров, которые чаще всего используются для задания формы именного игровых объектов. Они немного отличаются для двухмерных и трехмерных тел.
Есть еще другие двумерные коллайдеры, но у них специфическая область использования, поэтому с ними вы можете познакомится самостоятельно или изучая другие разделы канала. Например «Tilemap Collider 2D», который используется для тайловой карты.
Трехмерных коллайдеров чуть поменьше.
Специфические трехмерные коллайдеры мы в этом разделе тоже не будем рассматривать.
Коллайдеры могут быть двух типов. Коллайдеры на объекте с компонентом «Rigidbody(2D)», называют динамическими коллайдерами. Обычно это персонажи в игре.
Для создания пола, стен и других неподвижных элементов сцены, к объектам без компонента «Rigidbody(2D)» можно также добавлять коллайдеры. Они называются статическими коллайдерами. Статические коллайдеры могут взаимодействовать с динамическими коллайдерами, но они не сдвинутся в ответ на столкновение, так как сами не обладают компонентом физического тела.
В играх часто присутствуют области какого-то действия (например, зоны урона), а также коллекционные предметы (например, монетки или другие артефакты). Отличие этих объектов в том, что через них персонаж может свободно проходить и они не оказывают влияние на скорость перемещения персонажа. О таких объектах мы поговорим в отдельной статье: https://dzen.ru/a/Zj4SunlxmXyWw7gq
В этой статье мы будем рассматривать только объекты твердых препятствий, через которые персонаж не может пройти.
Рассмотрим применение коллайдеров на примере двумерной игры. Расположим персонажа на сцене, а затем добавим ему компонент физического тела «Rigidbody2D». Что такое компонент и как его добавить можно почитать в статье: https://dzen.ru/a/Za437i6Q937jiND_
Если сейчас запустить игру, то персонаж упадет вниз, так как на него действует сила гравитации. Подробно это разобрано в статье про Rigidbody по ссылке выше.
Давайте добавим для персонажа поверхность земли в виде квадратного спрайта.
Растянем квадрат по размеру сцены и разместим ниже персонажа. Но при запуске игры никакого столкновения не произойдет. Несмотря на то, что персонаж обладает компонентом твердого тела, физическая система не обсчитывает его взаимодействия с другими объектами, потому что у него нет формы, заданной при помощи коллайдера.
Чтобы заставить физическую систему следить за взаимодействиями физического тела с другими объектами нужно выполнить два действия:
- задать форму самому физическому телу
- задать форму другому объекту, с которым твердое тело будет взаимодействовать.
Как только оба игровых объекта при помощи компонента «Collider» приобретут форму, физическая система Unity сможет просчитать их столкновения.
Добавим компонент «Box Collider 2D» для персонажа.
Чтобы увидеть форму коллайдера нажмите на кнопку «Edit Collider» сразу под названием компонента. Вокруг персонажа появится рамка салатового цвета – это и есть коллайдер или форма физического тела. То есть на физической сцене персонаж будет представлять собой не лисенка, а квадрат.
По умолчанию размер коллайдера принимает размеры спрайта. Если у спрайта вокруг рисунка есть пустые поля, то коллайдер будет больше, чем сама картинка персонажа, как в данном случае. Вы можете изменить форму коллайдера, кликая мышкой и перетаскивая маленькие салатовые квадратики на линиях коллайдера. Главное попасть мышкой четко по ним, иначе режим редактирования сбросится и нужно опять будет его включить, нажав кнопку «Edit Collider».
Форма коллайдера не должна быть больше самого изображения игрового объекта, иначе игрок будет замечать, что физическое столкновение было обработано раньше, чем столкновение произошло графически. Но коллайдер можно сделать меньше изображения, для восприятия человеком это будет нормально и комфортно. В данном случае, мы исключаем из твердого тела ушки лисенка, немного хвоста, поскольку в реальной жизни уши и хвост не мешают животным прыгать и пролазить в узкие отверстия.
Аналогичным образом добавим квадратный коллайдер на поверхность ниже персонажа. В данном случае размер самого изображения четко по размерам спрайта, поэтому коллайдер принимает форму четко по границам игрового объекта.
Теперь при запуске игры наш персонаж не упадет дальше поверхности белого прямоугольника.
Таким образом, добавляя к игровому объекту компонент «Rigidbody(2D)» мы подключаем к нему физический движок Unity, который применяет к этому объекту различные силы. Но чтобы подключить отслеживание столкновений игровых объектов необходимо также добавить им форму при помощи компонента «Collider(2D)».
Важно понимать, что столкновение будет обрабатываться физическим движком только в том случае, когда ХОТЯ БЫ ОДИН (или оба) игровых объекта обладают компонентом «Rigidbody(2D)» типа Dynamic. И ОБА игровых объекта имеют форму, заданную при помощи компонента «Collider(2D)».
Добавим слева стену - еще один квадратный спрайт с коллайдером (стену).
Перемещение персонажа реализуем при помощи метода MovePosition(). Подробнее про перемещение твердого тела можно почитать в статье: https://dzen.ru/a/Zj4DQvmpzwqzaFAM
Таким образом можно реализовать простое и четкое перемещение персонажа из одной позиции в другую без учета ускорения и скорости. Но, как уже говорилось ранее, с методом MovePosition() нужно быть аккуратнее. При пошаговом, постепенном перемещении, физический движок стандартно обрабатывает коллизии персонажа с полом и стеной.
Но попробуем резко переместить персонажа в точку, которая находится внутри стены. Координаты этой точки (-7.7, -0.3).
Реализуем это по нажатию клавиши пробел следующим образом. Определим переменную «jump», при помощи которой будем определять нажатие клавиши пробел в методе Update().
Как только клавиша была нажата, значение переменной установим в «true», и в методе FixedUpdate() изменим положение физического тела.
Запустим игру и нажмем клавишу пробела. Персонаж попадет внутрь стены, а затем коллайдер стены его вытолкнет, поскольку твердое тело не может находится внутри другого твердого тела.
В этом особенность работы метода MovePosition(), при резких перемещениях нужно самостоятельно контролировать куда вы перемещаете твердое тело.
При перемещении твердого тела через метод AddForce() или непосредственно через параметр velocity, физическая система прежде, чем переместить твердое тело в новую позицию, проверяет, может ли оно там находится. Если, например, в новой позиции уже находится другое твердое тело, то перемещение не происходит, и тело остается в старой позиции.
Добавим на сцену еще один треугольный объект с коллайдером.
Если попытаться зайти на него персонажем, то персонаж начинает закручиваться.
Это происходит потому, что между двумя коллайдерами возникает трение, и динамический коллайдер из-за этого закручивается. В двумерных играх этот эффект часто не нужен. Чтобы его отключить, у компонента физического тела есть настройки «привязок», которые позволяют игнорировать некоторые компоненты перемещения.
В данном случае необходимо игнорировать вращение вокруг оси Z. Перемещение персонажа теперь будет без закручиваний и падений:
Дополнительно есть возможность убрать перемещение относительно оси Xи Y (свойство «Freeze Position»).
Помимо того, что физический движок Unity самостоятельно обрабатывает коллизии объектов с компонентом коллайдера, он еще и предоставляет методы, при помощи которых мы можем добавить в игру свои события, возникающие при столкновении двух игровых объектов. Например, при столкновении с дверью, ее можно открыть. Или при столкновении с лестницей можно заблокировать перемещение по горизонтали, но разрешить перемещение по вертикали. А когда персонаж отходит от лестницы наоборот - вертикальное перемещение блокируется и разрешается горизонтальное.
Важно, что сейчас мы говорим только про объекты твердых препятствий. Реализация зоны урона или сбора артефактов будет отличаться, об этом можно почитать в статье: https://dzen.ru/a/Zj4SunlxmXyWw7gq
У коллайдеров есть методы, которые физический движок Unity вызывает в определенный момент. Эти методы можно использовать в коде скриптов для того, чтобы добавить свои авторские события.
Для двумерных и трехмерных коллайдеров эти методы немного различаются. Поэтому, если вы работаете над двумерной игрой, то в коде скриптов нужно использовать только методы для двумерных коллайдеров, методы для трехмерных коллайдеров работать не будут.
Методов всего три для каждого типа коллайдеров:
1 Методы касания коллайдеров – вызываются один единственный раз, когда данный коллайдер начинает касаться другого коллайдера. Это первичное касание может быть как одной точкой, так и несколькими сразу.
ОnCollisionEnter2D(Collision2D collision) – метод для двумерных объектов;
OnCollisionEnter(Collision collision) – метод для трехмерных объектов;
Один или оба этих коллайдера должны принадлежать игровому объекту с компонентом Rigidbody(2D)!
Отличие методов заключается в названии, а также в типе входного параметра, который содержит информацию о точках соприкосновения, скорости соударения и т.д.
2 Методы соприкосновения коллайдеров – вызываются каждый кадр, пока данный коллайдер имеет точки соприкосновения с другим коллайдером.
OnCollisionStay2D (Collision2D collision) – метод для двумерных объектов;
OnCollisionStay (Collision collision) – метод для трехмерных объектов;
Один или оба этих коллайдера должны принадлежать игровому объекту с компонентом Rigidbody(2D)!
Отличие методов заключается в названии, а также в типе входного параметра, который содержит информацию о точках соприкосновения, скорости соударения и т.д.
3 Методы расхождения коллайдеров – вызываются один единственный раз, когда данный коллайдер перестает касаться другого коллайдера.
OnCollisionExit2D (Collision2D collision) – метод для двумерных объектов;
OnCollisionExit (Collision collision) – метод для трехмерных объектов;
Один или оба этих коллайдера должны принадлежать игровому объекту с компонентом Rigidbody(2D)!
Отличие методов заключается в названии, а также в типе входного параметра, который содержит информацию о точках соприкосновения, скорости соударения и т.д.
В одном скрипте каждый из перечисленных методов может быть использован только один раз!
Рассмотрим сразу пример, чтобы понять, когда и как работают методы. У нас есть треугольное препятствие - попробуем при соприкосновении его и персонажа вывести на консоль фразу «It’s a collision».
Добавим на треугольное препятствие скрипт «CollisionScript» и откроем его. Принципы работы скриптов можно подробнее изучить по ссылке https://dzen.ru/a/ZdLxUjWs1kpwHFql
При столкновении двух игровых объектов, один из которых имеет компонент Rigidbody(2D), физический движок проверяет наличие скриптов у обоих объектов и в найденных скриптах ищет метод OnCollisionEnter(2D). При наличии такого метода выполняется его код. Если эти методы определены в скриптах обоих объектов, то выполняется код обоих методов.
Поэтому нам нужно в скрипте «CollisionScript» написать метод
OnCollisionEnter2D(). Чтобы правильно и быстро это сделать лучше использовать подсказки. Как подключить подсказки в коде для редактора Visual Studio описано по ссылке https://dzen.ru/a/Y_HtuNSznj1qyrsP
Откройте скрипт и поставьте курсор ниже фигурной скобки метода Update(). Начните набирать фразу «oncol», после чего у вас откроется выпадающее меню, где стрелками можно выбрать нужный метод и нажать клавишу Enter. Можно также два раза кликнуть мышкой по нужному методу.
После этого в коде появится правильная сигнатура метода, которую можно использовать для написания вашего кода.
Добавим вывод на консоль фразы «It’s a collision».
Подробнее про консоль и вывод информации на нее можно почитать по ссылке https://dzen.ru/a/Zbd_J6TwtSEEHWyt
Сохраните скрипт и запустите игру. Если персонаж коснется треугольника, то на консоли появится «It’s a collision».
Аналогичным образом добавим метод OnCollisionStay2D() с выводом на консоль фразы «It’s a STAY collision»
При запуске игры в консоли появится одно сообщение «It’s a collision», а затем будет каждый кадр выводится сообщение «It’s a STAY collision» до тех пор, пока персонаж не отойдет от треугольника.
Аналогичным образом, если добавить в код метод OnCollisionExit2D(), на консоли единственный раз появится сообщение «It’s a EXIT collision». Это сообщение будет самым последним.
Этот скрипт будет одинаково работать, связанный как с объектом треугольника, так и с объектом персонажа. Удалим скрипт с объекта треугольника, и добавим его на объект лисенка.
При запуске игры мы увидим, что сообщения начали генерироваться сразу же, мы даже не двигали никуда персонажа.
Все правильно, в момент старта игры лисенок уже стоит на горизонтальном блоке, который обладает компонентом коллайдера, поэтому скрипт выводит сообщения о столкновении именно с этим горизонтальным блоком.
Но как тогда отделить столкновения с поверхностью земли от столкновений с нужным нам объектом треугольника? Самый простой вариант – использовать теги объектов. О том, что такое тег объекта и как его задать, можно почитать в статье: https://dzen.ru/a/Zj4CkQNX-SOn4ExH
Создадим новый тег «ColorChanger», зададим его треугольнику и реализуем смену цвета объекта при столкновении с персонажем.
Информация об объекте столкновения хранится во входном параметре метода - переменной Collision2D collision. Через нее можно узнать как параметры столкновения, так и получить полный доступ к объекту, с которым произошло столкновение.
В строке 22 проверим, что столкновение произошло с игровым объектом, который имеет тег «ColorChanger». И если это действительно так, то через переменную «collision» обратимся к объекту, с которым произошло столкновение и изменим цвет у компонента SpriteRenderer (для упрощения кода мы опустим проверку наличия компонента).
Сохраните скрипт и запустите игру. Проверьте, что цвет треугольника меняется на красный при столкновении.
Если теперь для прямоугольника слева задать тег «ColorChanger», то он также изменит цвет.
Таким образом при помощи тегов и метода столкновений можно менять состояние игровых объектов в процессе игры.
Работа с трехмерными коллайдерами происходит по такому же алгоритму. Один из трехмерных объектов должен обладать компонентами Rigidbogy и Collider. Другому трехмерному объекту достаточно добавить только компонент коллайдера, после чего он превратится в препятствие для первого объекта. В скриптах можно определить один из методов коллизии, например, OnCollisionEnter(), и в нем изменять состояние игровых объектов.
В этой статье мы говорили только о столкновении твердых тел, но в Unity существует еще один тип коллайдера – триггерный, который позволяет фиксировать столкновения с любым игровым объектом, который обладает компонентом триггерного коллайдера и не оказывает физического воздействия на компонент Rigibody(2D). О таких коллайдерах можно почитать в статье: