Reputation: 153
I'm using a lightning GameObject prefab to have a visual effect when i'm firing my weapon. When I fire, I enable that lightning object and I have a generic component that deactivates it after a certain delay.
The problem is that the "should wait" log is never reached, and instead of waiting the set delay, it waits much longer and doesn't actually deactivate the GameObject.
Here's the code for the DeactivateAfter component
public class DestroyAfter : MonoBehaviour {
[SerializeField]
private float delay;
private bool firstRun = true;
void OnEnable () {
if (firstRun == false) {
StartCoroutine(DestroyMethod());
}
firstRun = false;
}
public IEnumerator DestroyMethod() {
Debug.LogFormat("Should wait; Time: {0}", Time.time);
yield return new WaitForSeconds(delay);
Debug.LogFormat("Should deactivate; Time: {0}", Time.time);
gameObject.SetActive(false);
}
}
Upvotes: 0
Views: 570
Reputation: 90580
If I understood you correctly the lightning GameObject is already a prefab you instantiate when firing and you want to destroy it after a delay.
So instead of a Coroutine solution and enabling or disabling the Object, this could be way simpler done using instantiate and destroy after as your script is actually called:
GameObject obj = GameObject.Instantiate(yourPrefab, position, rotation);
GameObject.Destroy(obj, delay);
This function can be called from anywhere as long as you have yourGameObject
provided to the calling class. So you don't even need an own class for this.
The second float parameter is a delay in seconds (see API)
For example you could have a shooting class like:
public class Shooting : MonoBehavior
{
[SerializeField]
private GameObject lightningPrefab;
[SerializeField]
private float delay;
public void OnShooting(Vector3 position, Quaternion rotation){
GameObject obj = GameObject.Instantiate(lightningPrefab, position, rotation);
/* Directly after instantiating the Object
* you can already "mark" it to be destroyed after x seconds
* so you don't have to store it as variable anywhere */
GameObject.Destroy(obj, delay);
}
}
You then also could add some check to not constantly spawn the prefab:
[...]
private GameObject lightningObject;
public void OnShooting(Vector3 position, Quaternion rotation){
if(lightningObject == null ){
lightningObject = GameObject.Instantiate(lightningPrefab, position, rotation);
GameObject.Destroy(lightningObject, delay);
}
}
On this way there is always only one of your lightning objects a time.
Another way without having to instantiate and destroy the object all the time would be a simple timeout instead of the Coroutine:
public class Shooting : MonoBehavior
{
[Tooltip("The lightning Object")]
[SerializeField]
private GameObject lightningObject;
[Tooltip("The time in sec the lightningObject stays visible")]
[SerializeField]
private float visibleDelay;
/* track the time that passed since the last OnShooting call */
private float timePassed;
/* Additional bool to not perform Update when not needed */
private bool isVisible;
/* Update is called once each frame */
private void Update(){
/* If the object is not visible do nothing */
if (isVisible != true) return;
/* update the timePassed */
timePassed += Time.deltaTime;
/* if delay passed since last OnShooting call
* deactiavte the object */
if (timePassed >= visibleDelay){
lightningObject.SetActive(false);
}
}
public void OnShooting(){
/* Activate the Object */
lightningObject.SetActive(true);
/* set isVisible */
isVisible = true;
/* reset the timePassed */
timePassed = 0;
}
}
Upvotes: 1
Reputation: 1736
The condition never be true, you need to set firstRun condition to true first.
private bool firstRun = **true**;
void OnEnable () {
if (firstRun == **true**) {
StartCoroutine(DestroyMethod());
}
firstRun = false;
}
And i ever like to set flag first and later do what you want:
private bool firstRun = **true**;
void OnEnable () {
if (firstRun == **true**) {
firstRun = false;
StartCoroutine(DestroyMethod());
}
}
Upvotes: 3
Reputation: 387
Hmm. Your code works fine in my project.
What i'm doing, some object have your script and I deactivate and then activate the gameObject when scene is playing.
Your Destroy Method is public. Check your project, maybe somewhere calls StopAllCoroutines() or StopCoroutine(DestroyMethod());
Upvotes: 0
Reputation: 599
I think you should use particle system for your weapon fire. Anyway I think your code is not working because you are deactivating the game object instead of deactivating the component. Activate and deactivate your component using something like this :
gameObject.GetComponent<YourComponent>().enabled = false;
Upvotes: 1