Как проверить соприкосновение?
Есть два объекта (летящий снаряд и противник), у обоих есть коллайдер, движение происходит и снаряд пролетает сквозь противника, вопрос как определить что снаряд столкнулся?
Я посмотрел примеры и там указывается следующее
void OnCollisionEnter(Collision v)< Debug.Log("tag=>" + v.gameObject.name); if(v.gameObject.name==". ") . >
Это я помещаю в префаб снаряда.
То есть теоретически когда снаряд столкнется с противником должен появится лог с его именем, но ничего нет..
- Вопрос задан более трёх лет назад
- 1901 просмотр
Комментировать
Решения вопроса 1

Griboks @Griboks Куратор тега Unity
Вы точно прочитали документацию и правильно настроили колайдеры? Если нет, то вот вам и ответ. Если да, то, возможно, вам надо поменять метод проверки коллизий на постоянный.
Ответ написан более трёх лет назад
Нравится 1 10 комментариев
Zimaell @Zimaell Автор вопроса
снаряд это куб превращенный в прямоугольник, противник сфера, коллайдеры используются те которые им были выданы при их создании, так же снаряду установлен триггер, что я мог неправильно установить?
Zimaell @Zimaell Автор вопроса
заменил на OnTriggerEnter, работает.
Zimaell @Zimaell Автор вопроса
Не совсем так работает как хотелось бы, при быстром полете видно что снаряд пролетает мимо и тем самым не соприкасается, видно по кадрам что снаряд не касается противника, если конечно сделать медленнее полет то касается, как быть то?

Griboks @Griboks Куратор тега Unity
Zimaell, стандартный метод проверки коллизии — покадровый. Иными словами, в кадре i снаряд не долетел, а в кадре i+1 — уже перелетел. Поэтому необходимо использовать постоянную проверку столкновения.
Zimaell @Zimaell Автор вопроса
то есть все же не через OnTriggerEnter нужно а через OnCollisionEnter?
но так у меня не работает вообще.

Griboks @Griboks Куратор тега Unity
Zimaell, вы точно прочитали документацию?
Zimaell @Zimaell Автор вопроса
Griboks, не понял, еще дополнительно движки физики нужно устанавливать ли я что-то не так понял?
Можете сказать что не так?

