Блок обнаружения столкновений в мире - PullRequest
1 голос
/ 19 марта 2012

В настоящее время я работаю над механизмом блочных миров в XNA и не могу правильно настроить обнаружение и обработку столкновений.Мир находится в массиве, индексированном с помощью (z * width * width + y * width + x) и содержащем различные блоки, представленные байтами.Все отлично и денди.Или так я думал.

Я пробовал разные методы для обработки столкновений, и в настоящее время я использую версию, в которой я рассчитываю направление игроков / камер, и перед добавлением его в позицию я проверяю каждый отдельный вектор (x, y и z) со смещением на половину единиц (чтобы компенсировать размер блока 1,0) по отношению к миру и применять его только тогда, когда результат равен нулю.Все идет нормально.Теперь проблема возникает, когда я иду прямо в угол, потому что оси X и Z не пересекаются / не сталкиваются, пока я не попал в куб.

Итак, как мне правильно рассчитать столкновение?обнаружение и обработка в мире блоков?

Мне бы очень хотелось получить некоторую информацию по этому вопросу, желательно на более высоком / концептуальном уровне, но примеры кода, конечно, приветствуются.



Чтобы более подробно объяснить мою ситуацию, основываясь на ответе @ A-Type:

Итак, давайте уточним здесь, чтобы помочь мне понять вас.У моего персонажа всего одна единица, большая во всех направлениях, что должно упростить ситуацию.

Прежде всего, вы говорите, я должен сначала обновить положение своих персонажей, а после проверять столкновения?Это был бы мой предпочтительный способ обнаружения столкновений, но если будет проще, я сначала проверю, а если возможно, перейду позже.

Ну, я понимаю, что игрок может пересекать только 8 кубов (в вашем примере 12) и округление, кажется, тоже очень хорошая идея, но я не совсем вижу переход от 12 кубов (опять же, в вашем примере, мой будет 8) к только 3. Не вызывает ли это ту же проблему, что и углыкуб персонажа не будет принят во внимание?

Я пытался реализовать это, но не смог, поэтому я подумал, что больше теории может сделать это.(Я действительно включил функцию обнаружения столкновений, но в этих случаях я полностью потерял скорость, а не только в направлении столкновения.)



Спасибо за ваше время!Karl

Ответы [ 2 ]

1 голос
/ 29 марта 2012

Хорошо, тогда давайте еще раз попробуем. Существует две основные фазы обнаружения столкновений в любой эффективной системе. Есть широкая и узкая фаза, если хотите. Широкая фаза использует неточные, но дешевые методы, чтобы определить, могут ли два объекта пересекаться, и передать их в узкую фазу. Узкая фаза принимает два наших объекта-кандидата и применяет более сложную физику для опосредования столкновения.

В мире сеток у нас есть очень простой и выгодный метод для широкофазного столкновения. Это сама сетка. Мы можем использовать позицию и размер игрока, чтобы определить 8 блоков, которые он может пересекать (теперь мы будем использовать ваш случай). Обратите внимание, что в моем первоначальном ответе мне показалось, что я говорил о том, чтобы сузить его до 3 блоков - я делал его более сложным, чем нужно, особенно для символа с 1 блоком. Самый простой способ заключается в следующем: округлите центр вашего персонажа до угла сетки, то есть там, где пересекаются углы 8 блоков. Затем выберите эти 8 блоков для узкофазного тестирования. Обязательно используйте округление средней точки , а не округление по полу, как это используется по умолчанию при работе с целыми числами. То есть, если значение равно 1,53, оно должно округляться до 2, а 1,49999 - до 1.

Теперь, узкая фаза, которую я на самом деле не очень много охватываю. Вы спросили, стоит ли двигаться первым или после, я думаю, что вам нужно сначала сделать это. Я не мастер симуляции физики, но я знаю, что вы сначала хотите рассчитать направление столкновения (центр персонажа минус центр блока). Глубина - это длина этого вектора. Если ваши блоки имеют ширину 1, то вы не хотите, чтобы эта длина была меньше 1; это показывает, что они пересекаются (в некоторой степени в основном).

Теперь есть много способов «восстановить» объекты после столкновения. Я бы предложил определить, по какой оси объекты сталкиваются меньше . То есть, если компонент X вашего вектора направления столкновения является наименьшим, это означает, что ваш игрок находится ближе всего к из столкновения в направлении X. Приложите противодействующую силу в этом направлении, пропорциональную глубине столкновения в направлении X. Или, если вы выберете, просто установите положение вашего персонажа на расстояние, которое вы хотите убрать, и не напрягайтесь силами. Но вы хотите перемещать персонажа только в одном кардинальном направлении. Это делает вещи проще и не мешает движению вдоль земли или вдоль стен.

Подумайте об этом так: скажем, каждый кадр вашего персонажа падает .3 в землю под действием силы тяжести. Теперь предположим, что он находится в центре блока, когда он попадает в этот кадр. Это означает, что его глубина столкновения с блоком под ним составляет (0,5, 0,3, 0,5) (где X в боковом направлении, Y в верхнем положении, а Z в прямом направлении). Если вы примените восстанавливающую силу во всех этих направлениях, вы будете перемещать игрока влево, назад и назад по земле. Этот последний бит - единственная часть, которую вы хотели сделать. Поэтому игнорируйте большие оси столкновения и восстанавливайте только по меньшей (Y). Теперь горизонтальное движение вашего персонажа беспрепятственно, и он остается над землей.

1 голос
/ 20 марта 2012

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

Предполагая, что у вас есть трехмерный массив байтов для ваших блоков, где 0 - это пустое пространство,Я настоятельно рекомендую округлить позицию вашего игрока до набора пространств сетки в вашем мире и проверить, не является ли какое-либо из этих пространств не 0. Затем выполните код обработки столкновений для непустых блоков.

ДляНапример, если ваш персонаж имеет рост 2 и ширину / глубину 1 (как Стив из Minecraft), он может максимально пересекать 12 пространств сетки одновременно (4 над головой, 4 вокруг его талии и 4 ниже его ног), иминимум 2 (если он идеально выровнен по сетке).

Переведите тело вашего персонажа в сетку.Округлите положение персонажа до ячейки сетки, затем проверьте 12 пробелов вокруг него (если он 2x1).Если они не пусты, выполните разрешение столкновений между этими блоками и вашим персонажем.Какие соседние блоки, которые вы проверяете, зависят от того, в каком направлении вы округлили. Например, если позиция вашего персонажа была (3.4, 2.7, 1.1), вы можете округлить ее до (3, 3, 1), а затем проверить блоки, которые на 1 БОЛЬШЕ внаправление X, 1 МЕНЬШЕ в направлении Y и 1 БОЛЬШЕ в направлении Z, потому что вы округлили ВНИЗ, ВВЕРХ и ВНИЗ соответственно.

Надеюсь, возможно, это понятно.Если нет, просто прокомментируйте.В частности, я не знаю, почему, но я не могу объяснить эту концепцию так хорошо, как следовало бы, тем более, что я занимаюсь такими вещами уже почти год.

...