だから私は、AがBの特定の距離内にあり、A度の方向が+/- 45度である場合に、キャラクターAがキャラクターBを見ることができる、キャラクターが別のキャラクターを「見る」ことができるかどうかをチェックする小さなゲームを作っています。角度Bが向いています。
現在、私は私がチェックしているところに少し計算をします
(facingAngle - 45) =< angleOfTarget =< (facingAngle + 45)
これは、360度の線を越える場合を除いて正常に機能します。
まあ言ってみれば facingAngle = 359, angleOfTarget = 5
。この状況では、ターゲットは中心からわずか6度ずれているので、関数をtrueに戻したいと思います。残念ながら、5は314と404の間にありません。
ちょうど試して
anglediff = (facingAngle - angleOfTarget + 180 + 360) % 360 - 180
if (anglediff <= 45 && anglediff>=-45) ....
その理由は、角度の違いがfacingAngle - angleOfTarget
ラッピング効果によるものですが、360度ずれている場合があります。
180 + 360を加算し、次に360を法として、180を減算すると、事実上、すべてが-180〜180度の範囲に変換されます(360度を加算または減算することにより)。
そうすれば、角度差が-45〜45度以内かどうかを簡単に確認できます。
これは私がオンラインで見つけて変更した簡単な関数です。 どの角度でも正しく機能します(0-360の外側でもかまいません)。 (この関数はcで動作するように作成されており、Xcodeで動作します。)
角度Aから角度BまでCOUNTER-CLOCKWISEをチェックすることを忘れないでください。角度が:)の間にある場合は、[〜#〜] yes [〜#〜](true)を返します。
まず、すべての角度を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);
//はいを返します
Alnitakの答えを別の方法で言い換えると、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>
つまり、角度の余弦は、モジュールを分割したベクトル| faceing>と| target>の間の内積であり、この場合は1であり、次のようになります。
angle = acos(<facing|target>)
常に最小の正の差を使用し、しきい値と比較する別の方法:
anglediff = Math.min(Math.abs(facingAngle - angleOfTarget), 360 - Math.abs(angleOfTarget - allowDirection));
if (anglediff <= 45)
ローエンド(負の値への)での折り返しを処理する簡単な解決策は、すべての値に360を追加することです。
(facingAngle + 315) =< (angleOfTarget + 360) =< (facingAngle + 405)
そうすれば、45の減算は、もはや発生しないため、負になることはありません。
上端での折り返しを処理するには、angleOfTarget
値にanother 360を追加して、もう一度確認する必要があります。
canSee = (facingAngle + 315 <= angleOfTarget + 360) &&
(angleOfTarget + 360 <= facingAngle + 405);
canSee |= (facingAngle + 315 <= angleOfTarget + 720) &&
(angleOfTarget + 720 <= facingAngle + 405);