В этой статье разберем как работать с группой физических объектов, рассчитывать и придавать им ускорение в разных направлениях.
В результате попробуем создать, что то похожее на взрывающихся ящиков, где на сцене, нажимая на любой физический объект он взрывается разбрасывая другие объекты которые находятся рядом.
Для начала подготовим сцену, добавим поверхности, стены и сам физический объект в виде ящика. Также добавляем ящику коллайдер BoxCollider2D и компонент Rigidbody2D.
Создаем новый скрипт Box, добавляем в него float переменную explodeForce, в которой будет указана сила взрыва ящика.
- public class Box : MonoBehaviour {
- [Range(0, 1000)]
- public float explodeForce = 100;
- }
Далее запишем новый метод Explode, где будет происходить сам взрыв ящика. Этот метод (Explode) будет вызываться через нажатие на ящик.
- public class Box : MonoBehaviour {
- [Range(0, 1000)]
- public float explodeForce = 100;
- public void Explode() {
- }
- }
Сохраняем этот скрипт и возвращаемся в редактор. Чтобы не писать целый отдельный обработчик нажатий мыши по ящику, воспользуемся уже готовым инструментом под названием Physics 2D Raycaster. Этот компонент позволяет обрабатывать нажатия на физические объекты, что находятся на сцене. Добавим камере этот новый компонент (Physics 2D Raycaster).
и дополнительно создаем новый объект EventSystem, без которого обработчик нажатий (Physics 2D Raycaster) не сможет работать.
Теперь мы можем отловить любые действия мыши над любым физическим объектом, для этого достаточно добавить этому объекту компоненте Event Trigger и выбрать нужное действие.
Так и сделаем – выбираем ящик, добавляем новый компонент Event Trigger
после чего выбираем действие, нажав кнопку Add New Event Type.
Для обработки нажатия можно выбрать событие PointerClick и добавить нужное действие, в нашем случае это действие взрыва Explode.
Возвращаемся в скрипт Box и теперь поработаем над физикой взрыва.
Задача заключается в следующем: при нажатии на ящик, первым делом необходимо выполнить сбор всех рядом стоящих ящиков, и в зависимости от расстояния от взрыва, раскидать их в разных направлениях.
Теперь разобьем эту задачу на части:
- Получить список всех ящиков на сцене вокруг взрыва.
- Рассчитать расстояние и силу взрыва для каждого ящика отдельно.
- Приложить рассчитанную силу и направление движения для каждого отдельного ящика с помощью компонента Rigidbody2D.
- Уничтожить разорвавшийся ящик.
Для начала в методе Awake скрипта Box получим компонент Rigidbody2D самого ящика.
- public class Box : MonoBehaviour {
- [Range(0, 1000)]
- public float explodeForce = 100;
- private Rigidbody2D body;
- private void Awake() {
- this.body = GetComponent<Rigidbody2D>();
- }
- public void Explode() {
- }
- }
Переходим к первому пункту задачи – необходимо получить список всех ящиков, стоящих рядом. Для этого воспользуемся специальным статическим методом OverlapCircleAll класса Physics2D, который вернет все коллайдеры, что находятся рядом.
- private Rigidbody2D body;
- public void Explode() {
- Vector2 position = this.body.position;
- Collider2D[] colliders = Physics2D.OverlapCircleAll(position, 3);
- }
Для примера, попробуем найти все объекты в радиусе 3 ед. от взрыва. Теперь с помощью цикла переберем все объекты из полученного списка colliders.
- private Rigidbody2D body;
- public void Explode() {
- Vector2 position = this.body.position;
- Collider2D[] colliders = Physics2D.OverlapCircleAll(position, 3);
- foreach(Collider2D collider in colliders) {
- Rigidbody2D other = collider.attachedRigidbody;
- }
- }
Сперва необходимо уточнить, есть ли у выбранного объекта компонент Rigidbody2D, чтобы его получить у компонента Collider2D есть свойство attachedRigidbody.
- public void Explode() {
- Vector2 position = this.body.position;
- Collider2D[] colliders = Physics2D.OverlapCircleAll(position, 3);
- foreach(Collider2D collider in colliders) {
- Rigidbody2D other = collider.attachedRigidbody;
- if (other != null && other != this.body) {
- }
- }
- }
Здесь мы выполняем даже две проверки: первая проверка на существование объекта Rigidbody2D, а вторая сравнивает, не является ли выбранный объект тем самым ящиком, который мы хотим взорвать. Переходим к следующему пункту задачи – рассчитываем силу и направления толчка. Чтобы вычислить направление от взрыва необходимо найти разность между позициями ящика и точкой взрыва.
- public void Explode() {
- Vector2 position = this.body.position;
- Collider2D[] colliders = Physics2D.OverlapCircleAll(position, 3);
- foreach(Collider2D collider in colliders) {
- Rigidbody2D other = collider.attachedRigidbody;
- if (other != null && other != this.body) {
- Vector2 direction = (other.position – position).normalized;
- }
- }
- }
В переменную direction записываем направление движения ящика от взрыва. Далее необходимо рассчитать дальность нахождения ящика от центра взрыва, так как в зависимости от расстояния будет меняться и сила толчка.
- public void Explode() {
- Vector2 position = this.body.position;
- Collider2D[] colliders = Physics2D.OverlapCircleAll(position, 3);
- foreach(Collider2D collider in colliders) {
- Rigidbody2D other = collider.attachedRigidbody;
- if (other != null && other != this.body) {
- Vector2 direction = (other.position – position).normalized;
- float distance = (other.position – position).sqrMagnitude;
- }
- }
- }
В переменной distance получаем квадрат расстояние ящика от центра взрыва, после чего можно приступать к расчету силы толчка.
- public void Explode() {
- Vector2 position = this.body.position;
- Collider2D[] colliders = Physics2D.OverlapCircleAll(position, 3);
- foreach(Collider2D collider in colliders) {
- Rigidbody2D other = collider.attachedRigidbody;
- if (other != null && other != this.body) {
- Vector2 direction = (other.position – position).normalized;
- float distance = (other.position – position).sqrMagnitude;
- Vector2 force = direction * this.explodeForce * this.body.mass / distance;
- }
- }
- }
Для получения силы взрыва сперва умножаем направление толчка direction на силу взрыва explodeForce, далее умножаем полученное значение на массу объекта, ведь чем больше масса объекта тем сильнее взрыв, после чего делим все полученное значение на квадрат расстояния distance, так как чем дальше объект тем слабее сила взрыва.
Теперь можно приложить полученную силу толчка к ящику, но просто вызвать метод AddForce у компонента Rigidbody2D будет недостаточно, так как данный метод прикладывает силу к центру объекта, а нам необходимо, чтобы толчок происходил из центра взрыва.
Для того, чтобы приложить силу к физическому объекту относительно его положения на сцене воспользуемся методом AddForceAtPosition компонента Rigidbody2D.
- public void Explode() {
- Vector2 position = this.body.position;
- Collider2D[] colliders = Physics2D.OverlapCircleAll(position, 3);
- foreach(Collider2D collider in colliders) {
- Rigidbody2D other = collider.attachedRigidbody;
- if (other != null && other != this.body) {
- Vector2 direction = (other.position – position).normalized;
- float distance = (other.position – position).sqrMagnitude;
- Vector2 force = direction * this.explodeForce * this.body.mass / distance;
- other.AddForceAtPosition(position, force, ForceMode2D.Impulse);
- }
- }
- }
В предпоследнем пункте задачи, в метод AddForceAtPosition необходимо передать точку из которой будет совершен толчок, для этого воспользуемся переменной position, где находится позиция взрыва, далее задаем саму силу толчка force и тип толчка в виде резкого импульса.
После чего завершаем выполнение задачи и удаляем со сцены взорвавшийся ящик.
- public void Explode() {
- Vector2 position = this.body.position;
- Collider2D[] colliders = Physics2D.OverlapCircleAll(position, 3);
- foreach(Collider2D collider in colliders) {
- Rigidbody2D other = collider.attachedRigidbody;
- if (other != null && other != this.body) {
- Vector2 direction = (other.position – position).normalized;
- float distance = (other.position – position).sqrMagnitude;
- Vector2 force = direction * this.explodeForce * this.body.mass / distance;
- other.AddForceAtPosition(position, force, ForceMode2D.Impulse);
- }
- }
- Destroy(this.gameObject);
- }
Сохраняем скрипт Box и переходим к тестированию.
Добавляем еще несколько ящиков на сцену.
Чтобы взрывы выглядели более эффектней можно добавить подготовить небольшую анимацию взрыва и добавить ее на сцену.
Заключение
В unity для физических объектов есть свои материалы, это не те материалы, в которых используются текстуры и шейдеры, а специальные физические материалы, где указываются параметры скольжения и упругости. Эти физические материалы помогают настраивать взаимодействие коллайдеров между объектами, заставляя их отпрыгивать от поверхностей или скользить по ним.
Добрый день!
Я начинающий seo работник.
Основные понятия по раскрутке имею, но вот имею вопрос:
как составить meta name title?
Мы не обучаем seo. Если Вы планируете работать в этом направлении, то ответ на этот вопрос должны были знать.
13. other.AddForceAtPosition(force,position , ForceMode2D.Impulse); -Правильно