实例化生成数百个项目而不是 1 个

Instantiate Spawning Hundreds of items instead of 1

我编写了一个脚本来检测何时有东西与我的游戏对象发生碰撞。当某物与其发生碰撞时,碰撞可能会持续 1 - 2 秒,但我只希望生成一个游戏对象。当我 运行 场景并与之碰撞时,数百个游戏对象立即产生,一切都崩溃了。

我试过使用 Thread.Sleep() 和 IEnumerator waitor() 但到目前为止运气不好。

任何想法将不胜感激,我将在下面附上代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;

public class ColliderHit : MonoBehaviour
{
    public GameObject topLevelMenu;
    public GameObject sublevel;
    public GameObject topMenuItem;
    public GameObject menuItemTouched;
    public GameObject itemToSpawn;
    public bool topLevelItem;

    void OnTriggerEnter(Collider col)
    {
        if (col.gameObject.name != "" || col.gameObject.name == "RightHandVisual" || col.gameObject.name == "OculusHand_R" || col.gameObject.name == "HandGrabInteractor" || col.gameObject.name == "OVRHandPrefab")
        {

            if (topLevelItem)
            {
                topLevelMenu.SetActive(false);
                sublevel.SetActive(true);
                sublevel.transform.position = topMenuItem.transform.position;
                sublevel.transform.rotation = topMenuItem.transform.rotation;
            }
            else
            {
                StartCoroutine(waiter());
                var itemsPos = menuItemTouched.transform.position;
                var itemsRot = menuItemTouched.transform.rotation;
                var itemsSca = menuItemTouched.transform.localScale;
                GameObject spawned = Instantiate(itemToSpawn);
                spawned.transform.rotation = itemsRot;
                spawned.transform.localScale = itemsSca;
                var zpos = itemsPos.z - (0.1f);
                spawned.transform.position = new Vector3(itemsPos.x, itemsPos.y, zpos);
            }
        }
    }
    IEnumerator waiter()
    {
        //Wait for 4 seconds
        yield return new WaitForSeconds(4);;
    }
}

您可以尝试声明一个

bool isInstantiated = false;

和这样的方法:

void ResetInstantiation()
{
    isInstantiated = false;
}

然后,检查它是否已经被实例化:

else
{
    StartCoroutine(waiter());
    var itemsPos = menuItemTouched.transform.position;
    var itemsRot = menuItemTouched.transform.rotation;
    var itemsSca = menuItemTouched.transform.localScale;

    if (isInstantiated) return;

    GameObject spawned = Instantiate(itemToSpawn);
    spawned.transform.rotation = itemsRot;
    spawned.transform.localScale = itemsSca;
    var zpos = itemsPos.z - (0.1f);
    spawned.transform.position = new Vector3(itemsPos.x, itemsPos.y, zpos);

    isInstatiated = true;
    Invoke("ResetInstantiation", 4.0f);
}

这样,您将值设置为 true 并停止实例化并在 4 秒后重置标志。 (或者你想要多少)

按原样修复代码的解决方案

那不是 Co-routines 的工作方式。需要等待的代码需要在协程内:

bool isOnCollideCooldown = false;

void OnTriggerEnter(Collider col)
{
    if (col.gameObject.name != "" || col.gameObject.name == "RightHandVisual" || col.gameObject.name == "OculusHand_R" || col.gameObject.name == "HandGrabInteractor" || col.gameObject.name == "OVRHandPrefab")
    {

        if (topLevelItem)
        {
            topLevelMenu.SetActive(false);
            sublevel.SetActive(true);
            sublevel.transform.position = topMenuItem.transform.position;
            sublevel.transform.rotation = topMenuItem.transform.rotation;
        }
        else
        {
            // Return if it is instantiated
            if (isOnCollideCooldown) return;
            
            // Otherwise spawn and wait
            StartCoroutine(waiter());
            
        }
    }
}
IEnumerator waiter()
{
    // Go onto cooldown
    isOnCollideCooldown = true;
    
    // Spawn the object
    var itemsPos = menuItemTouched.transform.position;
    var itemsRot = menuItemTouched.transform.rotation;
    var itemsSca = menuItemTouched.transform.localScale;
    GameObject spawned = Instantiate(itemToSpawn);
    spawned.transform.rotation = itemsRot;
    spawned.transform.localScale = itemsSca;
    var zpos = itemsPos.z - (0.1f);
    spawned.transform.position = new Vector3(itemsPos.x, itemsPos.y, zpos);
    
    //Wait for 4 seconds
    yield return new WaitForSeconds(4);
    
    // Go off cooldown
    isOnCollideCooldown = false;
}

其他解决方案

问题是当您生成对象时,它会立即与其他对象发生碰撞。因此,在带有生成对象的脚本上,您可以使用以下内容:

Collider col;
public float noCollisionTime = 1;

void Awake() {
    col.enabled = false;
    StartCoroutine(EnableCollider());
}


IEnumerator EnableCollider()
{
    yield return new WaitForSeconds(noCollisionTime);
    col.enabled = true;
}