具体条件是否评估错误

时间:2019-02-15 14:27:13

标签: c# unity3d

问题

我必须统一地根据另一个物体撞击它的位置来计算生成粒子系统的角度。

在此计算过程中,我确定了命中是否发生在受影响实体的下半部分。 该评估失败,并产生不同的结果。

我对此进行了调试(使用VS2017和最新的Unity 2018版本),发现当我在相关表达式上执行“监视”时,它的计算结果为true,而在运行代码本身时,它的计算结果为{{ 1}}。

我如何解决它

最初,当遇到问题时,我设法通过更改条件内部的表达式来解决该问题,但现在并没有改变它。

我试图将表达式提取为它自己的值,但是它在结果上显示不一致。 在调试器中,它很少会评估正确,而其他所有时间(包括不使用调试器)都会评估不正确。

相关代码

false

结果期望

由于这是一种通用方法,因此可以根据场景中的多个实体使用它,我希望它在各种情况下的评估结果都不同

在发生评估问题的情况下,我希望它评估为SpriteRenderer Renderer = GetComponent<SpriteRenderer>(); Bounds Bounds = Renderer.bounds; Vector3 Center = Bounds.center; Vector3 HalfSize = Bounds.extents; if (HitPosition.y != int.MinValue) { if (HitPosition.y < Center.y + HalfSize.y && HitPosition.y > Center.y - HalfSize.y) { HitPosition.y = Center.y + (HalfSize.y * (Center.y < 0 ? 1 : -1)); } } else { HitPosition.y = Random.Range(Center.y - (HalfSize.y * 0.2f), Center.y + (HalfSize.y * 0.9f)); HitPosition.x += (HitPosition.x < Center.x ? -1 : 1) * HitPosition.x / 100; } bool HitOnRight = HitPosition.x >= Center.x + HalfSize.x; bool HitOnLeft = HitPosition.x <= Center.x - HalfSize.x; float Angle = 0f; if (Center.y - HalfSize.y - HitPosition.y >= 0) // <--- Issue { Angle = HitOnLeft ? 135f : (HitOnRight ? -135f : 180f); } else { Angle = HitOnLeft ? 90f : (HitOnRight ? -90f : 0f); } ,在所有其他情况下,它应该(并且确实)评估为true

2 个答案:

答案 0 :(得分:1)

在@McAden和另一个删除其答案(或已删除答案)的同伴之后,问题确实是计算本身。

如果将来有人遇到这个问题,我将解释问题的原因。

当使用Debug.LogXXX函数打印输出时,Unity将所有值舍入到2个小数点。 我试图找到官方文档,但看起来它是C#本身的一部分。 float(对于那些来自Java背景的人)被标识为Single类型的对象,并且在打印时使用ToString()方法将结果缩小到两位小数。< / p>

在执行标准Debug.LogFormat打印时,这会引起混乱,因为它将显示2个小数位,在我的情况下,差异很小,结果将四舍五入为零。

经过更深入的调试并进一步探究了差异的实际值之后,我到达了得到的值:
Y中心值:5.114532
半个Y值:0.64
Y值:4.447533
差异结果:-0.0000001192

这不是一个完美的例子,因为您可以看到它会导致-0.000001的差异,直到现在为止有很多实例导致看起来是绝对0。

  • 为了进行适当的比较,我们需要遵循C# official documentation,该准则规定:
      

    在精度损失可能会影响比较结果的情况下,可以使用以下技术代替调用Equals或CompareTo方法:

         

    调用Math.Round方法以确保两个值具有相同的精度。下面的示例修改了前面的示例以使用此方法,以便两个小数值相等。

    using System;
    
    public class Example
    {
       public static void Main()
       {
          float value1 = .3333333f;
          float value2 = 1.0f/3;
          int precision = 7;
          value1 = (float) Math.Round(value1, precision);
          value2 = (float) Math.Round(value2, precision);
          Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2, value1.Equals(value2));
       }
    }
    // The example displays the following output:
    //        0.3333333 = 0.3333333: True
    
  • 另一种方法是实现IsApproximatelyEqual
      

    测试近似相等而不是相等。此技术要求您定义两个值可以相差但仍相等的绝对量,或者定义一个较小值可以与较大值相差的相对量。

最终,此问题的根本原因是我忽略了变量代表的更深的精度值,因此发现自己不明白为什么比较不正确。

谢谢您的帮助,希望没人遇到这种愚蠢的问题:)

答案 1 :(得分:0)

运算符优先级。尝试一些括号。

    if ((Center.y - HalfSize.y - HitPosition.y) >= 0) // <--- Issue
    {
        Angle = HitOnLeft ? 135f : (HitOnRight ? -135f : 180f);
    }
    else
    {
        Angle = HitOnLeft ? 90f : (HitOnRight ? -90f : 0f);
    }