2010-12-21 48 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); 

你會得到碰撞發生的時間段時期部分的分數在。

相關問題