Как стать автором
Обновить

Is Grounded в 2D платформере: как узнать, стоит ли персонаж?

Время на прочтение 2 мин
Количество просмотров 18K
Буду краток. Бился над этой задачей достаточно долгое время, посему решил поделиться решением. Движок — Unity3D.

Постановка задачи


Есть персонаж, есть платформы. Само собой, на персонаже коллайдер и ригидбоди, всё двадэ. На платформах тоже коллайдеры. На платформах — эффекторы, ибо платформы должны быть твердые только сверху. То есть, если перснаж упал на платформу, он на ней стоит. Но если персонаж идет мимо платформы или прыгает под ней — он свободно проходит через нее.

Персонаж может прыгать, только если стоит на платформе. Нужно знать, стоим ли мы.

Условия:

1) Форма платформы произвольная.
2) Персонаж может стоять на самом краю платформы.
3) Платформы могут быть наклонными.
4) Платформы могут двигаться.

Популярное решение и почему оно не подходит


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

1) Если мы «идем мимо» или «запрыгиваем на», то рэйкаст вполне поймает «землю», хотя персонаж не стоит.
2) Рэйкаст работает по конкретной точке, а не по площади. А значит, если платформа не будет находиться именно под точкой рэйкаста — например, мы стоим на краю платформы, или на маленьком камушке — проверка ее не заметит.

Решение


Решение нельзя получить логически, только опытным путем. Ибо оно проистекает из особенностей работы физики движка. Вам нужны:
using System.Linq — вообще удобная штука, рекомендую ознакомиться, если еще не. Использую для поиска по коллекциям, уничтожает 90% форычей с вложенными ифами.
GetComponent().bounds.min.y — низ вашего коллайдера, то бишь минимальная ордината
OnCollisionStay2D docs.unity3d.com/ScriptReference/Collider2D.OnCollisionStay2D.html
OnCollisionExit2D
CollisionContacts docs.unity3d.com/ScriptReference/Collision-contacts.html docs.unity3d.com/ScriptReference/ContactPoint-point.html

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

Так вот, оказывается, если персонаж стоит на платформе, то геометрически его коллайдер и коллайдер платформы не пересекаются. А значит, «низ персонажа» должен быть ВНЕЗАПНО выше точки контакта. ВСЁ!

1) Создаем список:

List<Collider2D> GroundColliders = new List<Collider2D>();

2) По событию OnCollisionStay2D проверяем и при необходимости добавляем коллайдеры:

void OnCollisionStay2D(Collision2D coll)
{     
     if (!GroundColliders.Contains(coll.collider))   
            foreach (var p in coll.contacts)
                   if (p.point.y < myCollider.bounds.min.y)
                   {
                          GroundColliders.Add(coll.collider);
                          break;
                   }
}

3) Если больше не пересекаемся с платформой — удаляем ее из списка:

void OnCollisionExit2D(Collision2D coll)
    {
        if (GroundColliders.Contains(coll.collider))
            GroundColliders.Remove(coll.collider);
    }

4) Угадайте, что проверяем:

bool IsGrounded
    {
        get
        {
            return GroundColliders.Count > 0;
        }
    }

Просто, понятно, достаточно универсально, безо всяких тегов, рэйкастов, дополнительных геймобжектов. Пользуйтесь на здоровье.
Теги:
Хабы:
+10
Комментарии 19
Комментарии Комментарии 19

Публикации

Истории

Работа

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн