用于检测两条线是否相交的算法在SFML中未给出准确/想要的结果

时间:2018-11-22 16:10:57

标签: c++ coordinates sfml

我已经为此抓了几天。

在我的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)

因此,您可以在测试播放器与子弹的撞击点之间的线与矩形的顶部(位于播放器下方)之间是否存在交点时看到该程序,从而在播放器与子弹!

我还提供了用于检测碰撞的部分代码

    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和导致了意外的行为。

问题已解决,谢谢您的帮助

0 个答案:

没有答案