BASIC TELEPORTING QUEST: ‘Blink World Light’ - Solutions

Actually I fixed this code again, only because what you wrote so thank you :slight_smile: .
I put it in Update because when it was in Start the coroutine ran only once, but now I added a while loop around the foreach loop and it works fine when the StartCoroutine is in Start

public class Lights : MonoBehaviour
{
    [SerializeField] Light[] mainWorldLight;

    [SerializeField] float blinkWorldTime;
    WaitForSecondsRealtime WaitBlinkWorldTime;

    private void Awake()
    {
        WaitBlinkWorldTime = new WaitForSecondsRealtime(blinkWorldTime);
    }

    private void Start()
    {
        StartCoroutine(BlinkWorldLights());
    }

    IEnumerator BlinkWorldLights()
    {
        while (true)
        {
            yield return WaitBlinkWorldTime;
            foreach (var light in mainWorldLight)
            {
                light.enabled = !light.enabled;
            }
        }
    }
}
2 Likes

You probably shouldn’t as it gets triggered multiple times which is not likely what you want…

Nice!

1 Like

I took the easy approach to this one; I just turned the directional light off in editor and implemented the following coroutine code:

IEnumerator BlinkWorldLight()
{
    mainWorldLight.gameObject.SetActive(true);
    yield return new WaitForSeconds(2);
    mainWorldLight.gameObject.SetActive(false);
}

I considered having it blink on and off multiple times but I’m just trying to take this first section quickly.
I do feel that the current implementation, with every teleporter accessing the directional light, is inherently flawed, however. With the teleporters as close together as they are in this project, it would be easy to call the coroutine from one teleporter script before it has finished in another. This means that if you hit a second teleporter soon after the first, the directional light could be turned off almost immediately by the first teleporter, so you don’t get the intended visual effect.

I think it would make more sense to have a designated LightManager in the game that handles turning the light on and off.
Alternatively you could place a script for handling the calls from teleporters onto the light itself. You might have an event-style system where each teleporter registers on the script on the light at the start of the coroutine and deregisters after the delay; then turn the light off only when there are no registered teleporters. This would also make smoothly lerping the light value (i.e. intensity) up and down very easy, even if you have the light flashing on and off repeatedly as long as teleporters are registered.

To be honest though, I wasn’t sure what the desired visual effect was here so I may have completely missed the mark ^^’

1 Like

I think the gist of this challenge was you have a darkened scene and the occasional blinking light illumiates so the player can see further.
How and where you do it is up to you.
I made a lightning effect in a separate ‘manager’ for my ‘game’ with noise too.

1 Like

Ahhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh

Thank you! I see where I went wrong now. I misread the challenge as saying you are supposed to make the lights flash when you step on a teleporter, but reading it again, that challenge doesn’t actually mention anything about teleports at all. :man_facepalming:

Went back and fixed this one. Custom light manager class for having a lightning effect. Tried to write self meaningful names for the many variables I used to achieve my desired effect.

public class LightManager : MonoBehaviour
{
    [SerializeField] Light mainWorldLight;

    void Start()
    {
        float timeBetweenFlashSequences = Random.Range(3f, 6f); 
        StartCoroutine(MainBlinkSequence(timeBetweenFlashSequences));
    }

    IEnumerator MainBlinkSequence(float waitTime)
    {
        yield return new WaitForSeconds(waitTime);
        int numFlashes = Random.Range(2, 6);
        for (int i = 0; i < numFlashes; i++)
        {
            mainWorldLight.enabled = true;
            //time light on is dependent on num flashes, preventing long duration if high number
            float timeLightOn = Random.Range(0.1f, 0.1f + 0.8f / (numFlashes / 2));
            yield return new WaitForSeconds(timeLightOn);
            mainWorldLight.enabled = false;
            //time between flashes is dependent on num flashes, preventing long wait if high number
            float timeBeforeNextFlash = Random.Range(0.1f, 0.1f + 0.7f / (numFlashes / 2));
            yield return new WaitForSeconds(timeBeforeNextFlash);
        }
        float timeBetweenFlashSequences = Random.Range(3f, 6f); 
        StartCoroutine(MainBlinkSequence(Random.Range(3f, 6f)));
    }
}

I’m happy with the result but I don’t know how to make the script more designer friendly. I want the min and max range values of all these variables to be exposed to the editor:

float timeBetweenFlashSequences
int numFlashes 
float timeLightOn
float timeBeforeNextFlash

I could expose the min and max of each individually, but imo that would not be super friendly to a designer.
A better way would be to expose a slider with min and max handles, but unity doesn’t seem to have this by default and I know nothing about making a custom editor :sweat_smile:

Anyway I’m happy enough with the result. :slight_smile:

1 Like

It’s good practice to expose regardless so at least they can be changed easily outside the code

Look at NaughtyAttributes in the asset store. Its free and has some very useful Drawer Attributes including a MinMax slider.

You could always do a tooltip specifying the desired range of your exposed values. That might provide some guidance to a designer.

“waitTime” is a serialized float set to 1.0f. I didnt like the string reference fetching the coroutine so I changed it.

    void OnTriggerEnter(Collider other) 
    {
        TeleportPlayer();
        DeactivateObject();
        IlluminateArea();
        StartCoroutine(BlinkWorldLight());
        // Challenge 6: TeleportPlayerRandom();
    }

    IEnumerator BlinkWorldLight()
    {
        mainWorldLight.gameObject.SetActive(true);
        yield return new WaitForSeconds(waitTime);
        mainWorldLight.gameObject.SetActive(false);
    }

I took the challenge to mean that the light would blink occasionally to light up the scene not just on a trigger enter …

    void OnTriggerEnter(Collider other) 
    {
        TeleportPlayer();
        DeactivateObject();
        IlluminateArea();
        StartCoroutine ("BlinkWorldLight");
    }

    IEnumerator BlinkWorldLight()
    {
        float originalIntesity = mainWorldLight.intensity;
        
        for (float intensity = originalIntesity; intensity <= 1; intensity += 0.05f)
        {
            mainWorldLight.intensity = intensity;
            yield return new WaitForSeconds(.1f);
        }

        for (float intensity = mainWorldLight.intensity; intensity >= originalIntesity; intensity -= 0.05f)
        {
            mainWorldLight.intensity = intensity;
            yield return new WaitForSeconds(.1f);
        }
    }

Im fading in the light in and out rather than blinking.

Looking for some help on a good article to use for lerp.

Privacy & Terms