首页 > 解决方案 > 我可以使用 IEnumerator 作为更新函数吗?

问题描述

我有一些结构,如对象 - 4 个子对象 - 每个孩子还有 2 个孩子。我想为每个子对象更改其颜色的 alpha。

我创建了应该更改 alpha 的 IEnumarator,但是当我测试它时,它只会更改为 0.8,而不是 0,而且我还想按时间更改它,例如平滑 2 秒,但它发生得很快

imageComponents = gameObject.GetComponentsInChildren<Image>();
textComponents = gameObject.GetComponentsInChildren<Text>();    

IEnumerator HideAllBoosters(Transform _object)
    {
        foreach (Image image in imageComponents)
        {
            Color _color = image.GetComponent<Image>().color;
            _color = new Color(_color.r, _color.g, _color.b, 0);
            image.GetComponent<Image>().color = Color.Lerp(image.color, _color, 10 * Time.deltaTime);
        }
        foreach (Text text in textComponents)
        {
            Color _color = text.GetComponent<Text>().color;
            _color = new Color(_color.r, _color.g, _color.b, 0);
            text.GetComponent<Text>().color = Color.Lerp(text.color, _color, 10 * Time.deltaTime);
        }
        yield return null;
    } 

Idk 如何正确地做到这一点,mb 我应该在 Update 中为每个对象更改颜色,但我不确定它是否有利于清晰和简单的代码,所以我要求的是 - 我可以为每个对象使用另一个 IEnumerator,它可以像 Update 一样工作,之类的:

    foreach (Image image in imageComponents)
    {
         StartCourutine(changeAlpha(image));
    }

标签: c#unity3d

解决方案


错误是10 * Time.deltaTime作为t值传递Lerp(Vector3 a, Vector3 b, float t);

如果您查看以下文档Lerp()

当 t = 0 时返回 a。当 t = 1 时返回 b。当 t = 0.5 时,返回 a 和 b 之间的中间点。

这意味着为了让您的 alpha 具有良好的淡入淡出效果, 的tLerp()应该是一个在一定时间内从 1 到 0(或者如果您想淡入,则为 0 到 1)的值。现在10 * Time.deltaTime,根据帧速率,您传入的值将始终相同。(在这种情况下,大约为 0.8)。

要解决此问题,您需要t一个在 0 和 1 之间缓慢增加/减少(取决于您想要淡入还是淡出)的值。一种方法是将您的逻辑封装在一个while循环中。

float speed = 0.01f; 
float time = 0;
while ( time < 1)
{
    time += speed;
    //Rest of code
}

这将在每次循环运行时将time值增加(在本例中为 0.01),在本例中为 100 次迭代(0.01 * 100 = 1)。speed

我们现在可以将此time值应用为方法中的t值,Lerp()以使其平滑过渡

image.color = Color.Lerp(image.color, _color, time);

如果您希望淡入淡出花费更多或更少的时间,只需增加或减少 中的值即可speed

整个实现看起来像这样(请注意,我还做了一些优化,稍后会介绍)

public float speed = 0.01f; //The speed at which the fade happens

private Image[] imageComponents;
private Text[] textComponents;

void Start()
{
    imageComponents = gameObject.GetComponentsInChildren<Image>(); //Cache the images so we don't have to find them every time
    textComponents = gameObject.GetComponentsInChildren<Text>(); //Cache the texts

    StartCoroutine(HideAllBoosters());//Start the Coroutine
}

IEnumerator HideAllBoosters()
{
    float t = 0; //Start value for our loop
    while (t < 1) // 1 indicates the max value of t at which the loop stops. In this case after 100 iterations since the speed is 0.01
    {
        t += speed;

        foreach (Image image in imageComponents)
        {
            Color _color = image.color;
            _color = new Color(_color.r, _color.g, _color.b, 0);
            image.color = Color.Lerp(image.color, _color, t); //t dictates how far in the interpolation we are.
        }
        foreach (Text text in textComponents)
        {
            Color _color = text.color;
            _color = new Color(_color.r, _color.g, _color.b, 0);
            text.color = Color.Lerp(text.color, _color, t);
        }
        yield return null;
    }
}

我所做的优化:您循环遍历的数组已经是imageComponentsand类型。这意味着当您在循环中遍历它们并且已经是它们各自的类型时,并且已经持有对其组件的引用。这意味着您的和电话是不必要的。textComponentsImageTextforeach()Image imageText text.GetComponent<Image>().GetComponent<Text>()

例如:

Color _color = image.GetComponent<Image>().color;

是相同的

Color _color = image.color;

我还删除了所需的Transform _object参数HideAllBoosters,因为该方法似乎根本没有使用它。可能是您稍后在此问题范围之外的函数中的某处使用了此值。如果是这种情况,您当然需要将其包括在内。


推荐阅读