码迷,mamicode.com
首页 > 其他好文 > 详细

扩展Coroutine:自定义YieldInstruction

时间:2015-07-06 18:00:41      阅读:124      评论:0      收藏:0      [点我收藏+]

标签:unity   unity3d   coroutine   


Unity的Coroutine机制无疑是这个引擎的一个亮点,可以把很多异步的逻辑用一种顺序的书写方式去实现,这个还是很重要的。

关于Coroutine的原理,说实话,这个没有源代码,不好说具体是怎么实现的。看他用到了IEnumerator,想象是使用了.Net的枚举机制。网上有不是探讨Coroutine实现原理的帖子,有兴趣的同学可以翻开看看。

Coroutine之所以强大,缺不了一系列YieldInstruction的派生类,包括:WaitForSeconds , WaitForFixedUpdate,AsyncOperation等等,我一直在琢磨能不能实现自己的YieldInstruction派生类呢?今天花时间尝试了一些,答案是“不能,也能”,哈哈。为什么说“不能”呢,是因为YieldInstruction这个类可没什么虚函数可以去override的,为什么说“能”呢!我们可以借用一个特殊的YieldInstruction派生类,来实现等同的功能,这个类就是Coroutine。

完整的演示工程下载:http://pan.baidu.com/s/1jGGhRKE


这个工程是这样一个例子:
假设我们想实现这样一个YieldInstruction:当一个动画播放完事儿之后,程序再继续。

具体的实现也很简单,首先我们需要一个IEnumerator的派生类,并实现其3个接口,具体代码如下:

using UnityEngine;
using System.Collections;

public class WaitForEndOfAnim : IEnumerator
{
    AnimationState m_animState;

    public WaitForEndOfAnim(AnimationState animState)
    {
        m_animState = animState;
    }
    //-- IEnumerator Interface
    public object Current
    {
        get
        {
            return null;
        }
    }

    //-- IEnumerator Interface
    public bool MoveNext()
    {
        return m_animState.enabled;
    }

    //-- IEnumerator Interface
    public void Reset()
    {
    }
}

这里面核心的逻辑就在“MoveNext”函数中,我通过m_animState.enabled来判断动画是否播放完了。

有了这个类时候,如果我们在协程函数体中写:yield return new WaitForEndOfAnim(animState),发现并没有其作用。后来改为:yield return StartCoroutine(new WaitForEndOfAnim(animAttack));就OK了。完整的测试代码如下:

using UnityEngine;
using System.Collections;

public class UnitTest : MonoBehaviour
{

    // Use this for initialization
    void Start()
    {
    }

    void OnGUI()
    {
        GUILayout.BeginArea(new Rect(6, 6, 200, 300));
        GUILayout.BeginVertical();
        GUILayout.Box("Conrountinue测试");

        if (GUILayout.Button("启动"))
        {
            StartCoroutine(DoTest());
        }

        GUILayout.EndVertical();
        GUILayout.EndArea();
    }

    IEnumerator DoTest()
    {

        Animation anim = GetComponentInChildren<Animation>();
        AnimationState animAttack = anim["attack"];
        animAttack.speed = 0.1f;

        AnimationState animHit = anim["hit"];
        animHit.speed = 0.1f;

        AnimationState animDie = anim["die"];
        animDie.speed = 0.1f;

        Debug.Log("1.开始播放攻击动画。" + Time.time * 1000);
        anim.Play(animAttack.name);
        yield return StartCoroutine(new WaitForEndOfAnim(animAttack));

        Debug.Log("2.开始播放受击动画。" + Time.time * 1000);
        anim.Play(animHit.name);
        yield return StartCoroutine(new WaitForEndOfAnim(animHit));

        Debug.Log("3.开始播放死亡动画。" + Time.time * 1000);
        anim.Play(animDie.name);
        yield return StartCoroutine(new WaitForEndOfAnim(animDie));

    }
}
最后,运行结果看下图,注意时间戳:

技术分享


版权声明:本文为博主原创文章,未经博主允许不得转载。

扩展Coroutine:自定义YieldInstruction

标签:unity   unity3d   coroutine   

原文地址:http://blog.csdn.net/neil3d/article/details/46775267

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!