所以我正在制作一个小游戏,我正在检查角色是否可以“看到”另一个角色A可以看到角色B,如果A在B的某个距离内,并且A的角度方向是+/-角度B的45度朝向。
目前,我正在进行一些计算,我正在检查是否
(facingAngle - 45) =< angleOfTarget =< (facingAngle + 45)
除了当我们穿过360度线时,这种方法很好。
我们说facingAngle = 359, angleOfTarget = 5
。在这种情况下,目标只偏离中心6度,所以我希望我的函数返回true。不幸的是,5不在314和404之间。
答案 0 :(得分:21)
试试
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 :(得分:8)
有一个三角解决方案可以避免包装问题。
我假设你有两个字符P1
和P2
的(x,y)坐标。你已经指定你知道两者之间的距离,你可能用毕达哥拉斯定理计算了它。
您可以使用两个向量的点积来计算它们之间的角度:
A . B = |A| . |B| . cos(theta).
如果您将A
作为facingAngle
向量,它将为[cos(fA), sin(fA)]
,且幅度|A|
为1。
如果您将B
作为两个字符之间的向量,并且您的距离高于:
cos(theta) = (cos(fA) * (P2x - P1x) + sin(fA) * (P2y - P1y)) / |B|
其中|B|
是您已计算的距离。
您无需实际使用反余弦来查找theta
,因为对于-45到+45的范围,您只需要检查cos(theta) >= 0.70710678
(即1 / sqrt(2)
)
这似乎略微复杂,但是你可能已经在你的程序中找到了所有必需的变量。
答案 2 :(得分:8)
这是我在网上找到的一个简单的功能,并进行了修改。 它适用于任何角度(可以在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;
}
EG。检查角度300是否在180到10度之间:
BOOL isBetween=angle_is_between_angles( 300, 180,10);
//返回是
答案 3 :(得分:0)
处理低端包装(转换为负值)的简单解决方案就是为所有值添加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);
答案 4 :(得分:0)
使用始终最小正差并与阈值比较的另一种方法:
anglediff = Math.min(Math.abs(facingAngle - angleOfTarget), 360 - Math.abs(angleOfTarget - allowDirection));
if (anglediff <= 45)
答案 5 :(得分:0)
以不同的方式重述Alnitak的答案,避免角度环绕360度的解决方案是在不同的坐标系中重新解决问题,其中角度总是很小。这是代码:
def inside_angle(facing, target):
dot = cos(facing)*cos(target) + sin(facing)*sin(target)
angle = acos(dot)
return angle <= pi/4
这是使用矢量投影完成的。假设向量&gt; = [cos(面对)罪(面对)]和|目标&gt; = [cos(目标)sin(目标)],当将目标投影到面对矢量时,当目标正好在面向量时或者将增加到任一侧时,角度将从零开始。这样我们就可以将它与pi / 4(45度)进行比较。角度的公式如下:
cos(angle) = <facing|target> / <target|target> <facing|facing>
即,角度的余弦是矢量&gt;之间的点积。和|目标&gt;将它们的模块分开,在这种情况下为1,变为:
angle = acos(<facing|target>)