Unity中携程与线程指南

在使用unity的过程中,对协程只知道如何使用,但并不知道协程的内部机理,对于自己不清楚的部分就像一块大石压力心里,让自己感觉到担忧和不适。这篇文章一探究竟,彻底揭开协程的面纱,让大家在使用中不再有后顾之忧。

协程是:程序组件来生成非抢占式多任务子函数,生成的子函数允许在程序里挂起和唤醒操作。通常协程可以很方便实现延时操作,以及异步加载操作。下面是两个简单协程使用例子。

延时操作:

<code class="hljs lasso">// Use this for initialization
02.void Start () {
03.StartCoroutine (Wait ());
04.}
05.
06.IEnumerator Wait(){
07.Debug.Log ('start time:' + Time.time);
08.yield return new WaitForSeconds (1);
09.Debug.Log ('time:' + Time.time);
10.yield return new WaitForSeconds(2);
11.Debug.Log ('time:' + Time.time);
12.}</code>

异步加载资源:

01.<code class="hljs lasso"><code class="hljs lasso">// Use this for initialization
02.void Start () {;
03.System.Action<string> callBack = delegate(string text) {
04.Debug.Log(text);
05.};
06.StartCoroutine (LoadRes (callBack));
07.}
08.
09.IEnumerator LoadRes(System.Action<string> callBack){
10.WWW www = new WWW ('http://www.baidu.com');
11.yield return www;
12.
13.if (string.IsNullOrEmpty (www.error)) {
14.callBack(www.text);
15.Debug.Log('load success');
16.}
17.else{
18.Debug.Log('load failed');
19.}
20.}</code></code>

原理:

Unity里的协程通过定义一个返回 IEnumerator类型的函数,先来通过一个函数看看Unity都能返回那些类型:

1.IEnumerator Test(){
2.yield return 2; // 返回整数
3.yield return 4.2; // 返回浮点数
4.yield return null; // 返回null
5.yield return new WaitForSeconds(1); // 返回instance
6.yield return new WWW ('http://www.baidu.com'); // 返回instance
7.}

返回的类型有什么要求?整理一下Unity都实现了那些返回类型:

1、int类型,需要等待的帧数
2、float类型,需要等待的时间(秒)
3、null,等待一帧
4、break,结束协程
5、实例,必须有bool isDone()成员函数,等isDone返回true
6、IEnumerator,等IEnumerator实例的MoveNext()返回false

Unity的返回类型知道了,如何捕获这些返回类型?来看IEnumerator如何实现的?

<code class="hljs lasso"><code class="hljs lasso"><code class="hljs cs"><code class="hljs cs">public interface IEnumerator
02.{
03.//
04.// Properties
05.//
06.object Current
07.{
08.get;
09.}
10.
11.//
12.// Methods
13.//
14.bool MoveNext ();
15.
16.void Reset ();
17.}</code></code></code></code>

通过研究IEnumerator接口,得到通过调用MoveNext,我们可以得到遍历所有yield返回的值,返回的值可以通过Current得到。每次调用MoveNext都会执行夹在yield中间的代码。写个测试程序来验证我们的理论:

01.<code class="hljs lasso"><code class="hljs lasso"><code class="hljs cs"><code class="hljs cs"><code class="hljs cs">publicclass game_client : MonoBehaviour {
02.
03.// Use this for initialization
04.void Start () {
05.IEnumerator i = Test ();
06.while (true) {
07.if(!i.MoveNext()){
08.break;
09.}
10.object cur = i.Current;
11.if(cur != null)
12.Debug.Log(cur.GetType());
13.else
14.Debug.Log('type is null');
15.}
16.}
17.
18.
19.IEnumerator Test(){
20.yield return 2;        
21.yield return 4.2;
22.yield return null;
23.yield return new WaitForSeconds(1);
24.yield return new WWW ('http://www.baidu.com');
25.}
26.}</code></code></code></code></code>

通过验证程序,可以得到yield返回的值,有了这些值,就可以实现自己的协程。
实现

设计接口:

1.<code class="hljs lasso"><code class="hljs lasso"><code class="hljs cs"><code class="hljs cs"><code class="hljs cs"><codeclass="hljs cs">class ScheduleCoroutine
2.{
3.public void StartCoroutine(IEnumerator coroutine);
4.public void StopCoroutine(IEnumerator coroutine);
5.public void Update(int frame, float time);
6.}</code></code></code></code></code></code>

设计数据结构:

01.<code class="hljs lasso"><code class="hljs lasso"><code class="hljs cs"><code class="hljs cs"><code class="hljs cs"><codeclass="hljs cs"><code class="hljs cs">class CoroutineNode{
02.public IEnumerator itor;
03.public string name;
04.public int frame;
05.public float time;
06.public Object instance;
07.public CoroutineNode pre;
08.public CoroutineNode next;
09.}</code></code></code></code></code></code></code>

具体实现代码,对于不同的项目需求,有不同的实现方式。这篇文章主要是探寻Unity协程的实现方式。搞清楚原理后,在使用上就会更加得心应手。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity使用线程可以提高游戏的性能和响应速度。但需要注意的是,Unity的所有API都是线程不安全的,所以在使用线程时,必须采用正确的方式来访问Unity API。 以下是在Unity使用线程的步骤: 1. 创建新的线程 使用C#的Thread类创建新的线程,如下所示: ``` Thread thread = new Thread(ThreadMethod); thread.Start(); ``` 其,`ThreadMethod`是新线程要执行的方法。 2. 在新线程执行逻辑 在新线程执行复杂的计算或其他需要耗费时间的操作。需要注意的是,在新线程不能直接访问Unity API。 3. 使用线程安全的方式访问Unity API 为了避免访问Unity API时出现线程安全问题,可以使用以下方法: - 使用线程安全的类型,如ConcurrentQueue,来存储需要在主线程处理的数据。 - 使用Unity的主线程调用方法,如`UnityMainThreadDispatcher.Instance().Enqueue()`方法,将需要在主线程执行的代码添加到主线程的执行队列。 以下是一个使用线程的示例代码: ``` private ConcurrentQueue<float> queue = new ConcurrentQueue<float>(); private void Update() { float value; while (queue.TryDequeue(out value)) { // 在主线程处理数据 Debug.Log(value); } } private void ThreadMethod() { for (float i = 0; i < 10000; i++) { queue.Enqueue(i); } } ``` 在上面的示例代码,我们使用ConcurrentQueue存储需要在主线程处理的数据。然后在Update方法不断地尝试从队列取出数据并在主线程处理。在新线程,我们向队列添加数据。这样可以保证在主线程处理数据,避免了访问Unity API时出现线程安全问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值