Unity中yield return 的使用心得

本文围绕Unity协程展开,介绍了其在优化项目、固定时间操作等方面的应用。阐述了WaitForSeconds和WaitForSecondsRealtime的区别,前者受Time.timeScale影响,后者不受。还讲解了用bool变量控制协程等待,以及跟随null模拟Update的情况,最后说明了协程的终止方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


持续更新中

等待固定时间

当我们要处理一些比较耗费资源的事情并且不需要每帧保持其准确性时,可以使用协程,降低该代码段的使用频率,以达到优化项目的目的。还有一些情况下,我们有时需要在一些固定的时间后做一些操作,等待固定时间也是一个很好的解决方案,比如:塔防游戏中的怪物的生成。
主要用到的类有两个 WaitForSecondsWaitForSecondsRealtime
相同点:都可以用来使协程等待
不同的:前者是缩放的时间,后者是未缩放的时间
什么意思呢??
举例来看:创建一个脚本,添加如下代码

    public float timeScale;
    public int fps;
    public IEnumerator Test1()
    {
        while (true)
        {
            Debug.Log("Coming1!!!!!!!  " + fps);
            yield return new WaitForSeconds(1f);
        }
    }
    public IEnumerator Test2()
    {
        while (true)
        {
            Debug.Log("Coming2!!!!!!!  " + fps);
            yield return new WaitForSecondsRealtime(1f);
        }
    }
    private void Start()
    {
        fps = 0;
        Time.timeScale = timeScale;
        StartCoroutine(Test1());
        StartCoroutine(Test2());
    }
    private void Update()
    {
        fps++;
    }

将其绑定到场景对象中,设置timeScale = 1,然后运行

可以看到如下的运行结果:
图一图一

将time scale 改为2,再次运行,看到如下结果:
图二图二
细心的朋友可能已经发现,在timescale该为2时,coming1的打印频率上升了,平均间隔比之前短了一半
由此可见,官方所说的缩放是指针对于Time.timeScale,也就是是说,WaitForSeconds的实际等待时间受Time.timeScale影响,而WaitForSecondsRealtime不受Time.timeScale影响。
但是,要注意,WaitForSeconds(x * Time.timeScale)不等于 WaitForSecondsRealtime(x)
因为在Time.timeScale = 1 时,图一中输出的信息显示他们的输出频率并不相同,所以不能如上做出等价。
仔细观察图一,可以发现,Coming2是规律的没秒输出一个,以此可以推出,WaitForSecondsRealtime指的等待时间应该是实际时间,WaitForSeconds指的等待时间应该是游戏时间,我们都知道,游戏时间是受Time.timeScale 影响。
因此,可以确定,WaitForSeconds等待的是游戏的时间,WaitForSecondsRealtime等待的是真实世界的时间

关于bool变量控制协程等待

对于很多情况下,我们需要等待特定条件后,再使协程继续运行,就需要用到bool变量控制协程运行。
主要用到有两个类 WaitUntilWaitWhile

    public bool tmp = false;
    private IEnumerator Test1()
    {
        Debug.Log("Coming1!!!!!!");
        yield return new WaitUntil(() => tmp);		//tmp为false 等待,为true执行
        //yield return new WaitWhile(() => tmp);	//tmp为true 等待,为false执行
        //yield return tmp;							//不可用,不会等待
        Debug.Log("Coming2!!!!!!!");
    }

跟随null的情况

有时,我们或许需要一些操作,不需要放在Update中,但也需要每帧执行一次,这时候就可以用yield return null,来模拟一个Update。不过有一点需要注意,yield null 是在update 后运行的,如下图官方文档所示。所以在使用时需要仔细考虑代码的执行顺序,避免出现问题。
在这里插入图片描述

终止协程

终止协程分为两种,一种是在协程内部终止,一种是外部终止。
内部终止:使用yield break 跳出协程来终止协程。
外部终止:开启协程的方法有一个Coroutine类型的返回值,在开启协程时接收这个值,就可以使用stop的第二个重载关闭协程了。也可以使用StopAllCoroutines 关闭所有协程。
在这里插入图片描述
当然,对于另外两种方法来说,有string参数(协程名)的方法可以关闭协程,不过一次只能关闭一个同名协程,而且只能关闭通过string开启的协程。而另一种方法好像并不能关闭协程(或者是我测试的方法不对),所以不推荐使用。

