Итак, это проблема, которую я пытался выяснить уже довольно давно. Mine - 2D платформерная игра с миром, состоящим из (обычно) неподвижных плиток и мобильных спрайтов, которые используют AABB для представления своих хитбоксов. Эта игра НЕ основана на сетке из-за некоторых сложностей с перемещением слоев плиток.
Я могу обнаружить столкновения и легко определить глубину столкновения. Я использую «метод наименьшей оси», чтобы определить, каким образом разрешить столкновение между спрайтом и плиткой. Если спрайт расположен глубже по горизонтали, чем по вертикали, то направление разрешения - вверх или вниз. Если спрайт находится глубже по вертикали, чем по горизонтали, направление разрешения - левое или правое.
Это достаточно просто и работает довольно хорошо. То есть до тех пор, пока спрайт не столкнется с более чем одним тайлом. Поскольку по своей природе каждое столкновение должно проверяться отдельно, разные столкновения могут иметь разное направление для разрешения. Например, если спрайт пытается пройти по ряду плиток, для одного кадра они будут пересекать следующую плитку, например что горизонтальная глубина меньше, чем вертикальная глубина. Поскольку столкновение говорит «разрешить влево», оно будет отброшено назад и застрянет в углу.
Я обдумывал эту проблему снова и снова в течение достаточно долгого времени, и ко мне пришли несколько решений, но у всех есть недостатки. Я мог бы пометить некоторые стороны как недостижимые, но без движка на основе сетки определение «недостижимости» является чрезвычайно сложным, особенно с возможностью перемещения слоев плиток.
Я полагаю, что другим возможным способом было бы предсказать столкновения до того, как они произойдут, и «отработать» движение до точки столкновения, но я не уверен, как работает математика для этого.
Я чувствую, что упускаю что-то невероятно очевидное, тем более что игры 80-х уже решили эту проблему.
Ответы:
Проблема
Проблема заключается в вашем методе разрешения столкновений. Ваш метод выглядит следующим образом:
Проблема в том, что он может легко перемещать игрока в неправильном направлении. Вы можете увидеть, как это может произойти на изображении ниже:
Поскольку игрок движется вниз вправо и находится над землей, можно ожидать, что игрок приземлится на землю (возле зеленой рамки). Но вместо этого он отталкивается от земли слева (обозначается красной рамкой). Это может быть проблемой, если игрок пытается прыгнуть с одной платформы на другую, потому что игрок может в конечном итоге погибнуть из-за неверного кода столкновения.
Решение
Решение этой проблемы на самом деле довольно просто. Вместо того, чтобы использовать вышеупомянутый метод, вы разрешаете столкновение следующим образом:
Теперь я надеюсь, что вы не выбросили свой код проверки глубины, потому что он вам все еще понадобится для шагов 3 и 6.
Чтобы разрешить столкновение между плитками на любой из двух осей (после перемещения игрока), вы сначала получаете глубину столкновения. Затем вы берете глубину столкновения и вычитаете ее из осей, которые вы в настоящее время проверяете на столкновение. Обратите внимание, что глубина должна быть отрицательной, если вы двигаетесь влево, чтобы игрок двигался в правильном направлении.
Используя этот метод, вам не только не нужно беспокоиться об ошибках коллизий, подобных той, что в сценарии на изображении выше, но этот метод также может обрабатывать коллизии с несколькими тайлами.
Пример кода:
источник
float
s для хранения своих координат. Так что это вызывало дрожь. Решением было округлить координаты, когда я закончил разрешать столкновения.Вы переосмысливаете проблему и объединяете пару вопросов. Но это нормально, потому что, как вы сказали, это очень решенная проблема с множеством отличных ответов.
Давайте разберемся с этим:
Tilemaps . Ваш первый пример - спрайт, идущий по пачке плиток, выложенных горизонтально (или скольжение по стене плиток, выложенных вертикально, они изоморфны). Одним из очень элегантных решений этого является просто не проверять края плиток, к которым, как мы знаем, спрайт не может добраться, такие как ребра, которые находятся «под землей», или ребра, граничащие с другой полностью сплошной плиткой.
Вы правы, что спрайт спускается из-за силы тяжести, затем движется вбок, затем застревает ... но ответ заключается в том, чтобы не заботиться о левом или правом краях плиток под землей . Таким образом, ваша процедура разрешения столкновений перемещает спрайт только вертикально - и ваш спрайт может идти своим чередом.
Ознакомьтесь с учебными пособиями по плитке Metanet для пошагового объяснения этого. В своем вопросе вы говорите, что не используете традиционную карту листов, но это тоже нормально: статические плитки находятся в карте листов и обновляются, как указано выше, при перемещении платформ и таких обновлениях, как # 2 ниже.
Другие AABB . Вы столкнетесь с проблемой только в том случае, если в одном кадре ваш спрайт сможет переместиться на расстояние, превышающее ширину / высоту большинства AABB в вашей игре. Если это не так, вы золотые: устраняйте коллизии один за другим, и все будет работать отлично.
Если AABB могут перемещаться очень быстро в одном кадре, то вы должны «смести» движение при проверке столкновений: разбейте движение на более мелкие дроби и проверяйте столкновения на каждом шаге.
источник