2010-12-21 102 views
2

对于那些比我自己(数学)有更多经验的人,我有一个XNA问题。XNA,C# - 检查一个Vector2路径是否跨越另一个Vector2路径

背景:我有一个实现边界类的游戏,它只包含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; 
    } 
+0

这是“边界”矩形,线条,线段还是其他? – 2010-12-21 22:39:09

+0

嗨,约翰,边界是一条线(ops!刚注意到我可怕的拼写)。为了说明问题,解决这个问题的简单方法是将每个Vector2作为边界存储在一个集合中,然后当对象正在移动时检查所述集合以确保我们没有在该集合中找到Vector2。然而,这对于级别开发来说是一个真正的痛苦,而且在旧的处理时间上相当昂贵。因此,由于几乎每一个边界都是一条直线,所以只存储起始和结束vector2对象并且在飞行中以数学方式计算它是否已被击中/穿过是有意义的。希望这有助于 – Nick 2010-12-22 08:23:05

回答

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; 
    } 
0

我想你想要的是找到自己的角度,所以只是做X/Y和比较,如果角度是一样的,他们是平行..

这样的:

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

不起作用。一个角度!= 0意味着“在矢量1上运动的物体是否曾经或将永远处于由矢量2定义的无穷线上”,这不是他想要的,除非我不明白这个问题。 – Tipx 2010-12-21 21:55:19

+0

我认为它会,我明白你在说什么,如果他不是平行的,他不知道他是朝着还是离开第二个向量,但这是问题的第二部分,否则,对于两个值x1和x2 ,如果对于x1,第一个向量的y值小于第二个向量的y值,并且对于x2,它是相反的,它们相交于中间。 – Alex 2010-12-21 22:05:27

0

对于你所有的数学需求,我建议你先在MathWorld.Wolfram.Com上试试。这里是一篇关于直线交叉点的文章:http://mathworld.wolfram.com/Line-LineIntersection.html

你感兴趣的部分是up的,包括第四个方程。

使用它可以得到交点坐标。然后您可以检查该移动过程中是否会穿过该坐标。对于这一检查,你可以这样做:

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; 
} 
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); 

你会得到碰撞发生的时间段时期部分的分数在。