Я уже несколько дней чесал голову.
В моей 2D-игре сверху вниз у меня есть массив FloatRects, представляющий стены.Я хочу выстрелить в пулю, представленную точкой на расстоянии X от игрока (X - радиус действия оружия).
Я хочу проверить, есть ли стена на траектории пули и есть лиустанавливает новую цель пули в точку столкновения.
Для этого я попытался проверить, пересекается ли сторона прямоугольника с линией траектории моей пули, используя это решение: https://stackoverflow.com/a/1968345/10546991
Я использовал программу, связанную выше, но она дает мне странные результаты, когда цель выше, чем у игрока, пуля которого просто стреляет позади.
Взгляните на следующий пример:
Примечание: в SFML ось Y направлена вниз
A - игрок
B - точка удара или цель пули, называйте ее как хотите.
C - верхняя левая сторона прямоугольника
D - верхняя правая сторона прямоугольника
(2500,2000) = a
(2500, 1300) = b
(2400, 2500) = c
(2600, 2500) = d
S1 = (0, -700)
S2 = (200, 0)
numeratorS = 700 * -100
numeratorT = 200 * -500
denominator = -200 * 700
s = 700 * - 100 / -200 * 700 = -70 000 / -140 000 = 7/14 = 1/2
t = -100 000 / -140 000 = 10 / 14 = 5 / 7
intersectionPoint.x = 2500 + (1/2 * 0) = 2500
intersectionPoint.y = 2000 + (1/2 * -700) = 1650
intersectionPoint (2500,1650)
Так, как вы можете видеть при тестировании, есть ли пересечение между линией междуигрок и бТочка удара ullet и верхняя сторона прямоугольника (который находится под игроком) программа находит пересечение между игроком и пулей!
Я также предоставляю часть кода, которую я использую для обнаруженияколлизии
Vector2f intersectionPoint = target;
//Check if bullet hits a wall and calculate new target
for (int i = 0; i < arraySize; i++)
{
float intersectionPointMagnitude = sqrt(intersectionPoint.x * intersectionPoint.x + intersectionPoint.y * intersectionPoint.y);
//Storing rect corner positions
Vector2f rectTopLeft;
rectTopLeft.x = collisions[i].left;
rectTopLeft.y = collisions[i].top;
Vector2f rectBottomLeft;
rectBottomLeft.x = collisions[i].left;
rectBottomLeft.y = collisions[i].top + collisions[i].height;
Vector2f rectBottomRight;
rectBottomRight.x = collisions[i].left + collisions[i].width;
rectBottomRight.y = collisions[i].top + collisions[i].height;
Vector2f rectTopRight;
rectTopRight.x = collisions[i].left + collisions[i].width;
rectTopRight.y = collisions[i].top;
Vector2f intersectionLeft = intersectionPoint;
if (Maths::vectorsIntersect(start, target, rectTopLeft, rectBottomLeft, intersectionLeft))
{
//We want to set a new target only if the detected collision is closer than the previous one
intersectionLeft = intersectionLeft - start;
float intersectionLeftMagnitude = sqrt(intersectionLeft.x * intersectionLeft.x + intersectionLeft.y * intersectionLeft.y);
if (intersectionLeftMagnitude < intersectionPointMagnitude)
{
intersectionPoint = intersectionLeft;
target = start + intersectionPoint;
}
}
Я просто не могу понять, откуда возникла проблема, поэтому, если кто-нибудь сможет мне помочь, она будет очень признательна.
Редактировать: Вот Maths :: vectorsIntersectчто действительно похоже на функцию в ссылке выше
bool vectorsIntersect(Vector2f A, Vector2f B, Vector2f C, Vector2f D, Vector2f& intersectionPoint)
{
Vector2f S1 = B - A;
Vector2f S2 = D - C;
//Calculate scalar parameters
float denominator = (S1.x * S2.y - S1.y * S2.x);
//We can't divide by 0!
if (denominator == 0.0f)
return false;
//S & T have the same denominator
float numeratorS = (S1.x * (A.y - C.y) - S1.y * (A.x - C.x));
float numeratorT = (S2.x * (A.y - C.y) - S2.y * (A.x - C.x));
float s, t;
s = numeratorS / denominator;
t = numeratorT / denominator;
//Check for intersection point
if (abs(s) > 0.0f && abs(s) < 1.0f && abs(t) > 0.0f && abs(t) < 1.0f)
{
//Return intersection point
intersectionPoint.x = A.x + (t * S1.x);
intersectionPoint.y = A.y + (t * S1.y);
return true;
}
return false;
}
РЕДАКТИРОВАТЬ 2: Хорошо, теперь я чувствую себя глупо, в моей функции Maths :: vectorIntersect я проверял, находятся ли абсолютные значения как s, так и t между 0 и 1, чтоВот почему при скалярных параметрах, где между -0 и -1, функция вернула true и привела к неожиданному поведению.
Проблема решена, спасибо за помощь