Griboks @Griboks Куратор тега Unity
Zimaell, предлагаю вам всё-таки прочитать документацию, чтобы найти ответы на интересующие вас вопросы. Например, в первом абзаце написано:
Unity provides different physics engine implementations which you can use according to your Project needs: 3D, 2D, object-oriented, or data-oriented.
Это означает, что физические движки уже встроены в юнити, и вам не требуется их устанавливать отдельно. А в следующих разделах написано, как правильно настраивать колайдеры, и какие события они активируют при столкновении.
Zimaell @Zimaell Автор вопроса
Griboks, Что-то не совсем пойму, по материалам там куча настроек, у меня вот как
Особо и не разгонишься с настройками.
Проверка на соприкосновение объекта Unity
Знаете кого-то, кто может ответить? Поделитесь ссылкой на этот вопрос по почте, через Твиттер или Facebook.
-
Важное на Мете
Похожие
Подписаться на ленту
Лента вопроса
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.1.8.3130
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Collision.contacts
Благодарим вас за то, что вы помогаете нам улучшить качество документации по Unity. Однако, мы не можем принять любой перевод. Мы проверяем каждый предложенный вами вариант перевода и принимаем его только если он соответствует оригиналу.
Ошибка внесения изменений
По определённым причинам предложенный вами перевод не может быть принят. Пожалуйста попробуйте снова через пару минут. И выражаем вам свою благодарность за то, что вы уделяете время, чтобы улучшить документацию по Unity.
Ваше имя Адрес вашей электронной почты Предложение * Разместить предложенное
public var contacts : ContactPoint[];
public ContactPoint[] contacts ;
Описание
Точки соприкосновения сгенерированные физическим движком.
Каждый контакт содержит точку соприкосновения, нормаль и два сталкивающихся коллайдера (см. ContactPoint). From inside OnCollisionStay or OnCollisionEnter you can always be sure that contacts has at least one element.
function OnCollisionStay(collision : Collision) < for (var contact : ContactPoint in collision.contacts) < print(contact.thisCollider.name + " hit " + contact.otherCollider.name); // Visualize the contact point Debug.DrawRay(contact.point, contact.normal, Color.white); > >
using UnityEngine; using System.Collections;
public class ExampleClass : MonoBehaviour < void OnCollisionStay(Collision collision) < foreach (ContactPoint contact in collision.contacts) < print(contact.thisCollider.name + " hit " + contact.otherCollider.name); Debug.DrawRay(contact.point, contact.normal, Color.white); > > >
// A grenade // - instantiates a explosion prefab when hitting a surface // - then destroys itself
using UnityEngine; using System.Collections;
public class ExampleClass : MonoBehaviour < public Transform explosionPrefab; void OnCollisionEnter(Collision collision) < ContactPoint contact = collision.contacts[0]; Quaternion rot = Quaternion.FromToRotation(Vector3.up, contact.normal); Vector3 pos = contact.point; Instantiate(explosionPrefab, pos, rot); Destroy(gameObject); > >
Прыжок Персонажа
В данной статье мы разберём функцию прыжка, которая довольно часто используется в играх. Для начала нам необходимо объявить две переменные: jumpForce – хранит информацию о силе прыжка, rb – в ней будет храниться ссылка на компонент Rigidbody2D.
private float jumpForce; private Rigidbody2D rb;
Обязательно перетащите компонент Rigidbody2D в поле rb, в окне Inspector.
Далее пишем код непосредственно самого прыжка, помещённый в метод Update():
void Update() < if (Input.GetKeyDown(KeyCode.Space)) < rb.AddForce(new Vector2(rb.velocity.x, jumpForce), ForceMode2D.Impulse); >>
Для того чтобы наш персонаж осуществил прыжок, необходимо, чтобы игрок нажал кнопку Space(пробел). Сам прыжок осуществляется через метод rb.AddForce(). Так как прыжок не затрагивает координаты по оси X, мы оставляем координаты объекта неизменными, с помощью rb.velocity.x. Координаты по оси Y изменим на то значение, которое хранится в переменной jumpForce. ForceMode2D.Impulse является необязательным параметром, который изменяет тип прыжка. Его можно удалить.
Поздравляем, прыжок готов. Но в нём есть небольшая проблема. Мы можем прыгать многократно, летая над землёй бесконечно много. А ведь нам нужно осуществлять прыжки только тогда, когда персонаж находится на земле. Для этого мы должны написать код, который будет определять, находится ли наш персонаж на земле или нет, и заносить данную информацию в переменную, например, в isGrounded. Объявим её:
public bool isGrounded;
Существуют как минимум 4 способа определить, имеется ли под ногами персонажа земля, или её нет. Сейчас мы каждый из этих способов разберём.
1 Способ. Collision2D
В данном способе мы будем использовать класс Collision2D, который реагирует на взаимодействие двух объектов. Мы будем использовать метод OnCollisionEnter2D() – который срабатывает тогда, когда наш объект соприкасается с другим объектом:
private void OnCollisionEnter2D(Collision2D collision) < if (collision.collider.CompareTag("Ground")) < isGrounded = true; >>
Когда наш персонаж соприкасается с другим объектом, происходит проверка на тег данного объекта, с которым соприкаснулся персонаж. И если тег данного объекта будет равняться Ground, то в нашу переменную isGrounded занесётся значение true – что будет означать, что наш персонаж находится на земле. Поэтому, не забудьте создать новый тег Ground, и присвоить его тем объектам, с которых может прыгать наш персонаж.
Когда мы осуществим прыжок, и взаимодействие персонажа с землёй будет разорвано, то нам необходимо указать переменной isGrounded, что персонаж уже не находится на земле. Для этого используем метод OnCollisionExit2D () – который срабатывает тогда, когда соприкосновение двух объектов разрушается.
private void OnCollisionExit2D(Collision2D collision) < if (collision.collider.CompareTag("Ground")) < isGrounded = false; >>
Поздравляем, наш прыжок полностью готов, со всеми необходимыми проверками. Весь готовый код выглядит следующим образом:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Jump1 : MonoBehaviour < private float jumpForce; private Rigidbody2D rb; public bool isGrounded; private void OnCollisionEnter2D(Collision2D collision) < if (collision.collider.CompareTag("Ground")) < isGrounded = true; >> private void OnCollisionExit2D(Collision2D collision) < if (collision.collider.CompareTag("Ground")) < isGrounded = false; >> void Update() < if (Input.GetKeyDown(KeyCode.Space) && isGrounded) < rb.AddForce(new Vector2(rb.velocity.x, jumpForce), ForceMode2D.Impulse); >> >
Способ 2. Trigger2D
Данный способ очень схож на предыдущий, но с одним лишь отличием. Методы типа Trigger2D срабатывают тогда, когда объект входит в область другого объекта. Например, используя метод OnTriggerStay2D(), мы проверяем, вошёл ли наш персонаж в другой объект, имеющий тег Ground:
private void OnTriggerStay2D(Collider2D col) < if (col.CompareTag("Ground")) < Grounded = true; >>
Аналогичный код необходимо прописать и для выхода объекта из другого объекта:
private void OnTriggerExit2D(Collider2D col) < if (col.CompareTag("Ground")) < Grounded = false; >>
Как видите, метод аналогичен предыдущему. Но чтобы этот способ работал, необходимо проделать ещё несколько дополнительных действий, а именно:

