Найти в Дзене

Коллизии твердых тел. Компонент Collider.

Если вы еще не знакомы с компонентом твердого тела Rigidbody(2D), то сначала стоит прочитать материал по ссылке: https://dzen.ru/a/Zj4DQvmpzwqzaFAM

Теперь, когда наш персонаж известен физической системе благодаря компоненту Rigidbody(2D), мы сталкиваемся с проблемой.

В играх персонажи и предметы окружения чаще всего имеют очень сложную форму, и графический движок без проблем отрисует их. Но, если физический движок начнет обсчитывать перемещения и столкновения большого количества этих непростых форм, то вычисления станут очень сложными и трудозатратными.

При этом часть спрайтов может вообще не являться твердым телом. Например, перо на шляпе, косички в прическе или развевающийся плащ персонажа не должны мешать перемещению и вызывать ненужные столкновения.

Поэтому наша следующая задача – это сообщить физической системе, какая часть игрового объекта является «твердой». Именно эта часть будет участвовать в коллизиях (столкновениях) с другими объектами на сцене.

Для этого в Unity есть специальные компоненты, которые называются коллайдерами (Collider). Коллайдеры представляют собой простые формы, такие как квадраты или круги, которые физическая система принимает за приблизительную форму игрового объекта, чтобы выполнять свои расчеты столкновений.

Рисунок 1. Графическая и физическая сцены в Unity
Рисунок 1. Графическая и физическая сцены в Unity

Рассмотрим пока простейшие типы коллайдеров, которые чаще всего используются для задания формы именного игровых объектов. Они немного отличаются для двухмерных и трехмерных тел.

Рисунок 2. Простейшие двумерные коллайдеры
Рисунок 2. Простейшие двумерные коллайдеры

Есть еще другие двумерные коллайдеры, но у них специфическая область использования, поэтому с ними вы можете познакомится самостоятельно или изучая другие разделы канала. Например «Tilemap Collider 2D», который используется для тайловой карты.

Трехмерных коллайдеров чуть поменьше.

Рисунок 3. Простейшие трехмерные коллайдеры
Рисунок 3. Простейшие трехмерные коллайдеры

Специфические трехмерные коллайдеры мы в этом разделе тоже не будем рассматривать.

Коллайдеры могут быть двух типов. Коллайдеры на объекте с компонентом «Rigidbody(2D)», называют динамическими коллайдерами. Обычно это персонажи в игре.

Для создания пола, стен и других неподвижных элементов сцены, к объектам без компонента «Rigidbody(2D)» можно также добавлять коллайдеры. Они называются статическими коллайдерами. Статические коллайдеры могут взаимодействовать с динамическими коллайдерами, но они не сдвинутся в ответ на столкновение, так как сами не обладают компонентом физического тела.

В играх часто присутствуют области какого-то действия (например, зоны урона), а также коллекционные предметы (например, монетки или другие артефакты). Отличие этих объектов в том, что через них персонаж может свободно проходить и они не оказывают влияние на скорость перемещения персонажа. О таких объектах мы поговорим в отдельной статье: https://dzen.ru/a/Zj4SunlxmXyWw7gq

В этой статье мы будем рассматривать только объекты твердых препятствий, через которые персонаж не может пройти.

Рассмотрим применение коллайдеров на примере двумерной игры. Расположим персонажа на сцене, а затем добавим ему компонент физического тела «Rigidbody2D». Что такое компонент и как его добавить можно почитать в статье: https://dzen.ru/a/Za437i6Q937jiND_

Рисунок 4. Объект персонажа с компонентом физического тела
Рисунок 4. Объект персонажа с компонентом физического тела

Если сейчас запустить игру, то персонаж упадет вниз, так как на него действует сила гравитации. Подробно это разобрано в статье про Rigidbody по ссылке выше.

Давайте добавим для персонажа поверхность земли в виде квадратного спрайта.

Рисунок 5. Добавление квадратного спрайта
Рисунок 5. Добавление квадратного спрайта

Растянем квадрат по размеру сцены и разместим ниже персонажа. Но при запуске игры никакого столкновения не произойдет. Несмотря на то, что персонаж обладает компонентом твердого тела, физическая система не обсчитывает его взаимодействия с другими объектами, потому что у него нет формы, заданной при помощи коллайдера.

Рисунок 6. Падение персонажа
Рисунок 6. Падение персонажа

Чтобы заставить физическую систему следить за взаимодействиями физического тела с другими объектами нужно выполнить два действия:

- задать форму самому физическому телу

