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 and IsBehind calculations

乍一看,您的问题似乎是在IsFacing()方法中的rotationAngleangleBetweenPoints的测试中。

给定:

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);
}