27

だから私は、キャラクターが別のキャラクターを「見る」ことができるかどうかをチェックする小さなゲームを作っています.AがBから一定の距離内にあり、Aの角度の方向が+/- 45度の場合、キャラクターAはキャラクターBを見ることができます.角度 B が向いています。

現在、私は少し計算を行っています。

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

これは、360 度の線を越える場合を除き、正常に機能します。

としましょうfacingAngle = 359, angleOfTarget = 5。この状況では、ターゲットは中心から 6 度しか離れていないので、関数が true を返すようにします。残念ながら、5 は 314 と 404 の間にありません。

4

6 に答える 6

35

ちょうど試して

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

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

その理由は、角度の違いが、facingAngle - angleOfTargetラッピング効果により 360 度ずれる可能性があるためです。

180 + 360 を加算し、次に 360 を法として、180 を減算すると、事実上すべてが -180 から 180 度の範囲に変換されます (360 度を加算または減算することによって)。

すると角度差が-45度から45度以内かどうか簡単に確認できます。

于 2012-09-02T08:58:49.260 に答える
13

これは、オンラインで見つけて変更した簡単な関数です。どの角度でも正しく機能します (0 ~ 360 の範囲外でもかまいません)。(この関数は c で動作するように作成されており、Xcode で動作します。)

角度 A から角度 B まで反時計回りにチェックすることを思い出してください。角度が :)

まず、すべての角度を 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);

//はいを返します

于 2015-04-18T18:38:18.433 に答える
9

ラッピングの問題を回避する三角解があります。

P1文字との両方に (x, y) 座標があると仮定していますP2。おそらくピタゴラスの定理を使用して計算したと思われる2つの間の距離を知っていることをすでに指定しています。

2 つのベクトルの内積を使用して、それらの間の角度を計算できます。

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

ベクトルAとして取ると、 になり、大きさは 1 になります。facingAngle[cos(fA), sin(fA)]|A|

B2 つの文字の間のベクトルとして、上の距離を取得すると、次のようになります。

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

|B|、すでに計算した距離です。

-45 から +45 の範囲では(つまり)thetaを確認するだけでよいので、を見つけるために実際に逆余弦を取る必要はありません。cos(theta) >= 0.707106781 / sqrt(2)

これは少し複雑に思えるかもしれませんが、いずれにせよ、必要なすべての変数が既にプログラム内にぶら下がっている可能性があります。

于 2012-09-02T09:14:07.147 に答える
1

下限 (負の値) での折り返しを処理する簡単な解決策は、すべての値に 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);
于 2012-09-02T08:55:41.900 に答える
0

常に最小の正の差を使用し、しきい値と比較する別の方法:

anglediff = Math.min(Math.abs(facingAngle - angleOfTarget), 360 - Math.abs(angleOfTarget - allowDirection));
if (anglediff <= 45)
于 2015-10-09T10:14:33.283 に答える
0

Alnitak の回答を別の方法で言い換えると、360 度での角度のラップを回避する解決策は、角度が常に小さい別の座標系で問題を言い直すことです。コードは次のとおりです。

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

    return angle <= pi/4

これは、ベクトル射影を使用して行われます。ベクトル |facing> = [cos(facing) sin(facing)] および |target> = [cos(target) sin(target)] と仮定すると、ターゲットを向きベクトルに射影すると、角度はゼロからの範囲になります。ターゲットは正対するベクトルにあるか、どちらかの側に増加します。このようにして、それを pi/4 (45 度) と比較することができます。角度の式は次のとおりです。

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

つまり、角度のコサインは、ベクトル |facing> と |target> のドット積をモジュールで割ったもので、この場合は 1 で、次のようになります。

angle = acos(<facing|target>)

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

于 2016-07-21T23:33:53.930 に答える