unity学习日记:关于协同程序Coroutine

协同程序(Coroutine),顾名思义,即在主程序运行时开启另一端逻辑,来和主程序一同运行。

例如:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class coroutine_test : MonoBehaviour {

	// Use this for initialization
	void Start () 
    {
        StartCoroutine("Delay",3f);//开启一个名为Delay的协同,并为其传递一个参数“3”
        Debug.Log("3"+"time:"+Time.time);
	}
	
	// Update is called once per frame
	void Update () {}

   IEnumerator Delay(float delaytime)//协同函数
    {
        print("1"+"time:"+Time.time);
        yield return new WaitForSeconds(delaytime);
        Debug.Log("2"+"time:"+Time.time);
      
    }
}
最终运行结果:

可以看到,当我们以StartCoroutine来在主程序中开启了Delay的时候,主程序与Delay在同时运行。

在接触Coroutine之前,当游戏里需要使用延时的时候,一般要设置StartTime和DelayTime,然后在Update里面一遍遍检测来完成延时。但使用yield return Coroutine(中断式协同),却可以很简单的完成。

例如:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class coroutine_test : MonoBehaviour {

	// Use this for initialization
	IEnumerator Start () 
    {
        Debug.Log("0" + "time:" + Time.time);
        yield return StartCoroutine("Delay", 3f);//开启一个名为Delay的协同,并为其传递一个参数“3”
        Debug.Log("3"+"time:"+Time.time);
	}
	
	// Update is called once per frame
	void Update () {}

   IEnumerator Delay(float delaytime)//协同函数
    {
        print("1"+"time:"+Time.time);
        yield return new WaitForSeconds(delaytime);//等待一定的时间
        Debug.Log("2"+"time:"+Time.time);
      
    }
}
最终结果:

显而易见,上例中主程序等待协同函数执行完毕后才继续向下执行 。

总结:(1)启动协同函数时要使用StartCoroutine(协同工作)或者 yield return StartCoroutine(中断式协同工作),当使用yield return StartCoroutin时,主函数(即yield return StartCoroutine语句所在的函数)的返回值类型必须为IEnumerator,当使用StartCoroutine时则不能为IEnumerator。(2)协同函数的返回值类型必须为IEnumerator。(3)在协同函数中延时语句为yield return new WaitForSeconds()。

无论是协同还是中断式协同,都可以实现多重嵌套协同,例如:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class coroutine_test : MonoBehaviour {

	// Use this for initialization
	IEnumerator Start () 
    {
        Debug.Log("0" + "time:" + Time.time);
        yield return StartCoroutine("Delay", 3f);//开启一个名为Delay的协同,并为其传递一个参数“3”
        Debug.Log("5"+"time:"+Time.time);
	}
	
	// Update is called once per frame
	void Update () {}

   IEnumerator Delay(float delaytime)//协同函数
    {
        yield return new WaitForSeconds(delaytime);
        print("1"+"time:"+Time.time);
        yield return StartCoroutine("Delay1",2f);//在Delay函数中嵌套协同函数Delay1函数,并使用中断协同
        Debug.Log("4"+"time:"+Time.time);
      
    }
   IEnumerator Delay1(float delaytime)//协同函数
   {
       print("2" + "time:" + Time.time);
       yield return new WaitForSeconds(delaytime);//等待一定的时间
       Debug.Log("3" + "time:" + Time.time);

   }
}

使用StartCoroutine(string methodName)和StartCoroutine(IEnumerator routine)都可以开启协同。

区别在于使用字符串作为参数可以开启协同并在其自动结束前主动终止,

相反使用IEnumerator 作为参数只能等待协同自动结束而不能随时终止(除非使用StopAllCoroutines()方法)

另外使用字符串作为参数时,开启协同时最多只能向协同函数里传递一个参数(例如:yield return StartCoroutine("Delay ",3f);),

并且性能消耗会更大一点,而使用IEnumerator 作为参数则没有这个限制(例如:yield return StartCoroutine(Delay(3f,2f));)。

使用StopCoroutine(string methodName)来终止一个协同程序,使用StopAllCoroutines()来终止所有可以终止的协同程序,

终止协同的方法:
(1)StopCoroutine(string method):

StartCoroutine("Test");
StopCoroutine("Test");
StartCoroutine("Test2",1);
StopCoroutine("Test2");

(2)StopCoroutine(Coroutine routine)

以下这样调用停不掉Coroutine 
StartCoroutine(Test()); 
StopCoroutine(Test()); 
StartCoroutine(Test2(1)); 
StopCoroutine(Test2(1)); 

应该这样 
Coroutine c = StartCoroutine(Test3(p1,p2)); 
StopCoroutine(c)

(3)StopCoroutine(IEnumrator routine)
IEnumrator coroutine = Test();
StartCoroutine(coroutine );
StopCoroutine(coroutine);
IEnumrator coroutine1 = Test2(1);
StartCoroutine(coroutine1  );
StopCoroutine(coroutine1 );
以下这样调用停不掉Coroutine:
IEnumrator coroutine1 = Test();
IEnumrator coroutine2 = Test();
StartCoroutine(coroutine1 );
StopCoroutine(coroutine2 );

(4)StopAllCoroutines() 

可以停掉当前脚本的所有Coroutine。
注:以上(1)(2)(3)只能停掉使用字符串当参数来启用的协同,(4)可以停掉所有类型启用的协同。

====================================================================================================================================
2017/7/17
当以协程作为计时器时并放在update里面时,需注意限制协程的启动,因为在满足条件的情况下,每一帧都会启动一个同样的协程,他们之间互不干扰并会执行一样的操作。例如为射击游戏更换弹夹做一个协程,放在Update里面,更换弹夹需2秒,若协程启动限制只有子弹数为零时启动,2秒后重置子弹数为最大,那么在这2秒中里子弹数仍然为零,仍然满足协程的启动条件,接下来的2秒内每一帧仍会再启动一个协程,第一个协程执行完的时候,立即开枪却不会减少子弹数,因为后续2秒内的协程会不停地重置弹夹,只有当后续的协程执行完才能正常运行,这种情况下需对协程的启动加另外一个限制,当携程启动后,此限制激活,不再满足启动协程的条件,当协程执行完后,此限制失效,可以再次执行协程,使得同时只有一个执行此操作的协程在运行。












  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值