1. 协程

  在Unity 3D中,我们刚开始写脚本的时候肯定会遇到类似下面这样的需求:每隔3秒发射一个烟花、怪物死亡后20秒再复活之类的。刚开始的时候喜欢把这些东西都塞到Update里面去,就像下面这样写。

 float nowTime = 3.0f;
bool isDead = true;
float deadTime = 20.0f; void startFireworks()
{
// 放烟花
} void revival()
{
// 复活
} void Update ()
{
if (nowTime <= )
{
startFireworks();
nowTime = Random.Range(2.5f, 3.5f);
}
nowTime -= Time.deltaTime;
if (isDead)
{
if (deadTime <= )
{
revival();
isDead = false;
deadTime = 30.0f;
}
deadTime -= Time.deltaTime;
}
}

  当这样的需求多起来时,Update中凌乱不堪,如果有需求需要添加或者修改,将显得非常麻烦。尤其是类似死亡后复活这种需求,只是在死亡后等待30秒重新复活,其他时间根本不需要去执行,这样放在Update里面还需要每一帧去判断,显得很累赘。

好在Unity 3D支持yield协程,不懂没关系,先看看下面用协程实现上面的功能。

 void Start()
{
StartCoroutine(Fireworks());
} void deadHandle()
{
StartCoroutine(Revival());
} IEnumerator Fireworks()
{
while (true)
{
startFireworks();
yield return new WaitForSeconds(Random.Range(2.5f, 3.5f));
}
} IEnumerator Revival()
{
yield return new WaitForSeconds(30.0f);
revival();
}

  上面代码中,以IEnumerator作为返回值的函数就是协程,调用StartCoroutine()开始协程,在Start函数中调用StartCoroutine(Fireworks());,说明在开始时就开始执行协程Fireworks(),在deadHandle()中调用StartCoroutine(Revival());说明是在怪物死亡时开始执行协程。

  现在再来看看协程Fireworks()和Revival()中带有yield return的语句,yield return new WaitForSeconds(30.0f);表示现在从return这个语句处中断执行,在30秒后继续执行后面的代码。

  如果想在下一帧继续执行,就应该这样写 yield return null,这样语句就会在return这里中断,等待下一帧继续执行后面的代码。就像在Fireworks()里面写的,return之后,继续进行while判断,为true则继续循环,遇到yield return中断执行,等待,反复这样运行,就像Update一样。当然while中的判断条件可以自己指定,在需要中断的时候,在外面将while中的判断条件置为false即可。

 bool isContinue = true;
void stopFireworks()
{
isContinue = false;
}
IEnumerator Fireworks()
{
while (isContinue)
{
startFireworks();
yield return new WaitForSeconds(Random.Range(2.5f, 3.5f));
}
}

  当然也可以通过有StopCoroutine来中止协程的执行,不过这个函数是有条件的,具体可以去查阅unity文档或者网上搜索一下,有很多资料,这里只是告诉大家有这么个东西可以用。

  有了协程,写起脚本来真是方便了很多。协程和Update一样,也是系统在每帧会去检测调用,因此在协程中也是可以使用Time.deltaTime的。关于协程与Update之类的执行顺序,没有测试过,网上也有一些资料,大家可以参考,不同的Unity 3D版本具体的实现可能有出入,如果某些功能确实需要知道执行顺序,那么到时候可以亲测一下。

  需要注意的一点是:WaitForSeconds是受到Time.timeScale影响的,如果将其置为0,那么协程就无法执行下去了。不过yield return null不会受到影响,因为每帧会执行,只是Time.deltaTime为0了。

  2. 消息传递

  在游戏开发中,消息传递必不可少。通常有三种方式:保存别的对象的引用、Unity自带的SendMessage和C#中的事件。

  例如一个暂停,我需要通知玩家,暂停了,不要响应键盘鼠标操作了;通知UI,显示一个暂停面板;通过所有怪物,不要动了,暂停了,休息一下。

  第一种方式是刚开始写脚本时常用的,保存所有对象的引用,这是很麻烦的事情,我需要获取玩家、UI和所有的怪物对象,然后调用其相应的暂停函数,这在程序规模变大之后,添加、修改和删除是一个很大的工作量。而且很多对象之间相互引用,耦合对也很高,用起来比较麻烦。

  第二种方式是Unity 3D提供的Messages消息机制,不过网上说这种方法有很大的缺陷,而且只能通知一个父子关系的对象,不同对象之间的消息无法传递。没有用过这个机制,所以也不是很清楚是不是像上面说的那样。

  第三种方式是C#中的委托和事件,这个方法对于消息传递来说非常好用,从设计模式的角度上来说,就是一个典型的观察者模式。如果你用过EasyTouch摇杆,那你就应该知道在OnEnable()中使用EasyJoystick.On_JoystickMove += OnJoystickMove;注册自己的Move函数,在这里就是OnJoystickMove。其实EasyTouch这个就用到了C#事件,使用+=添加自己的响应函数,当发生摇杆移动时,就会调用你自己指定的OnJoystickMove函数。具体可以参考下面给出的参考资料的链接。

  今天就写到这里,这些都是简介性质的,详细资料网上都有很多,我这些只是告诉初学者Unity 3D中有这些东西,很可能是你需要的,可以少走一些弯路。

  关于协程和C#事件,是Unity 3D中强力推荐的两个机制,它们真的非常重要,一定要善用,大家可以体会一下。

  参考资料1:【吐血推荐】简要分析unity3d中剪不断理还乱的yield

  参考资料2:C# 事件和Unity3D

