Comments 19
UFO just landed and posted this here
Я, может, не понял проблемы, которую решает автор, но почему нельзя отслеживать контакт с землей просто по коллайду персонажа и платформы?
Раз столкнулся — значит встал на платформу — значит теперь стоит?
Ну и флажок какой "можноПрыгнуть" — прыгнули, сняли флажок, приземлились — включили флажок ?
Раз столкнулся — значит встал на платформу — значит теперь стоит?
Ну и флажок какой "можноПрыгнуть" — прыгнули, сняли флажок, приземлились — включили флажок ?
На платформах — эффекторы, ибо платформы должны быть твердые только сверху. То есть, если персонаж упал на платформу, он на ней стоит. Но если персонаж идет мимо платформы или прыгает под ней — он свободно проходит через нее.
Пересечение с коллайдером ВООБЩЕ не означает, что персонаж стоит на платформе. В этом и сложность.
И да,
Также платформа по тем или иным причинам может исчезнуть из-под персонажа.
приземлились — включили флажок ?— а как узнать, что приземлились? Нулевая вертикальная скорость может быть и в верхней токе прыжка, плюс платформа, на которой мы находимся, может двигаться. Мы можем прыгать из-под платформы и в верхней точке прыжка пересекаться с ней, но все-таки не "встать" на нее — и вот, у перса нулевая скорость, и он пересекается с платформой — НО НЕ СТОИТ.
Также платформа по тем или иным причинам может исчезнуть из-под персонажа.
Game development? 2D? Платформер? И ни одной картинки в статье?
Ну вы, блин, даете. (с)
Ну вы, блин, даете. (с)
Я может чего не понимаю, но: http://docs.unity3d.com/Manual/class-PlatformEffector2D.html
Достаточно установить флажок — Use One Way.
Достаточно установить флажок — Use One Way.
Конечно, можно. Но и что с того? Как это поможет узнать, можно прыгать или нет? Есть ли у вас более простой способ написать код, чтобы персонаж прыгал только если стоит на поверхности?
К тому же, если вы полагаете, что с этим флажком событие коллизии генерируется только "с нужной стороны" — вы ошибаетесь.
К тому же, если вы полагаете, что с этим флажком событие коллизии генерируется только "с нужной стороны" — вы ошибаетесь.
Вот вам видео, где пацан за 2 минуты сделал так, чтобы персонаж прыгал сквозь платформу: https://www.youtube.com/watch?v=acFYSKle6wY
Или же я снова чего-то недопонял?
Или же я снова чего-то недопонял?
Надо, чтобы он прыгал толкьо когда стоит. Задача — в том, чтобы определить, что персонаж прямо сейчас стоит.
Сложно не сделать прыжки и ходьбу сквозь платформу — сложно отследить, что персонаж стоит, с учетом того, что персонаж может прыгать-ходить сквозь платформы, двигатсья вместе с платформами, платформы могут быть наклонными и т. д.
Т.е. ни вертикальная скорость персонажа, ни пересечение с платформой, ни положение платформы и персонажа друг относительно друга не являются показателями того, что персонаж стоит.
Так что недопоняли, да.
Сложно не сделать прыжки и ходьбу сквозь платформу — сложно отследить, что персонаж стоит, с учетом того, что персонаж может прыгать-ходить сквозь платформы, двигатсья вместе с платформами, платформы могут быть наклонными и т. д.
Т.е. ни вертикальная скорость персонажа, ни пересечение с платформой, ни положение платформы и персонажа друг относительно друга не являются показателями того, что персонаж стоит.
Так что недопоняли, да.
Я правильно понял, две платформы могут быть друг над другом, но ближе, чем высота персонажа? можно сказать — "под ногами" и "в поясе"? И тогда, если я иду по нижней платформе, то я могу идти сквозь верхней платформы. А если прыгну — то попаду на верхнюю платформу.
Интересное решение!
Но по статье два "совета":
1 — LINQ хорош для прототипирования, когда нужно быстро понять что куда, но не всегда пригоден для рантайма из-за усиленного выделения памяти. Kаждый запрос — новый объект в куче, причём каждый новый запрос после точки — новый объект. Привет immutability. Поэтому часто на основе используемых решений просто делают конкретную реализацию алгоритма (поиска, агрегации или фильтрации) без дополнительного выделения памяти.
2 — Удалять элемент из списка можно без проверки Contains. Remove просто возвращает false если элемент в списке не найден (в самом Remove проверяется наличие элемента в списке с помощью IndexOf < 0)
Но по статье два "совета":
1 — LINQ хорош для прототипирования, когда нужно быстро понять что куда, но не всегда пригоден для рантайма из-за усиленного выделения памяти. Kаждый запрос — новый объект в куче, причём каждый новый запрос после точки — новый объект. Привет immutability. Поэтому часто на основе используемых решений просто делают конкретную реализацию алгоритма (поиска, агрегации или фильтрации) без дополнительного выделения памяти.
2 — Удалять элемент из списка можно без проверки Contains. Remove просто возвращает false если элемент в списке не найден (в самом Remove проверяется наличие элемента в списке с помощью IndexOf < 0)
Попробовал ради интереса реализовать решение, и вот что получилось в моём случае:
В OnCollisionStay проверяется это хитрое условие на "выше платформы" и оно не выполняется. Более того, на Math.Approximately тоже не выполняется (отрисовал точки дебагом, они выглядели "на одной высоте"). Стал смотреть фактические значения — в моём случае точка контакта оказалась выше нижней точки коллайдера. Приблизил картинку — так и есть. На скриншоте видно, что красная линия (точка контакта) выше синей (нижняя точка коллайдера)
Причём красная линия рисуется от точки контакта, а левая от нижней точки коллайдера. То есть (ещё раз) точка контакта выше нижней точки коллайдера. Проверить таким образом "приземление" не представляется возможным, ибо такой случай возникает чаще всего именно в описанных случаях, которые мы как раз пытаемся избежать (втыкаемся в платформу сбоку, пролетаем через платформу "телом"). Код несколько раз перепроверил, условие именно такое, которое описано в статье:
Видимо ваши звёзды были к вам более благосклонны и вы получили другой результат.
В OnCollisionStay проверяется это хитрое условие на "выше платформы" и оно не выполняется. Более того, на Math.Approximately тоже не выполняется (отрисовал точки дебагом, они выглядели "на одной высоте"). Стал смотреть фактические значения — в моём случае точка контакта оказалась выше нижней точки коллайдера. Приблизил картинку — так и есть. На скриншоте видно, что красная линия (точка контакта) выше синей (нижняя точка коллайдера)
Причём красная линия рисуется от точки контакта, а левая от нижней точки коллайдера. То есть (ещё раз) точка контакта выше нижней точки коллайдера. Проверить таким образом "приземление" не представляется возможным, ибо такой случай возникает чаще всего именно в описанных случаях, которые мы как раз пытаемся избежать (втыкаемся в платформу сбоку, пролетаем через платформу "телом"). Код несколько раз перепроверил, условие именно такое, которое описано в статье:
if (collision.contacts[i].point.y < GroundCheckCollider.bounds.min.y)
Видимо ваши звёзды были к вам более благосклонны и вы получили другой результат.
О да. мои звезды благосклонны. Загадка… Можно в ту формулу внести какую-то дельту
if (point.y — bounds.min.y < 0.001) типа того
if (point.y — bounds.min.y < 0.001) типа того
О, уже первый костыль! А почему именно 0.001? Может в каком-то случае будет больше. У вас на скриншоте как раз коллайдер заметно выше платформы (забегая вперёд — в моём случае эта разница получилась равной 0.0075). Эти волшебные числа до добра не доводят. Было бы интересно разобраться с самим принципом работы этого Box2D — почему в одних случаях коллайдер выше, а в других ниже, и тогда можно было бы с уверенностью использовать подобный способ.
Просто ради интереса — попробуйте изменить нижний коллайдер вашего персонажа на круг, тоже будет немного вниз проваливаться?
Поменял у себя коллайдер на BoxCollider2D и выполнился ваш случай, то есть коллайдер чуть выше платформы. Но в моём случае не получится использовать этот тип коллайдера.
Немного потестил как это всё работает, и получилось, что bounds.min.y для BoxCollider2D находится в центре привязки спрайта (pivot point), а не внизу по умолчанию (только если сама точка привязки в нуле). Синяя линия проводится из точки минимума вправо. Красные линии — точки контакта, тоже вправо:
С CircleCollider2D, как я уже скидывал выше, min.y всегда внизу. После изменения точки привязки картина не поменялась — точка контакта всё так же выше нижней точки коллайдера.
Просто ради интереса — попробуйте изменить нижний коллайдер вашего персонажа на круг, тоже будет немного вниз проваливаться?
Поменял у себя коллайдер на BoxCollider2D и выполнился ваш случай, то есть коллайдер чуть выше платформы. Но в моём случае не получится использовать этот тип коллайдера.
Немного потестил как это всё работает, и получилось, что bounds.min.y для BoxCollider2D находится в центре привязки спрайта (pivot point), а не внизу по умолчанию (только если сама точка привязки в нуле). Синяя линия проводится из точки минимума вправо. Красные линии — точки контакта, тоже вправо:
С CircleCollider2D, как я уже скидывал выше, min.y всегда внизу. После изменения точки привязки картина не поменялась — точка контакта всё так же выше нижней точки коллайдера.
Конечно, я в Unity не профи, но по-моему это какое-то слишком запаренное решение. Во-первых, есть же намного проще и лаконичнее, а во-вторых, уже раза 2 точно видел про это isGrounded на хабре, которые сюда перетекли с просторов англоязычного ютуба.
Sign up to leave a comment.
Is Grounded в 2D платформере: как узнать, стоит ли персонаж?