首页 文章

在Unity2D中,GameObject被实例化但不会触发与碰撞时应该做的事情(有时)

提问于
浏览
0

我有一个 Health 游戏对象,有机会在摧毁敌人时进行实例化 . 大多数时候,它会治疗玩家,播放声音效果等等 . 换句话说,它的行为方式应该如此 . 但是,有时候(可能是10次中的1次)当遇到实例化的对象时,它会播放声音效果,但不会治愈播放器,也不会被摧毁 . 随之而来的错误是:

MissingReferenceException:“GameObject”类型的对象已被破坏,但您仍在尝试访问它 . 您的脚本应该检查它是否为null或者您不应该销毁该对象 . UnityEngine.Object.Internal_InstantiateSingle(UnityEngine.Object数据,Vector3 pos,Quaternion rot)UnityEngine.Object.Instantiate(UnityEngine.Object original,Vector3 position,Quaternion rotation)(在C:/ buildslave / unity / build / Runtime / Export / UnityEngineObject .bindings.cs:211)UnityEngine.Object.Instantiate [GameObject](UnityEngine.GameObject original,Vector3 position,Quaternion rotation)(at C:/buildslave/unity/build/Runtime/Export/UnityEngineObject.bindings.cs:285) Heart.OnTriggerEnter2D(UnityEngine.Collider2D碰撞)(在Assets / Scripts / Heart.cs:36)

我一直试图弄清楚发生了什么,我似乎无法确定问题 . 在错误指向的 Health 状况对象下(错误实际上指向tempPickupEffect实例化的行):

private void OnTriggerEnter2D(Collider2D collision)
{
    if (collision.name == "Player_Ship")
    {
        AudioSource.PlayClipAtPoint(receiveSound, Camera.main.transform.position, 0.5f);

        GameObject tempPickupEffect = Instantiate(pickupEffect, transform.position, transform.rotation) as GameObject;
        tempPickupEffect.GetComponent<ParticleSystem>().Play();
        Destroy(tempPickupEffect, 3f);

        heal = true;
        Level1.playerHealth += healAmount;

        Destroy(gameObject);
    }
}

在我的敌人脚本下,我有一个名为spawnHealthUp()的方法,当敌人的生命值等于或低于零时被调用 . 这是方法:

private void spawnHealthUp()
{
    chance = Random.value;
    if (chance <= healthSpawnChance)
    {
        GameObject copyHealthUp = Instantiate(healthUp, transform.position, Quaternion.identity) as GameObject;
        copyHealthUp.GetComponent<Rigidbody2D>().velocity = new Vector2(-healthSpeed, 0f);
    }
}

提前感谢您对任何人都能提供的任何见解 .

1 回答

  • 0

    在你的情况下可能会发生很多事情,但我会说你的“pickupEffect”变量以某种方式失效,或者这是因为调用:

    tempPickupEffect.GetComponent<ParticleSystem>().Play();

    我将在下面详细介绍这两种情况 .

    首先,您可以添加一个检查以查看"pickupEffect"变量是否设置为null或某些脚本正在销毁该GameObject / prefab(通过调用它上面的Destroy()) . 在 OnTriggerEnter2D(...) 方法中调用 Instantiate(pickupEffect, ...) 之前添加此检查 . 这可以通过比较 pickupEffect == null 来完成( == 运算符被覆盖,并将根据this answer中的sugested检查GameObject / prefab是否已被销毁) .

    如果对象被破坏,通过执行以下操作来检测 where it is being destroyed 的简单方法是:创建一个包含 OnDisable() 函数的小脚本,并添加一个带有任何文本的 Debug.Log() 调用 . Debug.Log() 调用将记录您的文本,并且还会在日志消息中添加 stack trace ,您可以使用该消息来验证对 Destroy() 函数的调用位置(从而发现您的GameObject被销毁的位置) .

    // This script should be added to the "pickupEffect" gameobject
    void OnDisable()
    {
        Debug.Log("Object destroyed!");
    }
    

    当te对象被破坏时,将生成类似于以下内容的输出:

    Object destroyed!
    UnityEngine.Debug:Log(Object)
    MyObjectBeingDeleted:OnDisable() (at
    Assets/MyObjectBeingDeleted.cs:10) UnityEngine.Object:Destroy(Object)
    MyDestroyerObject:Update() (at Assets/MyDestroyerObject.cs:11)
    

    上面的堆栈跟踪告诉我 Destroy() 方法已在 MyDestroyerObject.cs 脚本的 line 11 上调用 .


    另一方面,问题实际上可能出现在代码的这一部分:

    tempPickupEffect.GetComponent<ParticleSystem>().Play();
    Destroy(tempPickupEffect, 3f);
    

    在这里您要命令粒子系统播放,但是在您发出该命令之后,您正在销毁包含该粒子系统的GameObject . 这实际上是一种不好的做法(最终可能会导致难以调试的异常) . 我建议您使用 Update() 方法创建一个脚本,该方法检查粒子系统是否已结束其执行,并在执行结束后销毁该对象 .

相关问题