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);
。
问题:
InvokeRepeating("Blink", 0, 1);
Run Code Online (Sandbox Code Playgroud)
被多次调用。因此,满足条件的每一帧都添加一个新的重复调用......最终可能会有数千个总是重复的并行调用。
您想要做的是在满足条件时启用闪烁并在不满足时禁用它。在这种情况下,我不会使用Invoke
或InvokeReapting
。您可以通过简单地使用计时器来实现它:
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)