简体   繁体   English

在 Unity 中使用协程销毁 object 后出现 MissingReferenceException

[英]MissingReferenceException after destroying an object using a coroutine in Unity

void OnCollisionEnter(Collision collision)
{
    if (collision.gameObject.layer == layer)
    {
        StopAllCoroutines();
        Destroy(gameObject, 1f);
    }
}

//Coroutine is called from another script
public IEnumerator MoveRb(Vector3 destination)
{
    yield return new WaitUntil(() => rb.velocity == Vector3.zero);

    destination.y = rb.position.y;
    rb.velocity = transform.right;

    //this is where i get an error 
    yield return new WaitUntil(() => Vector3.Distance(rb.position, destination) < 0.1f); 

    rb.velocity = Vector3.zero;
}

Basically, getting "MissingReferenceException" when trying to destroy an object while running coroutine.基本上,在运行协程时尝试销毁 object 时出现“MissingReferenceException”。 Delay of 1 second, nor replacing "WaitUntil" with while loop and "yield return null" doesn't fix this issue.延迟 1 秒,或者用 while 循环替换“WaitUntil”和“yield return null”都不能解决这个问题。 The only place where object gets destroyed is inside of "OnCollisionEnter" inside of the same gameObject script. object 唯一被销毁的地方是同一游戏对象脚本中的“OnCollisionEnter”。 What am I missing here?我在这里错过了什么?

Full exception message:完整异常消息:

MissingReferenceException: The object of type 'Rigidbody' has been destroyed but you are still trying to access it. MissingReferenceException:“刚体”类型的 object 已被销毁,但您仍在尝试访问它。 Your script should either check if it is null or you should not destroy the object.你的脚本应该检查它是否是 null 或者你不应该破坏 object。

As you posted on the other answer you actually run this routine from another script正如您在其他答案上发布的那样,您实际上是从另一个脚本运行此例程

public class ConveyourBelt : MonoBehaviour
{
    void OnCollisionEnter(Collision other)
    {
        if (other.gameObject.TryGetComponent(out MovingPart movingPart))
        {
            // runs this Coroutine on THIS component
            StartCoroutine(movingPart.MoveRb(transform.position + transform.right));
        }
    }
}

The issue here is that this ConveyourBelt component is running the Coroutine, not the MovingPart component attached to the other object这里的问题是这个ConveyourBelt组件正在运行协程,而不是附加到另一个 object 的MovingPart组件

=> The call to => 调用

StopAllCoroutines();

in the MovingPart component has no effect at all since it is never running that routine!MovingPart组件中根本没有效果,因为它从不运行该例程!

So when you destroy the object after 1 second the routine could still be running on the ConveyourBelt component.因此,当您在 1 秒后销毁 object 时,该例程仍可能在ConveyourBelt组件上运行。


As a solution you should rather make the routine running on the other component like作为解决方案,您应该让例程在其他组件上运行,例如

public class ConveyourBelt : MonoBehaviour
{
    void OnCollisionEnter(Collision other)
    {
        if (other.gameObject.TryGetComponent<MovingPart>(out var movingPart))
        {
            // rather runs the Coroutine on the movingPart component
            movingPart.StartCoroutine(movingPart.MoveRb(transform.position + transform.right));
        }
    }
}

The code should work in theory.该代码在理论上应该有效。 I think the problem is you are trying to access the coroutine again during this 1 second destroy delay.我认为问题是您在这 1 秒的销毁延迟期间再次尝试访问协程。 This results in the coroutine running while the gameobject is destroyed.这导致协程在游戏对象被销毁时运行。

If you want this 1s delay then either make sure that the coroutine can't get called again after you have collided with something or the easier way is to make the coroutine error proof.如果你想要这个 1s 的延迟,那么要么确保协程在你与某物发生碰撞后不会再次被调用,要么更简单的方法是让协程防错。 Means you check if the rigidbody is null before you use it.意味着在使用之前检查刚体是否为 null。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM