В настоящее время у меня есть платформер с плитками для ландшафта (графика позаимствована у Cave Story). Игра написана с нуля с использованием XNA, поэтому я не использую существующий движок или физический движок.
Столкновения плитки описываются в точности так, как описано в этом ответе (с простым SAT для прямоугольников и окружностей), и все работает отлично.
За исключением случаев, когда игрок врезается в стену во время падения / прыжка. В этом случае они поймают плитку и начнут думать, что достигли пола или потолка, которых на самом деле нет.
На этом скриншоте игрок движется вправо и падает вниз. Таким образом, после движения проверяются столкновения - и сначала выясняется, что персонаж игрока сталкивается с плиткой 3-й от пола и толкается вверх. Во-вторых, он сталкивается с плиткой рядом с собой и отталкивается вбок - конечный результат заключается в том, что персонаж игрока думает, что он на земле и не падает, и «цепляется» за плитку до тех пор, пока он на нее бежит. ,
Я мог бы решить это, задав вместо этого плитки сверху вниз, что заставило бы его плавно упасть, но затем произошел обратный случай, и он столкнулся с потолком, которого не было, когда прыгнул вверх к стене.
Как мне подойти к решению этой проблемы, чтобы персонаж игрока мог просто упасть вдоль стены, как и должен?
источник
Ответы:
Самый простой, более надежный подход - просто не проверять столкновения на скрытых ребрах. Если у вас две настенные плитки, одна над другой, то нижний край верхней плитки и верхний край нижней плитки не должны проверяться на столкновение с игроком.
Вы можете определить, какие ребра действительны во время простого прохода по карте листов, сохраняя внешние края в качестве флагов в каждом местоположении листов. Вы также можете просто сделать это во время выполнения, проверяя соседние плитки во время обнаружения столкновений.
Существуют более продвинутые версии этой же техники, которые облегчают и ускоряют поддержку неквадратных плиток.
Я рекомендую вам прочитать статьи ниже. Они представляют собой простое введение в основы физики и обнаружения столкновений в современных платформерах (таких как Cave Story). Если вы хотите почувствовать себя в духе старой школы Марио, есть еще несколько хитростей, о которых нужно беспокоиться, но большинство из них включают в себя обработку прыжков и анимации, а не столкновения.
http://www.metanetsoftware.com/technique/tutorialA.html http://www.metanetsoftware.com/technique/tutorialB.html
источник
Здесь порядок я бы сделал вещи ....
1) Сохранить текущий X, Y символа
2) Переместить направление X
3) Проверьте все углы символа, получив данные плитки, и проверьте, является ли он твердым, выполнив следующие действия: (X и Y - позиция символа)
... чтобы получить правильные данные плитки из картографических данных
4) Если какая-либо из плиток сплошная, вам нужно переместить X в наилучшее возможное положение, восстановив сохраненный X и ...
5) Повторите 2-4, используя Y
Если ваш персонаж выше плитки, вам нужно проверить больше плиток. Для этого вам нужно зациклить и добавить tileHeight в позицию персонажа, чтобы получить плитку
Если символ шире, чем 1 блок, сделайте то же самое, но замените CharacterY, CharacterHeight, TileHeight и т. Д. На CharacterX, CharacterWidth и т. Д.
источник
Что, если вы проверили возможность столкновения как часть метода движения игрока и отклонили движение, которое заставило игрока скользить в другой объект? Это предотвратит попадание игрока «внутрь» блока, и поэтому он не может быть «сверху» блока под ним.
источник
Я столкнулся почти с той же проблемой в игре, над которой я сейчас работаю. Я решил, что нужно сохранить область перекрывающейся части при тестировании на коллизии, а затем обработать эти коллизии на основе их приоритета (сначала наибольшую область), а затем дважды проверить каждую коллизию, чтобы увидеть, была ли она уже разрешена ранее. обработки.
В вашем примере область столкновения по оси X будет больше, чем по оси Y, поэтому она будет обработана первой. Затем, прежде чем пытаться обработать столкновение по оси Y, он проверит и увидит, что оно больше не сталкивается после перемещения по оси X. :)
источник
Простое, но не идеальное решение - изменить форму окна столкновения игрока, чтобы оно не было квадратом. Отрежьте углы, чтобы он был похож на восьмиугольник или что-то подобное. Таким образом, когда он сталкивается с плиткой, подобной плитке на стене, он соскользнет с нее и не будет пойман. Это не идеально, потому что вы все еще можете заметить, что он немного ловит углы, но он не застрянет, и его очень легко реализовать.
источник
Очень похожая проблема была рассмотрена в этом уроке: Введение в разработку игр . Соответствующая часть видео находится на 1:44 , объясняя с диаграммами и фрагментами кода.
Обратите внимание, что 14-tilemap.py содержит проблему отсечения, но она исправлена в 15-blocker-sides.py
Я не могу точно объяснить, почему последний пример учебника не обрезается, в то время как ваш код делает, но я думаю, что это как-то связано с:
self.resting
в коде используется только для проверки того, может ли игрок прыгнуть. Несмотря на это, я не могу заставить игрока совершить «двойной» прыжок со стены. Хотя теоретически это может быть возможно)источник
Другой метод (на который я ответил на вопрос, связанный с Byte56) - проверить, помещает ли разрешение столкновения символ в пустое место или нет. Таким образом, в вашей задаче вы получаете столкновение с потолка внутреннего прямоугольника, чтобы переместить его вверх, что было бы недопустимо (поскольку вы все еще сталкиваетесь с другой плиткой). Вместо этого вы перемещаете его только в том случае, если вы перемещены в свободное пространство (например, как столкновение с верхней плитки переместит вас влево), и как только вы обнаружите это столкновение, все готово.
В ответе, который я дал, был код, но он стал слишком сложным. Я бы отслеживал все столкновения в течение этого периода времени и выбирал только тот, который приводил к свободному пространству. Однако, если бы их не было, я думаю, что я прибегнул к сбросу позиции персонажа в его последнюю позицию, однако это действительно уродливо, и, возможно, вы бы предпочли реализовать что-то вроде оригинального Марио, где он просто двигается в одном направлении или что-то, когда нет свободного пространства. возможно. Также вы могли бы отсортировать этот список разрешений коллизий и перемещаться только в свободное пространство с наименьшим расстоянием (я думаю, что решение будет наиболее предпочтительным, хотя я не кодировал для этого).
источник
Я только сделал 3 SAT в 3D, так что, возможно, я не понимаю это правильно. Если я понимаю вашу проблему, это может быть связано с тем, что контакты с осью контакта не могут быть возможными, в результате чего игрок ведет себя так, как будто есть пол. Возможно, одним из обходных путей может быть использование формы круга для вашего персонажа, тогда вы будете получать контактные оси только в направлении оси X при ударе о стену.
источник