Unity 协程(Coroutine)高级用法实例

简介

在Unity中,C#协程(Coroutine)是一种特殊的异步编程机制,它允许我们在不阻塞主线程的情况下执行耗时操作,并且可以按照帧率分阶段地完成任务。以下是5个使用Unity协程的高级用例:

1. 异步加载场景并显示加载进度

IEnumerator LoadSceneAsync(string sceneName)
{
    AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneName);
    
    while (!asyncLoad.isDone)
    {
        float progress = Mathf.Clamp01(asyncLoad.progress / 0.9f); // 考虑到加载过程前0.9的部分代表实际资源加载
        Debug.Log($"Loading Scene: {progress * 100}%");
        
        yield return null; // 让出当前帧,等待下一帧继续检查加载进度
    }
}

void Start()
{
    StartCoroutine(LoadSceneAsync("NextScene"));
}

这个例子展示了如何通过协程异步加载场景,并在加载过程中实时反馈进度。

2. 延迟执行与定时器功能

IEnumerator DelayedAction(float delay, Action action)
{
    float startTime = Time.time;
    
    while (Time.time < startTime + delay)
    {
        yield return null;
    }
    
    action();
}

void UseDelayedAction()
{
    StartCoroutine(DelayedAction(3f, () => 
    {
        Debug.Log("Delayed action executed after 3 seconds.");
    }));
}

在这个案例中,我们创建了一个延迟执行动作的协程,可以在指定时间后执行任意给定的回调函数。

3. 动画序列控制

IEnumerator AnimateSequence(GameObject target, AnimationClip[] clips)
{
    foreach (var clip in clips)
    {
        target.GetComponent<Animator>().Play(clip.name);
        
        while (target.GetComponent<Animator>().GetCurrentAnimatorStateInfo(0).normalizedTime < 1.0f)
        {
            yield return null;
        }
    }
    
    Debug.Log("Animation sequence completed.");
}

void PlaySequence()
{
    GameObject character = GameObject.FindWithTag("Player");
    var clips = new AnimationClip[3] { animJump, animIdle, animRun };
    StartCoroutine(AnimateSequence(character, clips));
}

此例说明了如何通过协程按顺序播放一组动画片段,在每个片段播放完毕后切换至下一个片段。

4. 网络请求处理

using UnityEngine.Networking;

IEnumerator FetchData(string url)
{
    UnityWebRequest www = UnityWebRequest.Get(url);
    yield return www.SendWebRequest();

    if (www.result == UnityWebRequest.Result.Success)
    {
        string data = www.downloadHandler.text;
        Debug.Log("Received data: " + data);
        ProcessData(data);
    }
    else
    {
        Debug.LogError("Error: " + www.error);
    }
}

void RequestData()
{
    StartCoroutine(FetchData("http://example.com/data.json"));
}

这个示例展示了如何利用协程处理网络请求,当请求完成时读取返回的数据,并在网络请求期间保持游戏运行流畅。

5. 渐变颜色或透明度变化

IEnumerator FadeInOut(Color startColor, Color endColor, float duration)
{
    float timeElapsed = 0f;
    
    Material mat = GetComponent<Renderer>().material;
    Color currentColor = mat.color;
    
    while (timeElapsed < duration)
    {
        timeElapsed += Time.deltaTime;
        float t = timeElapsed / duration;
        currentColor = Color.Lerp(startColor, endColor, t);
        mat.color = currentColor;
        
        yield return null;
    }
    
    mat.color = endColor;
}

void FadeOut()
{
    StartCoroutine(FadeInOut(Color.white, Color.clear, 2f));
}

在此案例中,协程用于实现颜色或透明度渐变过渡效果,逐渐改变物体的颜色或透明度直至达到目标值。

6. 游戏对象的动态移动序列

IEnumerator MoveToSequence(Transform target, Vector3[] waypoints, float speed)
{
    for (int i = 0; i < waypoints.Length; i++)
    {
        Vector3 destination = waypoints[i];
        
        while (Vector3.Distance(target.position, destination) > 0.1f)
        {
            target.position = Vector3.MoveTowards(target.position, destination, speed * Time.deltaTime);
            yield return null;
        }
        
        // 到达一个点后可以暂停一会儿,增加平滑过渡效果
        yield return new WaitForSeconds(0.2f);
    }
    
    Debug.Log("Move sequence completed.");
}

