Is Grounded в 2D платформер: як дізнатися, чи варто персонаж?

Буду коротким. Бився над цим завданням досить довгий час, тому вирішив поділитися рішенням. Движок — Unity3D.

Постановка завдання

Є персонаж, є платформи. Само собою, на персонажі коллайдер і ригидбоди, всі двадэ. На платформах теж колайдери. На платформах — ефектори, бо платформи повинні бути тверді тільки зверху. Тобто, якщо перснаж впав на платформу, він на ній стоїть. Але якщо персонаж йде повз платформи або стрибає під нею — він вільно проходить через неї.

Персонаж може стрибати, тільки якщо стоїть на платформі. Потрібно знати, чи ми стоїмо.

Умови:

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

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


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

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

Рішення

Рішення можна отримати логічно, тільки досвідченим шляхом. Бо воно випливає з особливостей роботи фізики движка. Вам потрібні:

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)
{ 
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;
}
}

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

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.