Home > Software engineering >  Instantiate Spawning Hundreds of items instead of 1
Instantiate Spawning Hundreds of items instead of 1

Time:03-23

I have written a script that detects when something collides with my game object. When something collides with it, the collision may last 1 - 2 seconds but I only want one game object to spawn. When I run the scene and collide with it hundreds of game objects spawn instantly and everything crashes.

I have tried using Thread.Sleep() and IEnumerator waitor() but no luck so far.

Any ideas would be appreciated, I will attach the code below

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);;
    }
}

CodePudding user response:

Solution to fix your code as is

That's not how Co-routines work. The code that needs to be await needs to be within the coroutine:

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;
}

Additional Solution

The issue is that when you spawn the object, it instantly collides with the other objects. So on the script with the object that spawns you can use the following:

Collider col;
public float noCollisionTime = 1;

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


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

CodePudding user response:

You could try declaring a

bool isInstantiated = false;

and a method like this:

void ResetInstantiation()
{
    isInstantiated = false;
}

then, check if it's already been instantiated:

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);
}

This way, you set the value to true with stops the instantiation and reset the flag after 4 seconds. (or however many you wish)

  • Related