XNA,C# - 检查Vector2路径是否穿过另一个Vector2路径

时间:2010-12-21 21:35:10

标签: c# xna collision-detection

对于那些在这些问题上比我自己(数学)有更多经验的人,我有一个XNA问题。

背景:我有一个实现边界类的游戏,它只托管2个Vector2对象,一个起点和一个终点。当前的实现通过假设边界总是垂直或水平来粗略地处理冲突检测,即如果start.x和end.x是相同的检查我不是试图传递x等。

理想情况下,我想要实现的是一个接受两个Vector2参数的方法。第一个是当前位置,第二个是请求的位置(我想将其移动到假设没有异议)。该方法也将接受边界对象。这个方法应该做的是告诉我,如果我要在这一举动中跨越边界。这可能是一个布尔或理想的东西,代表我可以实际移动多远。

这种空洞的方法可能比我能说得更好。

        /// <summary>
    /// Checks the move.
    /// </summary>
    /// <param name="current">The current.</param>
    /// <param name="requested">The requested.</param>
    /// <param name="boundry">The boundry.</param>
    /// <returns></returns>
    public bool CheckMove(Vector2 current, Vector2 requested, Boundry boundry)
    { 
        //return a bool that indicated if the suggested move will cross the boundry.
        return true;
    }

5 个答案:

答案 0 :(得分:2)

我已经提出了一个答案,但这是另一个,类似但又不同的答案:

我会使用点线距离的变体,再次从Wolfram中取出! http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html

如果取公式14,但取下分子中的绝对值(| |),则得到一个有符号的距离。我从来没有听说过签名的距离概念,所以不要指望这个术语是准确的。好的,所以如果原点和目的地的签名距离不同,则意味着原点和目的地位于该线的两侧:

public bool CheckMove(Vector2 current, Vector2 requested, Boundry boundry)
{
    // Assuming you got 2 points in boundry.
    float signedDistanceCurrent = GetSignedDistance(current, boundry.Vector1, boundry.Vector2);
    float signedDistanceRequested = GetSignedDistance(current, boundry.Vector1, boundry.Vector2);

    return signedDistanceRequested * signedDistanceCurrent < 0;
}

public float GetSignedDistance(Vector2 point0, Vector2 point1, Vector2 point2)
{
    // Equation 14 without the |s.
    return ((point2.X-point1.X)*(point1.Y-point0.Y)-(point2.X-point0.X)*(point2.Y-point1.Y))/((point2.X-point1.X)^2+(point2.Y-point1.Y)^2)^(0.5F);
}
顺便说一句,我更喜欢我之前的答案,但这取决于你。

编辑:顺便说一下,用这种方法,你也可以知道碰撞发生的时间:如果你这样做:

float timeFractionToCollision = -signedDistanceCurrent / (signedDistanceRequested - signedDistanceCurrent);

你将获得发生碰撞的时间段的时间分数的一小部分。

答案 1 :(得分:2)

经过一段时间的研究,并且发现了谷歌的正确条款,我有一个解决方案,我刚刚在我的测试床上构建了它,并且它运行良好。

我已经在网上找到了一个例子并对其进行了测试,然后对其进行了更改以满足此问题的需求。应该注意的是,自从测试之后我做了更改,因为我在这台笔记本电脑上只有一台无法运行XNA应用程序的虚拟机,因此我相信它应该可以运行,但可能会有错误。

我们需要做的就是传递一个我们所在的向量,一个我们想要的向量和边界(它实际上是一个由起始和结束向量组成的线)。该方法将告诉我们两条线(一条是当前位置和请求位置之间的路径,另一条是边界)是否交叉。如果他们做交叉参数将作为额外的奖励将告诉我们在哪里。

这是一个非常有用的系统,用于创建强大的碰撞检测。

        /// <summary>
    /// Based on the 2d line intersection method from "comp.graphics.algorithms Frequently Asked Questions"
    /// </summary>
    /// <param name="currentLocation">The current location.</param>
    /// <param name="requestedLocation">The requested location.</param>
    /// <param name="boundary">The boundary.</param>
    /// <param name="collisionVector">The collision vector.</param>
    /// <returns></returns>
    public static bool Intersects(Vector2 currentLocation, Vector2 requestedLocation, Boundary boundary, ref Vector2 collisionVector)
    {
        float q = (currentLocation.Y - boundary.Start.Y) * (boundary.End.X - boundary.Start.X) - (currentLocation.X - boundary.Start.X) * (boundary.End.Y - boundary.Start.Y);
        float d = (requestedLocation.X - currentLocation.X) * (boundary.End.Y - boundary.Start.Y) - (requestedLocation.Y - currentLocation.Y) * (boundary.End.X - boundary.Start.X);

        if (d == 0) 
        {
            return false;
        }

        float r = q / d;

        q = (currentLocation.Y - boundary.Start.Y) * (requestedLocation.X - currentLocation.X) - (currentLocation.X - boundary.Start.X) * (requestedLocation.Y - currentLocation.Y);
        float s = q / d;

        if (r < 0 || r > 1 || s < 0 || s > 1)
        {
            return false;
        }

        collisionVector.X = currentLocation.X + (int)(0.5f + r * (requestedLocation.X - currentLocation.X));
        collisionVector.Y = currentLocation.Y + (int)(0.5f + r * (requestedLocation.Y - currentLocation.Y));
        return true;
    }

答案 2 :(得分:0)

我认为你想要的是找到它们的角度,所以只做X / Y并比较,如果角度相同,它们是平行的。

像这样:

float radians = (float)Math.Atan2(vector.X, vector.Y);

答案 3 :(得分:0)

我认为你要做的是2D光线盒交叉(带有轴对齐的盒子)。您可以找到许多在线算法,包括以下算法:http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter3.htm

答案 4 :(得分:0)

为了满足您的所有数学需求,我建议您先试用MathWorld.Wolfram.Com。这是一篇关于Line-Line Intersection的文章:http://mathworld.wolfram.com/Line-LineIntersection.html

你感兴趣的那部分,包括第四个等式。

使用它,您将获得交叉点坐标。然后,您可以检查在该移动过程中是否会越过该坐标。对于此检查,您可以执行以下操作:

public bool CheckMove(Vector2 current, Vector2 requested, Boundry boundry)
{
    // If your object doesn't move, it can't hit anything!
    if (current.X == requested.X && current.Y == requested.Y) { return false; }

    Vector2 impactPoint = /* Your code to get the impact
                            point from the link above */;

    Vector2 movement = requested - current;
    float timeToImpact = 0;
    // We checked for object movement already, so it's either moving in X, Y or both.
    // I choose to check for X first, but you could check for Y.
    if (movement.X != 0)
    {
        timeToImpact = (impactPoint.X - current.X) / movement.X;
    }
    else
    {
        timeToImpact = (impactPoint.Y - current.Y) / movement.Y;
    }

    // I don't consider a collision at 0 to be a collision since I think
    // it had to be resolved the period before.
    return timeToImpact <= 1 && timeToImpact > 0;
}