zoukankan      html  css  js  c++  java
  • C#神器 委托 + Unity神器 协程

    作为源生的C#程序员,可能已经非常了解委托(delegate)、行动(Action)以及C#的事件了,不过作为一个半道转C#的程序员而言,这些东西可能还是有些陌生的,虽然委托并非是C#独创,亦非是首创,C++的函数指针就完全类似于委托的功能,但很多东西没有委托的话实现起来还是很伤脑筋的。

    本文主要介绍委托与unity协程之间组合开发的便利,实质上也是对平常的学习和工作中学到的东西做个记录。

    一、委托

    定义委托:public delegate void MyDelegate(int _num);

                    //定义一个委托MyDelegate,如同定义一个类一样,此时的委托没有经过实例化是无法使用的,而他的实例化必须接收一个返回值和参数都与他等同的函数,此处的委托MyDelegate只能接收返回值为void,参数为一个int的函数


    实例化委托:MyDelegate _MyDelegate=new MyDelegate(TestMod);

                    //以TestMod函数实例化一个MyDelegate类型的委托_MyDelegate,此处TestMod函数的定义就应如下:

                            public void TestMod(int _num);

                    //之后调用_MyDelegate(100)时就完全等同于调用TestMod(100)


    二、协程

    定义协程:public IEnumerator MyCoroutine(){ };

                    //定义一个协程MyCoroutine,不同于定义类或委托,此时的协程是可以直接使用的,Unity的每一个执行周期里都会包含属于协程的那一部分,只要是场景中属于激活状态的物体(active为true),如同update那般,Unity在渲染的每一帧都会去查找该物体上是否存在协程部分的代码,若存在则加入该物体协程的执行周期,协程部分的代码会如同update那样被Unity每帧执行,当然不同于update的是,大部分协程内部不存在延时的话,一次执行之后便会跳出了,而且既然是处于Unity规定的生命周期里的模块,协程如同update一样当他们所在的物体属于未激活的话(active为false),该物体上所有脚本中包含的协程代码都是不会被执行的。


    使用协程:StartCoroutine(MyCoroutine());

                    //使用StartCoroutine函数将协程MyCoroutine加入此脚本所在物体的协程执行周期内,如果在渲染的下一帧此物体依旧是处于激活状态的话,那么协程MyCoroutine中的代码便会得到Unity执行。



    三、委托+协程

    其实网上关于这个的例子很多,我在这里只是做个比较系统的归纳。

    还记得Unity的Invoke("test",2)吗(延时2秒后执行函数test)?不得不说这是个很大的坑,test函数不能赋予参数不说,还必须得是在当前类里面的方法,而对于延时执行等控制时间轴的操作,这在任何一个项目中肯定都是不可少的,索性有协程,我们完全可以替换掉Invoke的作用。

    我们可以自己写一个延时控制器:

    /// <summary>
        /// 延时执行
        /// </summary>
        /// <param name="action">执行的委托</param>
        /// <param name="delaySeconds">延时等待的秒数</param>
        public IEnumerator DelayToInvokeDo(Action action, float delaySeconds)
        {
            yield return new WaitForSeconds(delaySeconds);
            action();
        }
        /// <summary>
        /// 使用例子
        /// </summary>
         StartCoroutine(DelayToInvokeDo(delegate() {
                    task.SetActive(true);
                    task.transform.position = Vector3.zero;
                    task.transform.rotation = Quaternion.Euler(Vector3.zero);
                    task.doSomethings();
                },1.5f));


    我们可以看到这里的例子是在1.5秒之后执行一个匿名委托,该委托的内容是将游戏物体task激活,并设置其位置与旋转属性,然后可以做更多的事情。

    不过好像有些缺陷,task这个变量是哪里来的?Unity能否识别?事实上无论task是本类的全局静态变量还是普通单例变量,甚至只是一个与此部分协程代码处在同一域中的局部变量,加入到协程执行周期以后,短期内他是不会被释放的,也就不用担心Unity在后续执行到task的SetActive的时候会报空引用的错了。

    只不过我们确实可以将之完善一下,或许我想更好的控制task。

    /// <summary>
        /// 延时执行
        /// </summary>
        /// <param name="action">执行的委托</param>
        /// <param name="obj">委托的参数</param>
        /// <param name="delaySeconds">延时等待的秒数</param>
        public IEnumerator DelayToInvokeDo(Action<GameObject> action, GameObject obj,float delaySeconds)
        {
            yield return new WaitForSeconds(delaySeconds);
            action(obj);
        }
        /// <summary>
        /// 使用例子
        /// </summary>
         StartCoroutine(DelayToInvokeDo(delegate(GameObject task) {
                    task.SetActive(true);
                    task.transform.position = Vector3.zero;
                    task.transform.rotation = Quaternion.Euler(Vector3.zero);
                    task.doSomethings();
                },GameObject.Find("task1"),1.5f));


    1.5秒之后执行一个匿名委托,该委托的内容是将游戏物体task激活,并设置其位置与旋转属性,然后可以做更多的事情,这里的task是我们从场景中获取的name为task1的物体,将之作为参数传入了委托中。

    后续你可能需要更多的参数,更多的种类,不过那只需要在此基础上扩展就可以了,最后将协程DelayToInvokeDo放在一个全局脚本内,定义一个该脚本的静态变量,那么就可以在项目的任何位置加入这个协程了。



  • 相关阅读:
    git常用命令
    springcloud 心得记录
    Spring Boot整合RabbitMQ
    docker安装rabbitmq
    Linux按顺序启动多个jar的shell脚本
    idea连接docker实现一键部署
    docker安装mysql
    阿里云CentOS服务器挂载数据盘
    【selenium学习中级篇 -26】HTMLTestRunner生成测试报告
    【selenium学习中级篇 -25】Unittest框架
  • 原文地址:https://www.cnblogs.com/liang123/p/6325882.html
Copyright © 2011-2022 走看看