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)