void StartMoving()
{
    Transform playerTransform = GameObject.FindWithTag("Player").transform;
    Vector3[] path = { new Vector3(0, 0, 0), new Vector3(5, 0, 0), new Vector3(5, 5, 0) };
    StartCoroutine(MoveToSequence(playerTransform, path, 2f));
}

此示例中,协程用于实现游戏对象按照预设路径顺序移动,每到达一个点后等待片刻再继续移动到下一个目标点。

7. 处理帧率依赖的时间间隔

IEnumerator FrameRateIndependentInterval(float realTimeSeconds)
{
    float startTime = Time.time;
    float elapsedTime = 0f;

    while (elapsedTime < realTimeSeconds)
    {
        elapsedTime += Time.deltaTime;
        yield return null;
    }

    Debug.Log("A frame rate independent interval of " + realTimeSeconds + " seconds has passed since start.");
}

void RunFrameRateIndependentAction()
{
    StartCoroutine(FrameRateIndependentInterval(3f));
}

在本例子中,我们创建了一个不受实际帧率影响的定时器,确保无论帧率如何变化,都会在指定的真实时间(例如3秒)之后执行操作。

8. 异步加载资源并在完成后初始化

using UnityEngine.ResourceManagement.AsyncOperations;

IEnumerator LoadAssetAsync<T>(string assetPath, System.Action<T> onLoaded)
{
    AsyncOperationHandle<T> operation = Addressables.LoadAssetAsync<T>(assetPath);

    while (!operation.IsDone)
    {
        yield return null;
    }

    if (operation.Status == AsyncOperationStatus.Succeeded)
    {
        T loadedAsset = operation.Result;
        onLoaded?.Invoke(loadedAsset);
    }
    else
    {
        Debug.LogError($"Failed to load asset at path: {assetPath}");
    }

    Addressables.Release(operation);
}

void InitializeWithLoadedAsset()
{
    StartCoroutine(LoadAssetAsync<GameObject>("Assets/Prefabs/MyPrefab.prefab", prefab =>
    {
        Instantiate(prefab, Vector3.zero, Quaternion.identity);
    }));
}

在这个例子中,使用Unity Addressables异步加载系统加载资源,并在加载完成后通过回调函数进行初始化操作。

python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)

50个开发必备的Python经典脚本(11-20)

50个开发必备的Python经典脚本(21-30)

50个开发必备的Python经典脚本(31-40)

50个开发必备的Python经典脚本(41-50)
————————————————

​最后我们放松一下眼睛
在这里插入图片描述

C#中,可以使用协程Coroutine)来实现排队运行的功能。协程是一种特殊的迭代器函数,它可以在执行过程中暂停并返回中间结果,然后再次从暂停的地方继续执行。 要实现协程的排队运行,可以使用yield return语句来暂停执行,并在需要时恢复执行。下面是一个简单的示例代码: ```csharp using System.Collections; using UnityEngine; public class CoroutineQueue : MonoBehaviour { private Queue coroutineQueue = new Queue(); private void Update() { if (coroutineQueue.Count > 0 && !IsInvoking("DequeueCoroutine")) { StartCoroutine("DequeueCoroutine"); } } public void EnqueueCoroutine(IEnumerator coroutine) { coroutineQueue.Enqueue(coroutine); } private IEnumerator DequeueCoroutine() { IEnumerator coroutine = (IEnumerator)coroutineQueue.Dequeue(); yield return StartCoroutine(coroutine); } } ``` 上述代码中,CoroutineQueue类维护了一个队列(coroutineQueue)用于存储需要排队运行的协程。在Update方法中,检查队列是否为空并且没有正在运行的协程,如果满足条件,则使用StartCoroutine方法启动一个新的协程来处理队列中的下一个任务。 EnqueueCoroutine方法用于向队列中添加新的协程任务。 使用示例: ```csharp CoroutineQueue coroutineQueue = new CoroutineQueue(); void Start() { // 添加协程任务到队列 coroutineQueue.EnqueueCoroutine(ExampleCoroutine1()); coroutineQueue.EnqueueCoroutine(ExampleCoroutine2()); } IEnumerator ExampleCoroutine1() { // 协程1的执行逻辑 yield return null; } IEnumerator ExampleCoroutine2() { // 协程2的执行逻辑 yield return new WaitForSeconds(2f); } ``` 在上述示例中,我们创建了一个CoroutineQueue实例,并添加了两个协程任务到队列中。这些协程将会按照添加的顺序依次执行。 请注意,以上示例是Unity引擎中使用协程的方式。如果你是在其他C#环境中使用,可能需要针对具体情况做一些修改和适配。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极致人生-010

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值