- задать форму другому объекту, с которым твердое тело будет взаимодействовать.

Как только оба игровых объекта при помощи компонента «Collider» приобретут форму, физическая система Unity сможет просчитать их столкновения.

Добавим компонент «Box Collider 2D» для персонажа.

Рисунок 7. Компонент коллайдера
Рисунок 7. Компонент коллайдера

Чтобы увидеть форму коллайдера нажмите на кнопку «Edit Collider» сразу под названием компонента. Вокруг персонажа появится рамка салатового цвета – это и есть коллайдер или форма физического тела. То есть на физической сцене персонаж будет представлять собой не лисенка, а квадрат.

Рисунок 8. Редактирование формы коллайдера
Рисунок 8. Редактирование формы коллайдера

По умолчанию размер коллайдера принимает размеры спрайта. Если у спрайта вокруг рисунка есть пустые поля, то коллайдер будет больше, чем сама картинка персонажа, как в данном случае. Вы можете изменить форму коллайдера, кликая мышкой и перетаскивая маленькие салатовые квадратики на линиях коллайдера. Главное попасть мышкой четко по ним, иначе режим редактирования сбросится и нужно опять будет его включить, нажав кнопку «Edit Collider».

Рисунок 9. Измененная форма коллайдера
Рисунок 9. Измененная форма коллайдера

Форма коллайдера не должна быть больше самого изображения игрового объекта, иначе игрок будет замечать, что физическое столкновение было обработано раньше, чем столкновение произошло графически. Но коллайдер можно сделать меньше изображения, для восприятия человеком это будет нормально и комфортно. В данном случае, мы исключаем из твердого тела ушки лисенка, немного хвоста, поскольку в реальной жизни уши и хвост не мешают животным прыгать и пролазить в узкие отверстия.

Аналогичным образом добавим квадратный коллайдер на поверхность ниже персонажа. В данном случае размер самого изображения четко по размерам спрайта, поэтому коллайдер принимает форму четко по границам игрового объекта.

Рисунок 9. Измененная форма коллайдера
Рисунок 9. Измененная форма коллайдера

Теперь при запуске игры наш персонаж не упадет дальше поверхности белого прямоугольника.

Рисунок 11. Коллизия двух объектов
Рисунок 11. Коллизия двух объектов

Таким образом, добавляя к игровому объекту компонент «Rigidbody(2D)» мы подключаем к нему физический движок Unity, который применяет к этому объекту различные силы. Но чтобы подключить отслеживание столкновений игровых объектов необходимо также добавить им форму при помощи компонента «Collider(2D)».

Важно понимать, что столкновение будет обрабатываться физическим движком только в том случае, когда ХОТЯ БЫ ОДИН (или оба) игровых объекта обладают компонентом «Rigidbody(2D)» типа Dynamic. И ОБА игровых объекта имеют форму, заданную при помощи компонента «Collider(2D)».

Добавим слева стену - еще один квадратный спрайт с коллайдером (стену).

Рисунок 12. Объект стены
Рисунок 12. Объект стены

Перемещение персонажа реализуем при помощи метода MovePosition(). Подробнее про перемещение твердого тела можно почитать в статье: https://dzen.ru/a/Zj4DQvmpzwqzaFAM

Рисунок 13. Скрипт перемещения персонажа
Рисунок 13. Скрипт перемещения персонажа

Таким образом можно реализовать простое и четкое перемещение персонажа из одной позиции в другую без учета ускорения и скорости. Но, как уже говорилось ранее, с методом MovePosition() нужно быть аккуратнее. При пошаговом, постепенном перемещении, физический движок стандартно обрабатывает коллизии персонажа с полом и стеной.

Но попробуем резко переместить персонажа в точку, которая находится внутри стены. Координаты этой точки (-7.7, -0.3).

Рисунок 14. Положение для перемещения твердого тела
Рисунок 14. Положение для перемещения твердого тела

Реализуем это по нажатию клавиши пробел следующим образом. Определим переменную «jump», при помощи которой будем определять нажатие клавиши пробел в методе Update().

Как только клавиша была нажата, значение переменной установим в «true», и в методе FixedUpdate() изменим положение физического тела.

Рисунок 15. Скрипт с реализацией перемещения
Рисунок 15. Скрипт с реализацией перемещения

Запустим игру и нажмем клавишу пробела. Персонаж попадет внутрь стены, а затем коллайдер стены его вытолкнет, поскольку твердое тело не может находится внутри другого твердого тела.

В этом особенность работы метода MovePosition(), при резких перемещениях нужно самостоятельно контролировать куда вы перемещаете твердое тело.