- Создать новый тег, например, Ground, и присвоить его к земле, то-есть к тем объектам, с которых можно будет осуществлять прыжки.
- Создать новый объект-пустышку, и поместить его внутрь тех объектов, которые представляют собой землю. А сам объект разместить чуть выше объекта-земли для того, чтобы наш персонаж мог в этот объект войти.
- Добавить в объект-пустышку компонент Box Collider 2D, и поставить галочку в поле isTrigger.
В целом, этот способ не очень удобен, для него необходимо создавать новые объекты, и вкладывать его в объекты типа земли.
Итоговый код выглядит следующим образом:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Jump3 : MonoBehaviour < private float jumpForce; private Rigidbody2D rb; public bool Grounded; private void OnTriggerStay2D(Collider2D col) < if (col.CompareTag("Ground")) < Grounded = true; >> private void OnTriggerExit2D(Collider2D col) < if (col.CompareTag("Ground")) < Grounded = false; >> void Update() < if (Input.GetKeyDown(KeyCode.Space) && isGrounded) < rb.AddForce(new Vector2(rb.velocity.x, jumpForce), ForceMode2D.Impulse); >> >
Способ 3. OverlapCircle
Метод OverlapCircle() довольно часто используется по сравнению с другими способами. Суть данного способа заключается в том, что вокруг персонажа создаётся круговая область. И если в эту область попадает объект типа земля, то мы это записываем в нашу переменную isGrounded. Сейчас мы объявим несколько дополнительных переменных, которые нам понадобятся:
private float groundRadius = 0.3f; public Transform groundCheck; public LayerMask groundMask;
А теперь добавим строку, которая будет определять наличие персонажа на земле, и записывать в переменную isGrounded результат:
isGrounded = Physics2D.OverlapCircle(groundCheck.position, groundRadius, groundMask);
Метод Physics2D.OverlapCircle() принимает 3 параметра. Все эти 3 параметра были объявлены нами чуть выше, в предыдущем коде.
groundCheck.position – это координата точки, которая будет являться центром создаваемой окружности. Обычно для неё создаётся новый игровой объект, и помещается под ноги персонажа.
groundRadius – радиус окружности.
groundMask – название слоя, с которым будет взаимодействовать ваш персонаж, например, слой Ground.
Не забудьте в окне Inspector присвоить игровой объект персонажа полю Transform, и новый слой Ground для LayerMask.

Данный способ очень распространён, возможно потому, что он самый короткий в написании кода. Но что самое главное, у данного способа очень большие перспективы не только для прыжка, но и для реализации других интересных идей. Так же стоит отметить, что и в этом и в предыдущих способах мы можем менять проверки как по тегу, так и по слою, на Ваше усмотрение.
Итоговый код выглядит следующим образом:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Jump3 : MonoBehaviour < private float jumpForce; private Rigidbody2D rb; public bool Grounded; private float groundRadius = 0.3f; public Transform groundCheck; public LayerMask groundMask; isGrounded = Physics2D.OverlapCircle(groundCheck.position, groundRadius, groundMask); void Update() < if (Input.GetKeyDown(KeyCode.Space) && isGrounded) < rb.AddForce(new Vector2(rb.velocity.x, jumpForce), ForceMode2D.Impulse); >> >
Способ 4. Raycas
Данный способ используется довольно редко, но он так же имеет большие возможности в применении, не только в качестве прыжка. Суть данного способа в том, что наш персонаж выпускает луч себе под ноги, который ищет землю под ногами.
Для начала объявим дополнительное поле, которое будет отвечать за длину выпускаемого вниз луча:
public float rayDistance = 0.03f;
Далее выпустим луч от нашего объекта вниз, который будет искать объект на своём пути, имеющий слой Ground. Как мы писали выше, здесь поиск можно использовать как по слою, так и по тегу, как Вам удобно.
RaycastHit2D hit = Physics2D.Raycast(rb.position + Vector2.up * 0.2f, transform.localScale.x * Vector2.down, rayDistance, LayerMask.GetMask("Ground"));
В зависимости от ситуации, в переменную hit попадёт определённое значение, если луч встретит под собой землю. Если же луч земли под собой не обнаружит, то переменная hit получит значение null.
Сейчас мы определить, есть ли значение в переменной hit, или его нет. После чего в переменную isGrounded занесём true или false.
if (hit.collider != null) < isGrounded = true; >else
Проверка завершена. Итоговый код выглядит следующим образом:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Jump4 : MonoBehaviour < private float jumpForce; private Rigidbody2D rb; public bool isGrounded; public float rayDistance = 0.03f; RaycastHit2D hit = Physics2D.Raycast(rb.position + Vector2.up * 0.2f, transform.localScale.x * Vector2.down, rayDistance, LayerMask.GetMask("Ground")); if (hit.collider != null) < isGrounded = true; >else < isGrounded = false; >private void Update() < if (Input.GetKeyDown(KeyCode.Space) && isGrounded) < rb.AddForce(new Vector2(rb.velocity.x, jumpForce), ForceMode2D.Impulse); >>