Unity3D - 让游戏对象用 c# 闪烁

die*_*m_L 1 c# unity-game-engine

在我的 Unity 项目中,我有一个Empty GameObject ,它有 3 个子GameObjects。该空的游戏物体被称为Cable Strip如果摄像机移动到一个特殊的位置,我想这三个子对象的材料开始发生变化,从白色到黄色和背部。不幸的是,我所有的解决方案都不起作用。

这是我到目前为止:

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; 
           }
       }
   }
}
Run Code Online (Sandbox Code Playgroud)

我怎样才能让我的游戏对象以一种很好的方式闪烁?

编辑

抱歉,错误的定义不起作用。问题是,颜色变化太快。即使我InvokeRepeating无所改变地改变秒。即使我写了它仍然以毫秒为单位改变颜色InvokeRepeating("Blink", 0, 10);

der*_*ugo 5

问题:

InvokeRepeating("Blink", 0, 1);
Run Code Online (Sandbox Code Playgroud)

被多次调用。因此,满足条件的每一帧都添加一个新的重复调用......最终可能会有数千个总是重复的并行调用。


您想要做的是在满足条件时启用闪烁并在不满足时禁用它。在这种情况下,我不会使用InvokeInvokeReapting。您可以通过简单地使用计时器来实现它:

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;
}
Run Code Online (Sandbox Code Playgroud)

或者,同样的事情也可以通过使用协程来实现,协程通常更简洁一些(但这是意见):

// 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);
     }
}
Run Code Online (Sandbox Code Playgroud)