【问题标题】:While infinite loop with moving unity transform带有移动统一变换的无限循环
【发布时间】:2019-02-04 22:04:34
【问题描述】:
while (transform.position != new Vector3(desX, desY))
{
    // 2 - Movement
    Vector3 movement = new Vector3(
        0.1f * desX,
        0.1f * desY,
        0);

    //movement *= Time.deltaTime;
    transform.Translate(movement);
}    

我的这部分程序使 Unity 引擎崩溃,我很确定这是一个无限循环,但我不知道为什么或如何修复它。

【问题讨论】:

标签: c# unity3d while-loop


【解决方案1】:
  1. 一般来说,不要在while 中做那些本应在每帧基础上发生的事情! (谢谢罗恩)
    在最好的情况下,while 的结果将是您的应用卡住,直到最终矢量匹配,使对象“跳跃”到位。在最坏的情况下,它们永远不会匹配,您的应用程序将永远冻结。

    相反,您应该使用Update() 方法,该方法在每一帧中调用,并且每帧仅移动对象一步。

  2. 要比较向量,您最好使用Vector3.Distance。将== operator 用于Vector3 基本上没问题,但在内部它的作用相当于

    Vector3.Distance(vectorA, vectorB) <= 0.00001f
    

    它使用可能不完全匹配的非常小的阈值。所以使用Vector3.Distance,您可以设置自己的阈值,例如到0.1 使其“更容易”匹配。

     bool match = Vector3.Distance(transform.position, new Vector3(desX, desY) < 0.1f
    
  3. 将一个对象移向另一个 Unity 实际上已经有一个内置方法 Vector3.MoveTowards 例如

    transform.position = Vector3.MoveTowards(transform.position, new Vector3 (desX, desY), 0.1f);
    

    这会处理 Vectors3 的比较,因此您甚至不再需要它。

  4. 为了使其流畅和节省帧数,您使用Time.deltaTime 是对的。没有这个,它会移动0.1 meters / frame,但你的帧率可能不稳定。使用Time.deltaTime 使其成为0.1 meters / second,这在几乎所有情况下都是您真正想要实现的。

所以把它放在一起你的代码应该是这样的

float desX;
float desY;

float moveSpeed = 0.1f;

void Update()
{
    var targetPosition = new Vector3 (desX, desY);

    transform.position = Vector3.MoveTowards(transform.position, targetPosition, moveSpeed * Time.deltaTime);
}

请注意,在某些情况下,MoveTowards 仍然不够可中继,例如如果你想跟踪碰撞或其他东西。在这种情况下,请参考here

【讨论】:

  • 你不应该使用 while 循环来统一移动东西,这就是 Update 方法的用途。
  • 1. Vector3 可以接受 2 个参数。第三个是 0。这样做是为了让您从 Vector2 创建创建 Vector3。 2.这在这里真的无关紧要。 OP 正在比较 Vector3 而不是 float。有一个用于比较两个向量的内置重载。它不是比较 float 而是检查它们的大小差异。 3.你也可以使用while循环来移动物体。我不知道还能说什么,但这并不能解决问题。它显示了另一种解决方案,但没有解决当前问题。
  • 此外,浮点数几乎从不相等(向量由浮点数组成)。使用Mathf.Approximately 进行比较。
  • @Draco18s 通常是的,但使用 == operator 比较 Vector3 已经使用近似值,通过内部执行与 Vector3.Distance(vectorA, vectorB, 0.00001) 比较的操作,因此只需使用非常小的阈值
【解决方案2】:

它冻结了您的应用程序,因为当 while 循环中的条件不满足时,您没有给其他脚本运行机会。

要解决这个问题,请将代码放入协程函数中,然后将 yield return null; 添加到 while 循环中。这使得 Unity 在每个循环之后等待一帧,因此其他脚本有机会运行每一帧。无论while 循环是否退出,这应该可以解决冻结问题。我还建议您使用Vector3.Distance 来确定您何时接近目的地。

public float reachThreshold = 0.2f;

void Start()
{
    StartCoroutine(MoveBject());
}

IEnumerator MoveBject()
{
    float distance = Vector3.Distance(transform.position, new Vector3(desX, desY));

    while (distance > reachThreshold)
    {
        // 2 - Movement
        Vector3 movement = new Vector3(
            0.1f * desX,
            0.1f * desY,
            0);

        //movement *= Time.deltaTime;
        transform.Translate(movement);

        //Wait a frame
        yield return null;
    }
}

如果您真的想随着时间的推移将 GameObject 移动到另一个位置,请参阅 this 帖子。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-31
    • 2021-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-31
    • 2021-08-28
    相关资源
    最近更新 更多