Unity 3D mathf.clamp到多个区域

时间:2017-03-11 14:36:38

标签: c# unity3d

我正在构建一个只能转向某些固定区域的旋钮。 现在我在其中一个区域使用数学钳:

float clampedAngle = Mathf.Clamp(angle, -250f, 0f);

我希望它适用于多个区域,例如:

clampedAngle = Mathf.Clamp(angle, -250f, -230f);
clampedAngle = Mathf.Clamp(angle, -100f, -45f);
clampedAngle = Mathf.Clamp(angle, -30f, 0f);

不幸的是,上面的代码不起作用,因为它会限制到最后一个值。如何将值钳制到多个有效区域?

1 个答案:

答案 0 :(得分:0)

这个问题的棘手部分是确定要钳制的范围。一种方法是找到与该值绑定的最接近的最小值/最大值,然后根据相应的范围进行钳位。

假设您的范围表示为值对的数组(双值数组),我们可以将它们连接在一起,并通过调整this answer中的方法来找到最接近的最小/最大值。然后,相当容易向后工作以确定最小/最大值来自哪个范围,并相应地进行钳位:

// Clamps given value to nearest of given min/max pairs
private float ClampToNearestRange(float value, float[][] ranges)
{            
    // First, let's flatten the values into a single list
    List<float> flattenedRanges = ranges.SelectMany(item => item).ToList();

    // Now, we'll find the closest value in the list, and then get its index
    float nearestValue = flattenedRanges.Aggregate((x,y) => Mathf.Abs(x-value) < Mathf.Abs(y-value) ? x : y);
    int valueIndex = flattenedRanges.IndexOf(nearestValue);

    // With the value index, we can deduce the corresponding range index
    int rangeIndex = (valueIndex % 2 == 0) ? valueIndex / 2 : (valueIndex - 1) / 2;

    // Finally, we'll clamp according to the range we selected
    return Mathf.Clamp(value, ranges[rangeIndex][0], ranges[rangeIndex][1]);
}

然后您将使用如下方法:

// First, declaring your ranges somewhere in your class
float[] range1 = new float[]{0, 60};
float[] range2 = new float[]{80, 100};
float[] range3 = new float[]{150, 200};
float[][] ranges;

Start ()
{
    ranges = new float[][]{range1, range2, range3};
    float clampedAngle1 = ClampToNearestRange(120, ranges); // returns 100
    float clampedAngle2 = ClampToNearestRange(126, ranges); // returns 150
    float clampedAngle3 = ClampToNearestRange(170, ranges); // returns 170
}

注意:这确实使用LINQ,这意味着如果您需要经常这样做,您可能希望将逻辑扩展为更多Unity友好的循环。不会那么简洁,但它可能会影响你的游戏性能。

希望这有帮助!如果您有任何问题,请告诉我。