协同函数的脚本编写






Scripting with Coroutines 编写带有协同程序的脚本

计时器示例
在第一个 讲解协同程序的教程中,我们学习了协同程序可以被用来“暂停”一个方法,直到返回yield得到一个想要的值,创建一个很好的计时系统。对于协同程序最擅长的是处理通用的执行步骤,例如计时器,它可以被简单的抽象和重用。

协同程序的参数
抽象出一个协同程序的第一步是给它一些参数。因为协同程序仅仅是一个方法,这就代表它们可以带有参数。这里有一个例子,协同程序说了一个被选择的信息和被设定的说话频率。
using UnityEngine;
using System.Collections;
 
public class TimerExample : MonoBehaviour
{
    void Start()
    {
        //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;
             
        }
    }
}
嵌套的协同程序
到现在为止,我们总是产生一个0(或者null),这告诉协同程序在继续运行之前要等到下一帧。协同程序一个最强力的特性是它们有能力在内部嵌套一个其他的yield状态。
为了看到这个行为,让我们先创建一个简单的Wait()示例。它实际不是做一些事情,只是用来占用一些时间。
IEnumerator Wait(float duration)
{
    for (float timer = 0; timer < duration; timer += Time.deltaTime)
        yield return 0;
}
现在,我们可以写另外的协同程序,看起来像这样:
using UnityEngine;
using System.Collections;
 
public class TimerExample : MonoBehaviour
{
    void Start()
    {
        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));
        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,它yield一个Wait(),这基本上可以这么说,“不要继续这个任务了,想继续的话要等到Wait完成”。
现在,关于协同程序最有力量的设计开始了。

行为的例子
这是最后一个例子,它仅仅显示了协同程序是如何控制物体的行为,以及创建简便的计时器。协同程序不是必须要返回一个时间线,他们可以很完美的产生任何的状况。结合嵌套示例和这个,可以给我们控制游戏对象状态最有力的工具。

移动位置
在这个脚本中,我们有一个简单的组件————targetPosition和moveSpeed变量,这可以在监视器中设置。当我们运行游戏时,我们的对象会使用一个协同程序去移动到设定的位置和被选中的速度。
using UnityEngine;
using System.Collections;
 
public class MoveExample : MonoBehaviour
{
    public Vector3 targetPosition;
    public float moveSpeed;
 
    void Start()
    {
        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()的示例,我们可以连续的工作在每一个点上。
using UnityEngine;
using System.Collections;
 
public class MoveExample : MonoBehaviour
{
    public Vector3[] path;
    public float moveSpeed;
 
    void Start()
    {
        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。

注意
如果你在协同程序上是一个新手,我希望这两个教程可以帮助你包装你的大脑,让你知道他们是如何工作并且如何使用。这里有一些额外的事情,在使用协同程序的时候应该记住:
*你仅仅能使用StopCoroutine()函数处理一个以string名的方式调用开始的协同程序。
*多个协同程序可以同时运行,他们会按照开始的顺序被更新。
*协同程序可以被按照以想要的深度嵌套起来(我们仅仅在例子中嵌套了一个级别)。
*如果你想要一个协同程序被很多脚本访问,你可以让他们变成一个static静态类型。(如果非要设计成静态模式的话,个人并不认同这个理由就要把协同程序做成静态的。这样很不安全)
*虽然有可能,但现在协同程序还不是多线程的,他们运行在一般的脚本所运行的线程中。
*如果你需要处理了消耗很多计算的需求,考虑把他们放在协同函数中,并通过时间来控制计算。
*IEnumerator函数不能有ref和out的参数,但是他们可以带有参数。
*目前为止,在Unity中没有简单的方法检测在一个物体上有多少、有哪些协同程序当前正在运行。(注意一下!)

如果你在这个教程中发现任何错误或者不对的细节,或者有一些建议或者请求的话,可以下边提交评论。
贤狼罗兰斯:最后,感谢ChevyRay的教程,真的很有帮助。就这么默默的翻译了也不要怪我,毕竟不靠这赚钱,也没多少人访问。

你可能感兴趣的:(Unity3D)