При перемещении твердого тела через метод AddForce() или непосредственно через параметр velocity, физическая система прежде, чем переместить твердое тело в новую позицию, проверяет, может ли оно там находится. Если, например, в новой позиции уже находится другое твердое тело, то перемещение не происходит, и тело остается в старой позиции.

Добавим на сцену еще один треугольный объект с коллайдером.

Рисунок 16. Треугольное препятствие
Рисунок 16. Треугольное препятствие

Если попытаться зайти на него персонажем, то персонаж начинает закручиваться.

Это происходит потому, что между двумя коллайдерами возникает трение, и динамический коллайдер из-за этого закручивается. В двумерных играх этот эффект часто не нужен. Чтобы его отключить, у компонента физического тела есть настройки «привязок», которые позволяют игнорировать некоторые компоненты перемещения.

Рисунок 17. Привязки для компонента физического тела
Рисунок 17. Привязки для компонента физического тела

В данном случае необходимо игнорировать вращение вокруг оси Z. Перемещение персонажа теперь будет без закручиваний и падений:

Дополнительно есть возможность убрать перемещение относительно оси Xи Y (свойство «Freeze Position»).

Помимо того, что физический движок Unity самостоятельно обрабатывает коллизии объектов с компонентом коллайдера, он еще и предоставляет методы, при помощи которых мы можем добавить в игру свои события, возникающие при столкновении двух игровых объектов. Например, при столкновении с дверью, ее можно открыть. Или при столкновении с лестницей можно заблокировать перемещение по горизонтали, но разрешить перемещение по вертикали. А когда персонаж отходит от лестницы наоборот - вертикальное перемещение блокируется и разрешается горизонтальное.

Важно, что сейчас мы говорим только про объекты твердых препятствий. Реализация зоны урона или сбора артефактов будет отличаться, об этом можно почитать в статье: https://dzen.ru/a/Zj4SunlxmXyWw7gq

У коллайдеров есть методы, которые физический движок Unity вызывает в определенный момент. Эти методы можно использовать в коде скриптов для того, чтобы добавить свои авторские события.

Для двумерных и трехмерных коллайдеров эти методы немного различаются. Поэтому, если вы работаете над двумерной игрой, то в коде скриптов нужно использовать только методы для двумерных коллайдеров, методы для трехмерных коллайдеров работать не будут.

Методов всего три для каждого типа коллайдеров:

1 Методы касания коллайдеров – вызываются один единственный раз, когда данный коллайдер начинает касаться другого коллайдера. Это первичное касание может быть как одной точкой, так и несколькими сразу.

ОnCollisionEnter2D(Collision2D collision) – метод для двумерных объектов;

OnCollisionEnter(Collision collision) – метод для трехмерных объектов;

Рисунок 18. Методы касания коллайдеров
Рисунок 18. Методы касания коллайдеров

Один или оба этих коллайдера должны принадлежать игровому объекту с компонентом Rigidbody(2D)!

Отличие методов заключается в названии, а также в типе входного параметра, который содержит информацию о точках соприкосновения, скорости соударения и т.д.

2 Методы соприкосновения коллайдеров – вызываются каждый кадр, пока данный коллайдер имеет точки соприкосновения с другим коллайдером.

OnCollisionStay2D (Collision2D collision) – метод для двумерных объектов;

OnCollisionStay (Collision collision) – метод для трехмерных объектов;

Рисунок 19. Методы соприкосновения коллайдеров
Рисунок 19. Методы соприкосновения коллайдеров

Один или оба этих коллайдера должны принадлежать игровому объекту с компонентом Rigidbody(2D)!

Отличие методов заключается в названии, а также в типе входного параметра, который содержит информацию о точках соприкосновения, скорости соударения и т.д.

3 Методы расхождения коллайдеров – вызываются один единственный раз, когда данный коллайдер перестает касаться другого коллайдера.

OnCollisionExit2D (Collision2D collision) – метод для двумерных объектов;

OnCollisionExit (Collision collision) – метод для трехмерных объектов;

Рисунок 20. Методы расхождения коллайдеров
Рисунок 20. Методы расхождения коллайдеров

Один или оба этих коллайдера должны принадлежать игровому объекту с компонентом 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. Можно также два раза кликнуть мышкой по нужному методу.

Рисунок 21. Добавление метода при помощи подсказок
Рисунок 21. Добавление метода при помощи подсказок

После этого в коде появится правильная сигнатура метода, которую можно использовать для написания вашего кода.

