1
votes

In my Unity project I have an Empty GameObject which has 3 child GameObjects. The Empty GameObject is called Cable Strip and if the camera move to a special position, I want that the material of the three child Object start to change from white to yellow and back. Unfortunately all my solutions does not work.

This is what I have so far:

using UnityEngine

public class BlinkingObject : MonoBehaviou
{
    public GameObject CableStrip;
    public Material white, yellow;

    public GameObject camManager; //Empty GameObject with the Main Camera
    private Vector3 camPosition;

    bool blinkObject;

    void Update()
    {
         if(camManager.transform.position == camPosition)
         {
             InvokeRepeating("Blink", 0, 1);
         }
    }

    public void Blink()
    {
       Renderer[] colorCable = CableStrip.GetComponentsInChildren<Renderer>(true);
       foreach (var cableChild in colorCable)
       {
           if(blinkObject)
           {
               cableChild.material = yellow;
               blinkObject = false; 
           } else
           {
               cableChild.material = white;
               blinkObject = true; 
           }
       }
   }
}

How can I get my gameobject to blink in a nice way?

Edit

Sorry wrong definition of does not work. The problem is, that the color changes too fast. Even if I change the seconds by InvokeRepeating nothing changes. It still changes the color in milliseconds even if I write InvokeRepeating("Blink", 0, 10);.

1
possibly because you are constantly invoking the blinking.. does it run the blink method? what happens if instead of the changes of materials you put debug messages....BugFinder
is this ever true : camManager.transform.position == camPosition ?derHugo
@BugFinder if i use debug messages it switches between the two messagesdiem_L
@derHugo not sure, i am new to c# but it works fine in all my c# script .. if you have a better solution i´d love to see it :)diem_L
@diem_L well, if the debug messages work then its doing it, so: are the debug messages once a second? Id guess it could be once a frame while the camera is in the right position ergo if you get say 200fps, its flipping 200 times a second and you dont see the colour changeBugFinder

1 Answers

5
votes

Problem:

InvokeRepeating("Blink", 0, 1);

is called multiple times. So every frame the condition is fulfilled you add a new repeating invoke ... ending up with probably thousands of parallel invocations that are always repeating.


What you want to do instead is enabling the blink when the condition is fulfilled and disable it when not. I wouldn't use Invoke or InvokeReapting in this case. You can achieve it by simply using a timer:

private float timer;
private bool blinkObject;

private Renderer[] colorCable;

private void Awake()
{
    // you want to do this only once!
    colorCable = CableStrip.GetComponentsInChildren<Renderer>(true);
}

private void Update()
{
     HandleBlink();
}

// As suggested by Cid you can ofcourse move it all to a method
// so you don't disturb other things happening in Update
private void HandleBlink()
{
     // is the condition fulfilled?
     var doBlink = camManager.transform.position == camPosition;

     // if not do nothing
     if(!doBlink) return;

     // reduce the timer by time passed since last frame
     timer -= Time.deltaTime;

     // if timer not under 0 do nothing else
     if(timer > 0) return;

     // If timer exceeded invert the blinkObject flag
     blinkObject = !blinkObject;

     foreach (var cableChild in colorCable)
     {
         // Shorthand for if(blinkObject) { ... = yellow; } else { ... = white; }
         cableChild.material = blinkObject ? yellow : white;
     }

     // and reset the timer
     timer = 1f;
}

Alternatively the same thing could also be achieved by using a Coroutine which is often a bit cleaner (but that's opinions):

// flag for preventing concurrent routines
private bool isBlinking;

private Renderer[] colorCable;

private void Awake()
{
    // you want to do this only once!
    colorCable = CableStrip.GetComponentsInChildren<Renderer>(true);
}

private void Update()
{
     // is the condition fulfilled?
     if(camManager.transform.position == camPosition)
     {
         if(!isBlinking) StartCoroutine(BlinkRoutine());
     }
     else
     {
         StopAllCoroutines();
         isBlinking = false;
     }
}

private IEnumerator BlinkRoutine()
{
     isBlinking = true;

     var blinkObject = false;

     // this looks scary but is fine in a Coroutine
     // as long as you YIELD somewhere inside!
     while(true)
     {
         blinkObject = !blinkObject;

         foreach (var cableChild in colorCable)
         {
             // Shorthand for if(blinkObject) { ... = yellow; } else { ... = white; }
             cableChild.material = blinkObject ? yellow : white;
         }

         yield return new WaitForSeconds(1);
     }
}