2012-09-02 101 views
16

所以我正在一點遊戲,我檢查如果一個字符可以「看到」之間的另一種,其中人物A可以看到人物B,如果A是B的一個特定距離內,其方向A的角度是B角度所面對的+/- 45度。計算如果角度是兩個角度

目前,我做一個小小的計算,其中我檢查,如果

(facingAngle - 45) =< angleOfTarget =< (facingAngle + 45) 

除了當我們越過360度線也能正常工作。

比方說facingAngle = 359, angleOfTarget = 5。在這種情況下,目標距離中心只有6度,所以我希望我的函數返回true。不幸的是,5是不是和404

+0

的〔確定如果角度處於其他2角之間]可能的複製(http://stackoverflow.com/questions/11406189/determine-if-angle-lies-在2個其他角度之間) – sschuberth

回答

14

試試看

anglediff = (facingAngle - angleOfTarget + 180 + 360) % 360 - 180 

if (anglediff <= 45 && anglediff>=-45) .... 

的原因是差角度是facingAngle - angleOfTarget雖然由於包裝效果,可能會關閉360度。

添加180 + 360然後模360然後減180,實際上只是將所有內容都轉換爲範圍-180到180度(通過增加或減少360度)。

然後你可以很容易地檢查角度差,它是否在-45到45度之間。

+1

在第一我認爲它沒有在主題的情況下工作,但後來我在Python中測試..工作!於是我回到帕斯卡去弄清楚它爲什麼不在那裏工作,事實證明帕斯卡爾的'mod'不支持負數...... – JHolta

+1

這在faceAngle爲0而angleOfTarget爲359的情況下失敗,例如。 除非我失去了一些東西,否則你會得到(0 - 359 + 180)%360 - 180 = -359。 在facesAngle - angleOfTarget減法周圍需要絕對值。 –

+0

在Java中完全測試(Android)。有用。 – pascalbros

0

一個簡單的解決方案來處理在低端包裝紙(成負值)314之間,僅僅是增加360到所有的值:

(facingAngle + 315) =< (angleOfTarget + 360) =< (facingAngle + 405) 

這樣, 45的減法永遠不會消極,因爲它不再發生。

要在高端處理包裹,則需要再次檢查,增加另一個 360到angleOfTarget值:

canSee = (facingAngle + 315 <= angleOfTarget + 360) && 
      (angleOfTarget + 360 <= facingAngle + 405); 
canSee |= (facingAngle + 315 <= angleOfTarget + 720) && 
      (angleOfTarget + 720 <= facingAngle + 405); 
8

有一個三角函數的解決方案,避免了包裝問題。

我假設你有兩個字符P1P2的(x,y)座標。你已經指定你知道你使用畢達哥拉斯定理推算出的兩者之間的距離。

可以使用點積兩向量來計算它們之間的角度:

A . B = |A| . |B| . cos(theta). 

如果你把AfacingAngle載體將是[cos(fA), sin(fA)],也就有了大小的1 |A|

如果你把B作爲兩個字符之間的載體,和你的距離上面你:

cos(theta) = (cos(fA) * (P2x - P1x) + sin(fA) * (P2y - P1y))/|B| 

其中|B|是您已計算的距離。

因爲對於-45到+45的範圍,您只需要檢查cos(theta) >= 0.70710678(即1/sqrt(2)),您不需要實際採用反餘弦來找到theta

這看起來好像有點很複雜,但有可能你已經在程序中有了所有必需的變量。

6

這是我在網上找到的一個簡單功能,並進行了修改。 它適用於任何角度(可以在0-360之外)。 (此功能是由在C工作,工作在Xcode。)

請記住,這從一個角度檢查逆時針角度B.它返回YES(真),如果角度之間:)

首先,簡單的轉換功能,使各個角度1-360

//function to convert angle to 1-360 degrees 
static inline double angle_1to360(double angle){ 
angle=((int)angle % 360) + (angle-trunc(angle)); //converts angle to range -360 + 360 
if(angle>0.0) 
return angle; 
else 
return angle + 360.0; 
} 

檢查角度:)

//check if angle is between angles 
static inline BOOL angle_is_between_angles(float N,float a,float b) { 
N = angle_1to360(N); //normalize angles to be 1-360 degrees 
a = angle_1to360(a); 
b = angle_1to360(b); 

if (a < b) 
return a <= N && N <= b; 
return a <= N || N <= b; 
} 

之間

例如,要檢查是否角300是180和10度之間:

BOOL isBetween=angle_is_between_angles(300, 180,10); 

//返回是

+1

如果將trunc()替換爲Math.floor(),似乎適用於Java。 – mindoverflow

0

使用總是最小正差和與閾值進行比較的另一種方法:

anglediff = Math.min(Math.abs(facingAngle - angleOfTarget), 360 - Math.abs(angleOfTarget - allowDirection)); 
if (anglediff <= 45) 
0

重申發佈參宿的答案以不同的方式,避免360度角度纏繞的解決方案是在角度始終很小的不同座標系中重新解決問題。以下是代碼:

def inside_angle(facing, target): 
    dot = cos(facing)*cos(target) + sin(facing)*sin(target) 
    angle = acos(dot) 

    return angle <= pi/4 

這是使用矢量投影完成的。假設面向> = [cos(朝向)sin(朝向)]並且| target> = [cos(target)sin(target)],則當將目標投影到面向量中時,角度將從零開始範圍,目標正好在面向向量處或將增加到任一側。這樣我們可以將它與pi/4(45度)進行比較。爲角度的公式如下:

cos(angle) = <facing|target>/<target|target> <facing|facing> 

即,角度的餘弦是矢量之間的點積|面向>和|目標>劃分它們的模塊,在這種情況下是1,這變爲:

angle = acos(<facing|target>) 

參考: https://en.wikipedia.org/wiki/Vector_projection