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. Shiro的认识

    #2019.2.2 Apache Shiro是基于java的一个安全框架.他帮助我们完成:认证.授权.加密.会话管理.web集成.缓存等问题. 在了Shiro之前,先要了解一下什么是权限管理? 权限管 ...

  2. linux之文件权限+用户权限

    chmod 文件权限命令: 文件权限: r是否能查看文件内容 w是否能修改文件的内容,需要与r权限配合使用   只有w的时候vim强制修改文件内容,会导致源文件内容清空 x是否能运行命令或脚本权限,需 ...

  3. WeX5学习笔记-02

    1.安装wex5,下载地址 http://wex5.com WeX5是绿色免安装的,解压即可直接使用.注意:不能解压到含中文.空格和特殊字符 的目录下, 例如:Program Files,是不可以的, ...

  4. 从零开始写自己的PHP框架系列教程(二)[App.php]

    从这一个文件开始以后加载的均以类加载,请注意命名空间和所在文件的路径 APP.php的这个类所在路径:根目录\framework\App.php 直接上代码 namespace framework; ...

  5. WEB学习笔记4-前端代码基本命名规法和格式规范

    1.HTML命名规范及格式规范 标签名和属性应该都小写,虽然HTML代码不区分大小写:属性值应该用双引号闭合. <IMG src=demo.jpg alt='test'/>(N) < ...

  6. 解决npm ERR! Please try running this command again as root/Administrator. 问题

    win10下,使用npm 安装插件时报npm ERR! Please try running this command again as root/Administrator的错误, 解决方案:需要删 ...

  7. mysql 数据库

    show databases 显示库use databse 进入库(databse为库名)show tables 显示表create table a select * from b where 0=1 ...

  8. 微信小程序登录(包括获取不到unionid的情况)

    我们一般都是先获取到微信的 unionid,然后再通过 unionid 去登录自己的网站,就可以关联到用户在自己网站上的 user_id,但是在小程序登录中,有时候可以获取到 unionid,有时候获 ...

  9. Codeforces1097D. Makoto and a Blackboard(数论+dp+概率期望)

    题目链接:传送门 题目大意: 给出一个整数n写在黑板上,每次操作会将黑板上的数(初始值为n)等概率随机替换成它的因子. 问k次操作之后,留在黑板上的数的期望. 要求结果对109+7取模,若结果不是整数 ...

  10. H5视频直播扫盲

    H5视频直播扫盲 2016-05-25 • 前端杂项 • 14 条评论 • lvming19901227 视频直播这么火,再不学就out了. 为了紧跟潮流,本文将向大家介绍一下视频直播中的基本流程和主 ...