Unity 3D中不得不说的yield协程与消息传递的更多相关文章

  1. 在Unity 3D中加入Image图片

    在Unity 3D中加入Image图片,我在刚开始是加不进去的,为什么呢?因为没有图片,图如下: 原因就是我们没有把图片设置为Script,图片的格式还是默认的那个,这只能作为贴图使用.我们将图片进行 ...

  2. Unity 3D中的阴影设置

    在Unity 3D中,经常需要用到光照阴影,即Directional Light的Shadow,Shadow分为Hard Shadow和Soft Shadow.区别是Soft Shadow的阴影边缘比 ...

  3. Unity 3d中Shader是什么,可以吃吗?

    众所周知,Unity3d是一款跨平台非常广的游戏引擎,上手容易,界面友好,集成功能众多,是目前开发手游的主流引擎.本人有幸使用Unity 3d进行开发已一年多时间,已领略了这歀引擎的强大之处. 编写s ...

  4. Unity 3D中C#的性能优化小陷阱

    本篇内容主要来自Unity官方手册: 一般性能优化 一些地方为本人瞎编杜撰,请酌情参考.如有错误,欢迎指出. Unity里C#编程虽然既简单还很爽,但是性能小陷阱还不少.我总强迫自己让代码最优,因此很 ...

  5. yield协程

    1.Generator Generator , 一种可以返回迭代器的生成器,当程序运行到yield的时候,当前程序就唤起协程记录上下文,然后主函数继续操作,当需要操作的时候,在通过迭代器的next重新 ...

  6. unity如何停止不用字符串方式开启协程的方法

    通常我们知道开启协程用StartCoroutine("Method"); 停止协程用StopCoroutine("Method"); 如果我们想要终止所有的协程 ...

  7. 6 生成器 yield 协程

    1.生成器 ----> 1 b = [x*2 for x in range(100000000000)] MemoryError: 想生成一个存放很多数据的列表,但是又不想内存占用太多 每次用一 ...

  8. python中进程、线程、协程简述

    进程 python中使用multiprocessing模块对进程进行操作管理 进程同步(锁.信号量.事件) 锁 —— multiprocessing.Lock 只要用到了锁 锁之间的代码就会变成同步的 ...

  9. 20170702-变量说明,静态方法,类方法区别,断点调试,fork,yield协程,进程,动态添加属性等。。

    概念: 并行:同时运行 并发:看似同时运行  json后任然中文的问题 import json d = {"名字":"初恋这件小事"} new_d1 = jso ...

随机推荐

  1. HTML5 浏览器支持

    css重置 header, section, footer, aside, nav, main, article, figure { display: block; } 为HTML添加新的元素 < ...

  2. Windows 2008 asp.net 配置

    目录 1.     前言.. 32.     部署环境.. 32.1         服务器环境信息.. 33.     磁盘阵列配置.. 44.     安装操作系统.. 45.     安装软件. ...

  3. wpf binging(三) 绑定方法的返回值

    有时候我们不能绑定对象的属性或者成员,我们需要绑定一个对象的方法时 可以用 ObjectDataProvider 比如先声明一个类 含有加法 ObjectDataProvider 的简单使用 以下为综 ...

  4. 搭建SSM(Spring+SpringMVC+Mybatis)

    1.SpringMVC和Spring不需要什么特殊配置就可以结合 2.Mybatis和Spring (1)需要引入额外的jar包:mybatis-spring-1.2.2.jar (2)配置数据源 ( ...

  5. Always an Integer 数论和字符串处理

    题意:判断一个整系数多项式除以一个常数结果是否一定是一个整数 大白p123例题.可以随机代入一些n的值,判断一下.不过只要代入1到k+1(k为多项式最高项的次数)即可.通过数学归纳法证明,先讨论k为0 ...

  6. Ubuntu 将其他盘挂载到/home的子目录下

    Ubuntu 14.04 将其他盘挂载到/home的子目录下当安装完Ubuntu系统,由于当时没有注意,分配的分区空间太小.经过一段时间安装了各式各样的软件后,常常会遇到/home目录下空间不够的情况 ...

  7. EtherCAT主站对PHY有要求?

    /********************************************************************** * EtherCAT主站对PHY有要求? * 说明: * ...

  8. Feign get接口传输对象引发一场追寻

    一个报错引发的追寻之路: Feign get接口传输对象,调用方接口代码: @FeignClient(name = "manage") public interface Acces ...

  9. SpringJPA主键生成采用自定义ID,自定义ID采用年月日时间格式

    自定义主键生成策略 在entity类上添加注解 @Id @GeneratedValue(strategy = GenerationType.AUTO, generator = "custom ...

  10. 20155219付颖卓《网络攻防》Exp4 恶意代码分析

    一.基础问题回答 如果在工作中怀疑一台主机上有恶意代码,但只是猜想,所有想监控下系统一天天的到底在干些什么.请设计下你想监控的操作有哪些,用什么方法来监控. 可以用window7自带的schtasks ...