- PVSM.RU - https://www.pvsm.ru -
Буду краток. Бился над этой задачей достаточно долгое время, посему решил поделиться решением. Движок — Unity3D.
Есть персонаж, есть платформы. Само собой, на персонаже коллайдер и ригидбоди, всё двадэ. На платформах тоже коллайдеры. На платформах — эффекторы, ибо платформы должны быть твердые только сверху. То есть, если перснаж упал на платформу, он на ней стоит. Но если персонаж идет мимо платформы или прыгает под ней — он свободно проходит через нее.
Персонаж может прыгать, только если стоит на платформе. Нужно знать, стоим ли мы.
Условия:
1) Форма платформы произвольная.
2) Персонаж может стоять на самом краю платформы.
3) Платформы могут быть наклонными.
4) Платформы могут двигаться.
В стандартном примере из ассет-стора предлагается использовать дополнительный геймобжект под персонажем, кидать из персонажа рэйкасты в геймобжект и следить, нет ли пересечения с землей.
1) Если мы «идем мимо» или «запрыгиваем на», то рэйкаст вполне поймает «землю», хотя персонаж не стоит.
2) Рэйкаст работает по конкретной точке, а не по площади. А значит, если платформа не будет находиться именно под точкой рэйкаста — например, мы стоим на краю платформы, или на маленьком камушке — проверка ее не заметит.
Решение нельзя получить логически, только опытным путем. Ибо оно проистекает из особенностей работы физики движка. Вам нужны:
GetComponent().bounds.min.y — низ вашего коллайдера, то бишь минимальная ордината
OnCollisionStay2D docs.unity3d.com/ScriptReference/Collider2D.OnCollisionStay2D.html [1]
OnCollisionExit2D
CollisionContacts docs.unity3d.com/ScriptReference/Collision-contacts.html [2] docs.unity3d.com/ScriptReference/ContactPoint-point.html [3]
OnCollisionStay2D срабатывает, когда персонаж и платформа движутся друг относительно друга. При попадании персонажа на платформу т.е. при OnCollisionEnter2D вышеуказанное событие тоже сработает.
Так вот, оказывается, если персонаж стоит на платформе, то геометрически его коллайдер и коллайдер платформы не пересекаются. А значит, «низ персонажа» должен быть ВНЕЗАПНО выше точки контакта. ВСЁ!
1) Создаем список:
List<Collider2D> GroundColliders = new List<Collider2D>();
2) По событию OnCollisionStay2D проверяем и при необходимости добавляем коллайдеры:
void OnCollisionStay2D(Collision2D coll)
{
foreach (var p in coll.contacts)
if (p.point.y < myCollider.bounds.min.y)
{
if (!GroundColliders.Contains(coll.collider))
GroundColliders.Add(coll.collider);
}
}
3) Если больше не пересекаемся с платформой — удаляем ее из списка:
void OnCollisionExit2D(Collision2D coll)
{
if (GroundColliders.Contains(coll.collider))
GroundColliders.Remove(coll.collider);
}
4) Угадайте, что проверяем:
bool IsGrounded
{
get
{
return GroundColliders.Count > 0;
}
}
Просто, понятно, достаточно универсально, безо всяких тегов, рэйкастов, дополнительных геймобжектов. Пользуйтесь на здоровье.
Автор: Neongrey
Источник [4]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/unity3d/115152
Ссылки в тексте:
[1] docs.unity3d.com/ScriptReference/Collider2D.OnCollisionStay2D.html: http://docs.unity3d.com/ScriptReference/Collider2D.OnCollisionStay2D.html
[2] docs.unity3d.com/ScriptReference/Collision-contacts.html: http://docs.unity3d.com/ScriptReference/Collision-contacts.html
[3] docs.unity3d.com/ScriptReference/ContactPoint-point.html: http://docs.unity3d.com/ScriptReference/ContactPoint-point.html
[4] Источник: https://habrahabr.ru/post/279407/
Нажмите здесь для печати.