Я программирую движок радиовещания.
Начальная позиция луча определяется положением игрока, который стоит внутри 2D-сетки.
При наведении луча в направлении я должен определить сетки, которые пересекает луч.
(Подробное описание концепции здесь: http://www.permadi.com/tutorial/raycast/rayc7.html)
Есть небольшая неточность, которая вызывает некоторые проблемы. Я считаю, что проблема вызвана неправильным расчетом шагов сетки.
Однако мне не хватает математического понимания, чтобы решить эту проблему.
Описание проблемы:
Когда луч направляется влево, размер шага пересечения сетки немного отличается от размера шага, когда он направляется вправо.
(Почему меня это вообще волнует ?: Это вызывает проблему, что некоторые горизонтальные пересечения сетки находятся дальше от игрока, чем вертикальные пересечения сетки, когда вертикальные и горизонтальные пересечения находятся близко друг к другу, особенно в углах. Так как я использую разные текстуры для вертикальных пересечений вид горизонтальных стен разрушен, потому что вертикальная текстура используется на небольших частях стены, даже если это горизонтальная стена.)
Эта проблема вызвана недостатком в моем алгоритме? Вот как я вычисляю первое горизонтальное пересечение сетки и размер шага сетки:
Найти первое пересечение сетки:
if (current_angle > 180) {
first_grid_horizontal_y = ((int)p.pos_y / Field::width) * Field::width + Field::width;
} else {
first_grid_horizontal_y = ((int)p.pos_y / Field::width) * Field::width - 1;
}
first_grid_horizontal_x = p.pos_x + (p.pos_y - first_grid_horizontal_y) / tan( 180 - current_angle);
Рассчитать размер шага:
if (current_angle > 180) {
grid_stepsize_horizontal_y = Field::width;
grid_stepsize_horizontal_x = Field::width / tan(current_angle - 180);
} else {
grid_stepsize_horizontal_y = -Field::width;
grid_stepsize_horizontal_x = Field::width / tan(180 - current_angle);
}
Как вы видите, я всегда использую «180 — текущий угол», чтобы определить направление значения x. Это вызывает неточность? Нужно ли больше различать углы?
Тригонометрические функции работают с радианами, а не градусами. Так
tan(180 - current_angle)
должен выглядеть так
tan(Math.Pi - current_angle)
Обратите внимание, что он равен
- tan(current_angle)
Если ваш current_angle в градусах, то:
current_angle_radians = current_angle_degrees * Math.Pi / 180
Я думаю, что ваша неточность исходит от вычитания 1 при движении вверх.
Идея, стоящая за этим, вероятно, заключается в том, что вы хотите получить индекс последнего пикселя блока, но это необязательно: здесь вы выполняете математику с плавающей запятой и y
Значение следующего горизонтального пересечения должно представлять линию между ячейками сетки. Если вы идете вниз, он представляет собой самую верхнюю координату ячейки; если вы идете вверх, это представляет самую нижнюю координату.
(В сторону: (int) y / w
будет округлять до нуля и, таким образом, будет работать только для неотрицательных чисел. Вы могли бы рассмотреть возможность использования floor(x / w)
.)