所以,综上所述,推荐使用public Coroutine StartCoroutine(IEnumerator routine); 开启协程,并接收返回值
使用public void StopCoroutine(Coroutine routine); 来关闭协程。
当然,也可以在协程内部通过条件控制,使用yield break 来终止协程 。具体使用,看个人经验及需求吧。

附一张脚本生命周期流程图

在这里插入图片描述

### 如何在 Unity 中集成 DeepSeek 实现语音输入功能 #### 准备工作 为了成功地将 DeepSeek 集成到 Unity 项目中,确保已经安装并配置好最新的 Unity 编辑器版本以及拥有有效的 DeepSeek API 访问权限[^1]。 #### 创建新场景或打开现有场景 启动 Unity 并创建一个新的场景或者加载现有的用于测试语音识别功能的场景[^2]。 #### 导入必要的资源包 下载官方提供的 DeepSeek SDK 或者通过 Asset Store 获取适用于 Unity 的插件。导入此软件开发工具包 (SDK),它包含了所有必需的脚本和依赖项来处理音频流并与远程服务通信[^3]。 #### 初始化 DeepSeek 客户端实例 在项目的 `Assets/Scripts` 文件夹下新建 C# 脚本来管理与 DeepSeek 的交互逻辑: ```csharp using UnityEngine; using System.Collections; public class VoiceInputManager : MonoBehaviour { private void Start() { // Initialize the client with your app key and secret here. var deepseekClient = new DeepSeekClient("your_app_key", "your_secret"); Debug.Log("DeepSeek Client Initialized."); } } ``` #### 设置麦克风录音设备 利用 Unity 自带的功能获取用户的麦克风访问授权,并设置合适的采样率和其他参数以便于后续传输给服务器分析: ```csharp private MicrophoneRecorder microphoneRecorder; void Awake(){ microphoneRecorder = gameObject.AddComponent<MicrophoneRecorder>(); } // A simple implementation of a recorder that captures audio from the default device at runtime. class MicrophoneRecorder : MonoBehaviour{ public AudioClip clip { get; private set;} AudioSource source; void OnEnable(){ if(Microphone.devices.Length == 0){ Debug.LogError("No microphones found!"); return ; } string micDeviceName = Microphone.devices[0]; int sampleRate = AudioSettings.outputSampleRate; float durationInSeconds = 5f; // Set desired recording length. StartCoroutine(Record(micDeviceName, sampleRate, durationInSeconds)); } IEnumerator Record(string deviceName,int hz,float seconds){ yield return null; using(var stream = Microphone.Start(deviceName,false,hz*seconds,hz)){ while(!Microphone.GetPosition(null)>0){yield return null;} clip = Microphone.End(deviceName); source.PlayOneShot(clip); SendAudioToServer(); } } async Task SendAudioToServer(){ byte[] bytes; using(var ms=new MemoryStream()){ clip.GetData().CopyTo(ms); bytes=ms.ToArray(); } await deepseekClient.RecognizeSpeechAsync(bytes,"audio/x-wav").ContinueWith(task=>{ if(task.IsFaulted || task.IsCanceled){ throw new Exception($"Recognition failed: {(task.Exception?.Message ?? "Unknown error")}"); }else{ var resultText = task.Result.Text; Debug.Log($"Recognized text: '{resultText}'"); } }); } } ``` 上述代码片段展示了如何捕获来自默认麦克风的声音数据,并将其转换为适合发送至 DeepSeek 远程接口的形式。注意这里假设了特定格式(`"audio/x-wav"`),实际应用时可能需要调整以匹配目标平台的要求[^4]。 #### 处理返回的结果 当接收到由 DeepSeek 解析后的文本字符串后,在控制台打印出来供开发者调试查看;也可以进一步绑定这些信息到 UI 组件上让用户直观感受到反馈效果[^5]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值