天天看点

Unity3D协程(二)

协程的参数

抽象化一个协程的第一个方法是给它传递参数,协程作为一个函数方法来说,它自然能够传递参数。

// Use this for initialization
	void Start ()
	{
		StartCoroutine (CoroutineMethod ()); 

		//Log "Hello!" 5 times with 1 second between each log  
		StartCoroutine (RepeatMessage (5, 1.0f, "Hello!"));  
	}

	IEnumerator RepeatMessage (int count, float frequency, string message)
	{  
		for (int i = 0; i < count; i++) {  
			Debug.Log (message);  
			for (float timer = 0; timer < frequency; timer += Time.deltaTime)
				yield return 0;  
		}  
	}
           

嵌套的协程

在此之前,我们yield的时候总是用0(或者null),仅仅告诉程序在继续执行前等待下一帧。协程最强大的一个功能就是它们可以通过使用yield语句来相互嵌套。我们先来创建一个简单的Wait()程序,不需要它做任何事,只需要在运行的时候等待一段时间就结束。

// Use this for initialization
	void Start ()
	{
		StartCoroutine (CoroutineMethod ()); 

		//Log "Hello!" 5 times with 1 second between each log  
		StartCoroutine (RepeatMessage (5, 1.0f, "Hello!"));  

		StartCoroutine (SaySomeThings ());  
	}

	//Say some messages separated by time
	IEnumerator SaySomeThings ()
	{  
		Debug.Log ("The routine has started");  
		yield return StartCoroutine (Wait (1.0f));  
		Debug.Log ("1 second has passed since the last message");  
                //yield return StartCoroutine (Wait (2.5f));		
                yield return new WaitForSeconds (2.5f);
		Debug.Log ("2.5 seconds have passed since the last message");  
	}

	//Our wait function
	IEnumerator Wait (float duration)
	{  
		for (float timer = 0; timer < duration; timer += Time.deltaTime)
			yield return 0;  
	}
           

第二个方法用了yield,但它并没有用0或者null,而是用了Wait()来yield,这相当于是说,“不再继续执行本程序,直到Wait程序结束”。

运动到某一位置

给targetPosition和moveSpeed变量赋值即可,这个程序并没有通过一个计时器或者无限循环,而是根据对象是否到达指定位置来yield。

public Vector3 targetPosition;
	public float moveSpeed;

	// Use this for initialization
	void Start ()
	{
		StartCoroutine (CoroutineMethod ()); 

		//Log "Hello!" 5 times with 1 second between each log  
		StartCoroutine (RepeatMessage (5, 1.0f, "Hello!"));  

		StartCoroutine (SaySomeThings ());  

		StartCoroutine (MoveToPosition (targetPosition));  
	}

	IEnumerator MoveToPosition (Vector3 target)
	{  
		while (transform.position != target) {  
			transform.position = Vector3.MoveTowards (transform.position, target, moveSpeed * Time.deltaTime);  
			yield return 0;  
		}  
	}
           

按指定路径前进

通过MoveToPosition() ,我们可以让它在这些点之间持续运动。

// Use this for initialization
	void Start ()
	{
		StartCoroutine (CoroutineMethod ()); 

		//Log "Hello!" 5 times with 1 second between each log  
		StartCoroutine (RepeatMessage (5, 1.0f, "Hello!"));  

		StartCoroutine (SaySomeThings ());  

		StartCoroutine (MoveToPosition (targetPosition));  

		StartCoroutine (MoveOnPath (true));  
	}

	IEnumerator MoveOnPath (bool loop)
	{  
		do {  
			foreach (var point in path) {
				yield return StartCoroutine (MoveToPosition (point));  
			}
		} while(loop);  
	}

	IEnumerator MoveToPosition (Vector3 target)
	{  
		while (transform.position != target) {  
			transform.position = Vector3.MoveTowards (transform.position, target, moveSpeed * Time.deltaTime);  
			yield return 0;  
		}  
	}
           

我还加了一个布尔变量,你可以控制在对象运动到最后一个点时是否要进行循环。

把Wait()程序加进来,这样就能让我们的对象在某个点就可以选择是否暂停下来,就像一个正在巡逻的AI守卫一样。!

注意:

如果你刚接触协程,我希望这两个教程能帮助你了解它们是如何工作的,以及如何来使用它们。以下是一些在使用协程时须谨记的其他注意事项:

  • l 在程序中调用StopCoroutine()方法只能终止以字符串形式启动(开始)的协程;
  • l 多个协程可以同时运行,它们会根据各自的启动顺序来更新;
  • l 协程可以嵌套任意多层(在这个例子中我们只嵌套了一层);
  • l 如果你想让多个脚本访问一个协程,那么你可以定义静态的协程;
  • l 协程不是多线程(尽管它们看上去是这样的),它们运行在同一线程中,跟普通的脚本一样;
  • l 如果你的程序需要进行大量的计算,那么可以考虑在一个随时间进行的协程中处理它们;
  • l IEnumerator类型的方法不能带ref或者out型的参数,但可以带被传递的引用;
  • l 目前在Unity中没有简便的方法来检测作用于对象的协程数量以及具体是哪些协程作用在对象上。