IsFacing and IsBehind calculations
本文关键字:calculations IsBehind and IsFacing | 更新日期: 2023-09-27 17:59:10
我正在寻找更好的方法来计算一个对象是面对另一个还是在另一个后面。到目前为止,我已经能够创建这个,但它似乎没有100%正确工作:(
我还认为应该是弧度,而不是度。
public static float GetAngle(float x1, float y1, float x2, float y2)
{
float xDiff = x2 - x1;
float yDiff = y2 - y1;
var angle = RadianToDegree((float)Math.Atan2(yDiff, xDiff));
if (angle < 0)
return 360 + angle;
return angle;
}
public static bool IsFacing(Point obj, float rotationAngle, Point target, float arcDegree = 180)
{
var angleBetweenPoints = GetAngle(obj, target);
return rotationAngle >= angleBetweenPoints - arcDegree / 2 && rotationAngle <= angleBetweenPoints + arcDegree / 2;
}
public static bool IsBehind(Point obj, float rotationAngle, Point target, float arcDegree = 180)
{
var angleBetweenPoints = GetAngle(obj, target);
var backViewAngle = rotationAngle > 180 ? rotationAngle - 180 : 180 - rotationAngle;
return backViewAngle >= angleBetweenPoints - arcDegree / 2 && backViewAngle <= angleBetweenPoints + arcDegree / 2;
}
乍一看,您的问题似乎是在IsFacing()
方法中的rotationAngle
与angleBetweenPoints
的测试中。
给定:
rotationAngle = 0, angleBetweenPoints = 350, arcDegree = 180
那么测试将是:
test = 0 >= (350 - 180 / 2) && 0 <= (350 + 180 / 2)
= 0 >= 260 && 0 <= 440
= false
这种情况经常发生,这是由于您的角度使用了[0..360]范围。虽然这在某些情况下是有用的,但这不是其中之一。这里更有用的是获得在[-180..180]范围内的航向角和目标角的差异,然后与arcDegree
的比较变得简单得多。
试试这个:
// Adjust a value to fit in the specified range
public static float Clamp(float v, float low, float high)
{
float range = high - low;
float modifier = ((int)((v - low) / range) - (v < low ? 1 : 0)) * range;
v -= modifier;
return v;
}
// Get the angle between a point+heading and another point
// Returns an angle in the range (-180..180) where:
// res < 0 target clockwise from heading
// res == 0 target at heading
// res > 0 target counter-clockwise from heading
static float RelativeAngle(float heading, float x1, float y1, float x2, float y2)
{
// get angle between points in world coordinates
float angle = RadianToDegree((float)Math.Atan2(y2 - y1, x2 - x1));
// adjust to local coordinates and normalize
return Clamp(angle - heading, -180, 180);
}
public static bool IsFacing(Point obj, float rotationAngle, Point target, float arcDegree = 180)
{
var angleBetweenPoints = RelativeAngle(rotationAngle, obj.x, obj.y, target.x, target.y);
return angleBetweenPoints >= -(arcDegree / 2) && angleBetweenPoints <= (arcDegre / 2);
}