Рисунок 22. Код скрипта с методом
Рисунок 22. Код скрипта с методом

Добавим вывод на консоль фразы «It’s a collision».

Подробнее про консоль и вывод информации на нее можно почитать по ссылке https://dzen.ru/a/Zbd_J6TwtSEEHWyt

Рисунок 23. Вывод на консоль
Рисунок 23. Вывод на консоль

Сохраните скрипт и запустите игру. Если персонаж коснется треугольника, то на консоли появится «It’s a collision».

Рисунок 24. Вывод на консоль
Рисунок 24. Вывод на консоль

Аналогичным образом добавим метод OnCollisionStay2D() с выводом на консоль фразы «It’s a STAY collision»

Рисунок 25. Код скрипта с методом
Рисунок 25. Код скрипта с методом

При запуске игры в консоли появится одно сообщение «It’s a collision», а затем будет каждый кадр выводится сообщение «It’s a STAY collision» до тех пор, пока персонаж не отойдет от треугольника.

Рисунок 26. Вывод на консоль
Рисунок 26. Вывод на консоль

Аналогичным образом, если добавить в код метод OnCollisionExit2D(), на консоли единственный раз появится сообщение «It’s a EXIT collision». Это сообщение будет самым последним.

Этот скрипт будет одинаково работать, связанный как с объектом треугольника, так и с объектом персонажа. Удалим скрипт с объекта треугольника, и добавим его на объект лисенка.

Рисунок 27. Объект треугольника без скрипта
Рисунок 27. Объект треугольника без скрипта
Рисунок 28. Объект персонажа со скриптом столкновений
Рисунок 28. Объект персонажа со скриптом столкновений

При запуске игры мы увидим, что сообщения начали генерироваться сразу же, мы даже не двигали никуда персонажа.

Рисунок 29. Сообщения о столкновении при запуске игры
Рисунок 29. Сообщения о столкновении при запуске игры

Все правильно, в момент старта игры лисенок уже стоит на горизонтальном блоке, который обладает компонентом коллайдера, поэтому скрипт выводит сообщения о столкновении именно с этим горизонтальным блоком.

Рисунок 29. Сообщения о столкновении при запуске игры
Рисунок 29. Сообщения о столкновении при запуске игры

Но как тогда отделить столкновения с поверхностью земли от столкновений с нужным нам объектом треугольника? Самый простой вариант – использовать теги объектов. О том, что такое тег объекта и как его задать, можно почитать в статье: https://dzen.ru/a/Zj4CkQNX-SOn4ExH

Создадим новый тег «ColorChanger», зададим его треугольнику и реализуем смену цвета объекта при столкновении с персонажем.

Рисунок 31. Тег для объекта треугольника
Рисунок 31. Тег для объекта треугольника

Информация об объекте столкновения хранится во входном параметре метода - переменной Collision2D collision. Через нее можно узнать как параметры столкновения, так и получить полный доступ к объекту, с которым произошло столкновение.

Рисунок 32. Скрипт столкновения
Рисунок 32. Скрипт столкновения

В строке 22 проверим, что столкновение произошло с игровым объектом, который имеет тег «ColorChanger». И если это действительно так, то через переменную «collision» обратимся к объекту, с которым произошло столкновение и изменим цвет у компонента SpriteRenderer (для упрощения кода мы опустим проверку наличия компонента).

Сохраните скрипт и запустите игру. Проверьте, что цвет треугольника меняется на красный при столкновении.

Если теперь для прямоугольника слева задать тег «ColorChanger», то он также изменит цвет.

Рисунок 33. Задание тег игровому объекту
Рисунок 33. Задание тег игровому объекту

Таким образом при помощи тегов и метода столкновений можно менять состояние игровых объектов в процессе игры.

Работа с трехмерными коллайдерами происходит по такому же алгоритму. Один из трехмерных объектов должен обладать компонентами Rigidbogy и Collider. Другому трехмерному объекту достаточно добавить только компонент коллайдера, после чего он превратится в препятствие для первого объекта. В скриптах можно определить один из методов коллизии, например, OnCollisionEnter(), и в нем изменять состояние игровых объектов.

В этой статье мы говорили только о столкновении твердых тел, но в Unity существует еще один тип коллайдера – триггерный, который позволяет фиксировать столкновения с любым игровым объектом, который обладает компонентом триггерного коллайдера и не оказывает физического воздействия на компонент Rigibody(2D). О таких коллайдерах можно почитать в статье:

https://dzen.ru/a/Zj4SunlxmXyWw7gq