I want to get a light attached to an object to start flashing on and off rapidly when the player enters a collision zone, and then stay off when the player isn’t in the collision zone. So far I’ve got the light to turn on when they enter the collision zone, and also I’ve got the light to flash as I want, but the problem is I can’t seem to get the light to flash when the player is in the collision zone.
Here’s my code so far, with comments:
using UnityEngine;
public class FlashingLights : MonoBehaviour {
//Set variable for light
public Light redLight;
//The timer for the light. It shouldn't be too quick or slow.
public float pulseSpeed = 1f;
private float timer;
//The object the light is attached to
public GameObject device;
//Get the light component from the object it's attached to
private void Awake()
{
if(device)
{
redLight = device.GetComponent<Light>();
}
}
// Use this for initialization
void Start () {
//Start with light disabled
redLight.enabled = false;
}
// Update is called once per frame
void Update () {
//The code below is used if the light is flashing. Trying to
//find a different way to get the light to flash but only
//when the user enters a trigger zone
/* timer += Time.deltaTime;
if(timer > pulseSpeed)
{
timer = 0;
redLight.enabled = !redLight.enabled;
}*/
}
//In the following two methods, the light stays off or is triggered on if they are in close range of a hazmat
private void OnTriggerEnter(Collider other)
{
redLight.enabled = true;
}
private void OnTriggerExit(Collider other)
{
redLight.enabled = false;
}
}
Any suggestions would really be appreciated. I think I might be missing something like IEnumerator?
Like you suggested, I would use a coroutine here. How it’s setup depends on how you want your light to flash. If you simply want it to blink on and off, you could do something like this.
IEnumerator Blink ()
{
//The intermission delay between the blinks
float intermissionDelay = 0.1f;
WaitForSeconds waitTime = new WaitForSeconds (intermissionDelay);
while (true)
{
redLight.enabled = !redLight.enabled;
yield return waitTime;
}
}
You’ll want to call StartCoroutine (Blink()) in your OnTriggerEnter, and call StopAllCoroutines () in your OnTriggerExit. Note that this might mess with your setup if you decide to implement more than one coroutine in that script.
This was very useful, but it still doesn’t work unfortunately. The light is off outside the collision zone but when I go in it’s still off. This is pointing me in the right direction though.
Insert a Debug.Log in your OnTriggerEnter method to make sure it’s called, put another one in the “Blink” coroutine, to make sure that’s called as well.
The Blink coroutine doesn’t seem to get the light flashing, but I tested it with just light.enabled = true; and that worked. OnTriggerEnter should work because light.enabled = true; worked just fine there as well.
Quick update, I did what you suggested and used Debug.Log, both came back fine. I wonder if it’s something to do with light.enabled = !light.enabled;?
No, that should work fine. Can you Debug.Log OnTriggerExit and see if that’s called right after your coroutine has started? Sounds like the coroutine is stopping right away.
Edit: Actually, while at it, could you post your new script?
From what I observed in the Console from Debug.Log, OnTriggerEnter appeared when I entered the collision zone, then Coroutine appeared. I tried this a few times and it works as it should.
Here’s my new script:
public class FlashingLights : MonoBehaviour {
//Set variable for light
public Light redLight;
//The timer for the light. It shouldn't be too quick or slow.
public float pulseSpeed = 1f;
private float timer;
//The object the light is attached to
public GameObject device;
//Get the light component from the object it's attached to
private void Awake()
{
if(device)
{
redLight = device.GetComponent<Light>();
}
}
// Use this for initialization
void Start () {
//Start with light disabled
redLight.enabled = false;
}
// Update is called once per frame
void Update () {
//The code below is used if the light is flashing. Trying to
//find a different way to get the light to flash but only
//when the user enters a trigger zone
/* timer += Time.deltaTime;
if(timer > pulseSpeed)
{
timer = 0;
redLight.enabled = !redLight.enabled;
}*/
}
//In the following two methods, the light stays off or is triggered on if they are in close range of a hazmat
private void OnTriggerEnter(Collider other)
{
//redLight.enabled = true; //This works but the light is static instead of flashing
StartCoroutine(Blink()); //This should make the light flash
Debug.Log("OnTriggerEnter works");
}
private void OnTriggerExit(Collider other)
{
//redLight.enabled = false;
StopAllCoroutines(); //This stops the light flashing
}
IEnumerator Blink()
{
float intermissionDelay = 0.1f; //Don't need this because the value can be entered in WaitForSeconds instead
WaitForSeconds waitTime = new WaitForSeconds(intermissionDelay);
while(true)
{
redLight.enabled = !redLight.enabled; //This should alternate the light being on and off
//redLight.enabled = true; //A quick test to check if IEnumerator was working
yield return waitTime;
Debug.Log("Blink Coroutine works");
}
}
}
I’ll check OnTriggerExit too and update you.
Edit: OnTriggerExit working fine.
Ya, I’m worried that for some reasons OnTriggerExit gets called too soon. Can you put a debug log in the while loop of the coroutine and see if that’s getting called repeatedly as intended?
I checked with Debug.Log again. When I enter the collision zone, OnTriggerEnter appears, then Coroutine repeats as I stand in the collision zone, then when I exit, OnTriggerExit appears. One thing I did notice was that the Debug.Log of OnTriggerEnter and Exit appeared twice, is that normal?
I don’t know, I don’t have much experience with those. Possibly there is a child of your trigger zone that also has a collider?
Anyway, you can run multiple instances of the same coroutine at once. So if trigger enter is called twice, there are 2 coroutines running together. One of them is enabling, and the other one is disabling right away in the same frame.
Try putting StopAllCoroutines () right before the StartCoroutine(Blink()) line in the OnTriggerEnter method. This will ensure only one instance of the coroutine is running.
Then, I suggest you figure out what causes it to be called twice. I personally can’t help you with that.
Okay, I’ll see what I can do. Thanks for your help, I appreciate it. My problems always seem to be difficult to sort out, then it turns out to be something really minor causing the problem.
Edit: Your suggestion worked! I put StopAllCoroutines before StartCoroutine in the OnTriggerEnter method and it did the trick. Thanks very much!