Алгоритм обнаружения пересечения двух линий не дает точных / желаемых результатов в SFML - PullRequest
0 голосов
/ 22 ноября 2018

Я уже несколько дней чесал голову.

В моей 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 и привела к неожиданному поведению.

Проблема решена, спасибо за помощь

...