Unity协程的简单应用

Unity协程是一种特殊的函数,可以让你在Unity中创建一种类似于多线程的异步操作。它可以在需要等待某个操作完成时,暂停执行当前代码,等待某个条件满足后再继续执行。
在一般情况下 unity中调用函数时,函数将运行到完成状态,然后返回。这实际上意味着在函数中发生的任何动作都必须在单帧更新内发生;函数调用不能用于包含程序性动画或随时间推移的一系列事件。例如,假设需要逐渐减少对象的 Alpha(不透明度)值,直至对象变得完全不可见。

void Fade() 
{
    
    
    for (float ft = 1f; ft >= 0; ft -= 0.1f) 
    {
    
    
        Color c = renderer.material.color;
        c.a = ft;
        renderer.material.color = c;
    }
}

就目前而言,Fade 函数不会产生期望的效果。因为该函数将完全在单个帧更新中执行为了使淡入淡出过程可见,必须通过一系列帧降低 Alpha 以显示正在渲染的中间值。这种情况下,永远不会看到中间值,对象会立即消失。

可以通过向 Update 函数添加代码(此代码逐帧执行淡入淡出)来处理此类情况。但是,使用协程来执行此类任务通常会更方便。

协程就像一个函数,能够暂停执行并将控制权返还给 Unity,然后在下一帧继续执行。在 C# 中,声明协程的方式如下:

IEnumerator Fade() 
{
    
    
    for (float ft = 1f; ft >= 0; ft -= 0.1f) 
    {
    
    
        Color c = renderer.material.color;
        c.a = ft;
        renderer.material.color = c;
        yield return null;
    }
}

此协程本质上是一个用返回类型 IEnumerator 声明的函数,并在主体中的某个位置包含 yield return 语句。yield return null 行是暂停执行并随后在下一帧恢复的点。要将协程设置为运行状态,必须使用 StartCoroutine 函数:
通过以上学习 我们可以实现一些具体的功能了,比如UI闪烁的功能:本质就是透明度(a值)的改变
以下是一个UI闪烁类 直接挂载到button上即可

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class UIFlash : MonoBehaviour
{
    
    
    public float flashInterval = 0.5f; // 闪烁时间间隔
    public float minAlpha = 0f; // 最小透明度
    public float maxAlpha = 1f; // 最大透明度

    private Image image;
    private Coroutine flashCoroutine;

    void Awake()
    {
    
    
        image = GetComponent<Image>();
    }

    void OnEnable()
    {
    
    
        if (flashCoroutine == null)
        {
    
    
            flashCoroutine = StartCoroutine(Flash());
        }
    }

    void OnDisable()
    {
    
    
        if (flashCoroutine != null)
        {
    
    
            StopCoroutine(flashCoroutine);
            flashCoroutine = null;
            image.color = new Color(image.color.r, image.color.g, image.color.b, maxAlpha); // 恢复初始透明度
        }
    }

    IEnumerator Flash()
    {
    
    
        while (true)
        {
    
    
            image.color = new Color(image.color.r, image.color.g, image.color.b, minAlpha);
            yield return new WaitForSeconds(flashInterval);
            image.color = new Color(image.color.r, image.color.g, image.color.b, maxAlpha);
            yield return new WaitForSeconds(flashInterval);
        }
    }
}

当然也有更简单的方法,Mathf.PingPong轻易的实现这个效果

public class NewBehaviourScript : MonoBehaviour
{
    
    
    private Color HintColor;//自己定义一个想要的颜色,默认是黑色
    Image image;
    private void Start()
    {
    
    
        image = GetComponent<Image>();
    }

    private void Update()
    {
    
    
        // HintColor=new Color(Random.Range(0f,1f),Random.Range(0f,1f),Random.Range(0f,1f));//随机颜色
        HintColor.a = Mathf.PingPong(5 * Time.time, 1F);
        image.color = HintColor;
    }
}

在Unity中,协程并不是真正的多线程,而是一种协作式的多任务处理方式
协程实际上是一种函数,它可以被中断和恢复执行。当协程执行到yield return语句时,它会暂停执行并将控制权交给协程管理器,让其他协程或主线程有机会执行。当等待的条件满足后,协程管理器会恢复执行该协程。 比如一个简单的计时器程序。

 public IEnumerator StartTime() 
    {
    
    
        while (secound > 0)
        {
    
    
            yield return new WaitForSeconds(1);
            secound--;
            changeText();
            Debug.Log(secound);
        }
        if (secound == 0)
        {
    
    
            button_xuzi.interactable = true;
        }
    }

尽管协程是在单个线程中执行的,但协程可以在主线程和后台线程之间切换执行。例如,当协程等待某个耗时操作完成时,它可以暂停执行并将控制权交给主线程或后台线程去执行其他任务,待耗时操作完成后再恢复执行该协程。
因此,尽管协程并不是真正的多线程,但它可以让我们在单线程中实现类似于多线程的异步操作,从而提高程序的效率和响应性。同时,使用协程也可以简化代码实现,使得程序更易于理解和维护。
协程通常用于场景加载,在Unity中,场景加载通常是一个比较耗时的操作,需要花费一定的时间来读取场景数据并进行初始化。如果在主线程中直接进行场景加载,会导致程序卡顿,用户体验不佳。因此,Unity提供了异步加载场景的功能,可以使用协程来实现。可以使用slider.value=progress制作进度条 进度 可以防止“卡”在当前场景,(并不是真的卡 而是在加载)。

 IEnumerator LoadSceneAsync()
    {
    
    
        AsyncOperation asyncOperation = SceneManager.LoadSceneAsync("场景名");
        asyncOperation.allowSceneActivation = false; // 禁止自动跳转到加载的场景

        while (!asyncOperation.isDone)
        {
    
    
            Debug.Log("场景加载进度:" + asyncOperation.progress);

            if (asyncOperation.progress >= 0.9f)
            {
    
    
                asyncOperation.allowSceneActivation = true; // 加载完成后允许自动跳转到加载的场景
            }

            yield return null;
        }

        // 在加载完成后执行的代码
        Debug.Log("场景加载完成");
    }

1.加载场景数据:使SceneManager.LoadSceneAsync()AssetBundle.LoadAssetAsync()等异步加载场景数据。

2.显示加载进度:在加载场景数据的过程中,可以显示一个加载进度条或动画,让用户知道加载的进度和状态。

3.初始化场景:在场景数据加载完成后,需要对场景中的对象进行初始化和设置,例如设置摄像机位置、激活游戏对象等。

4.等待一段时间:在场景初始化完成后,可以暂停一段时间,让场景中的对象有时间进行启动和初始化,以避免场景加载完成后仍然出现卡顿现象。

5.完成场景加载:在等待一段时间后,可以通知主线程场景加载完成,从而让主线程进行后续处理


注意:协程不是多线程!!!!

猜你喜欢

转载自blog.csdn.net/qq_45498613/article/details/129269894