漫话Unity(二)
三、Unity编辑器介绍
Unity是一个商业级的3d游戏引擎。一个引擎的专业程度事实上并非体如今它多么牛b 的次世代效果,说实话那些效果即便你会用也不敢用,由于没有哪个手机是次世代的。游戏引擎的专业程度体如今两个方面,一是编辑器的完好程度,二是基础设施的完好程度和优化程度(比方说异步资源载入,文件打包系统,场景管理效率。裁剪性能,渲染优化。性能分析等等)。毫无疑问Unity在这些方面都是很优秀的。除了写代码。你能够使用自己习惯的编辑器外。其它的东西都能够在Unity提供的一个大一统的编辑器下完毕。包含场景编辑,游戏调试,资源管理,动画编辑等等。甚至你还能够轻易的扩展编辑器的功能。让它提供诸如关卡编辑、怪物编辑、技能编辑等等功能。
这个就是Unity的编辑器了。最上面是一行菜单,菜单能够轻易的通过代码来扩展。
第一部分是场景物件浏览窗体,全部的场景物件都会在这里显示出来,假设执行了游戏,那么动态创建的物件也会在这里显示出来。你能够点击当中的一个物件来查看和改动它的属性。
第二部分是游戏执行窗体。能够查看游戏执行结果。游戏执行的时候也能够切换到scene分页查看当前场景,在场景视口中能够操作场景摄像机和场景物件。
第三部分是物件属性窗体。能够查看当前选定物件或者资源的属性。
每一个物件必定都有Transform属性。控制物件的大小、旋转、缩放。这里的属性改动能够直接反馈到执行的游戏中,可是要注意,执行时的属性改动不会保存,停止执行后属性会还原。
第四部分是资源窗体。它显示的是当前Assets文件夹下的实际文件夹和文件。这里须要注意两点,点击这里然后改动属性相应的是文件改动。不存在游戏执行与否的差别。
移动文件尽量在Unity内部进行。这样材质和脚本等会被正确的关联。可是假设是在windows浏览器下改动的,那么非常有可能这些关联就都丢失了,你就不得不又一次绑定或者设置。
四、Unity的开发语言
Unity的开发语言是C#,当然假设你很熟悉javascript或者很不喜欢c#,你也能够选择使用js来进行开发。在我看来js除了个人语言习惯外并没有其它优势,为了提高执行效率,Unity中的js并非纯正的js。而是经过改动的(貌似是微软干的),并且js是编译成dll之后才载入执行的。这意味着不可能像cocos2d-x中的js一样。当作纯脚本动态的更新并载入。
C#原本是微软的.Net官方语言,是windows独有的。而开源界的大神们开启了一个名叫Mono的项目,用于把C#移植到Linux等非windows平台。而Unity正是基于Mono项目,使得其具备非凡的跨平台移植能力。
Unity运行C#的原理是先编译成dll(不管是哪个平台都是dll。这个动态库并非程序直接载入的那种动态库。而是由Mono库来载入运行的)。然后载入运行。这意味着你不能更新代码的内容(细节会在后面讨论自己主动更新的时候再说),由于代码文件已经包括程序包内了。可是在不更新代码内容的前提下。一个预制(Prefab,后面会介绍)中绑定哪个脚本以及脚本开放的參数配置都是能够任意更新的。
五、Unity的基本元素
Unity场景中的全部物件都是GameObject。
GameObject是一个物件(如一个箱子。或者一个怪物),同一时候它也是一个节点,比方你能够创建一个空的GameObject然后把全部的怪物都挂接在这个节点下。场景物件窗体能够直接看到全部物件的层级关系。
每一个GameObject都能够加入随意的Component。组件是Unity中还有一个核心的基本要素。能够说万事万物皆组件。Unity中写代码的过程就是创建脚本作为组件挂接到GameObject上面来操作其属性的过程。你仅仅能创建一个GameObject而不能通过继承来扩展它,可是你能够通过组件来随意的扩展它的功能,这就是基于组件的编程模式。
习惯之后就会发现它的灵活和强大之处。
GameObject有一个必备的组件就是Transform。它描写叙述了物件的旋转、偏移、缩放,在属性窗体中显示的都是相对于父节点的数值,假设你在代码中直接设置transform.position。Unity会自己主动把这个绝对坐标改动为相对于父节点的坐标。
其它一些经常使用的系统组件介绍:
Mesh Render、Skin Mesh Render模型都会有这个组件,负责模型的显示。
可以说仅仅要可以显示的东西,不管是复杂的人物模型,还是简单的几何体。或者纯粹是一个图片,都会有Mesh Render这个组件。
Material组件,材质跟Shader关联在一起。Mesh Render中选择依赖的材质,材质中选择使用的Shader,shader中选择相应的纹理。这几样东西配合起来就组成了一个可渲染的物体。
Collider组件,碰撞盒(Box Collider),模型碰撞体(Mesh Collider)等都是属于这个组件。
要想发生碰撞必定要设置这个组件。
RigidBody组件,刚体组件,控制一个物体的质量、阻力等等。要想发生碰撞,碰撞的两方一定要有一个物体是具备刚体组件的。
Charactor Controller组件,这个比較特别,它与刚体组件等价。用于模拟rpg或者fps中的主角的物理运动效果,能够发生碰撞。可是不受真实物理影响。
Animator组件,控制人物动画播放。
Unity中最经常使用的系统组件就这些。剩下的另一些是特殊物体特有的,比方摄像机控制、灯光、地形等等。
六、Unity脚本开发之函数
Unity非常聪明的选择了C#来作为脚本,能够在保证效率的基础上减少了开发门槛。 C#具备三个非常优秀的品质,垃圾收集、完好的基础库和反射机制,这些是c++非常难具备的(不是说c++就不具备。仅仅只是实现并推广基于c++的垃圾收集和反射并非一件多么easy的事情,像boost十多年了也没有真正普及)。
全部的脚本都是继承自MonoBehaviour。而MonoBehaviour则继承自Component,它就是一个组件。
你能够任意创建脚本。然后把它挂接到GameObject。然后脚本就会被运行。MonoBehaviour提供了非常多基础的功能,熟悉这些功能后Unity的脚本开发就不在话下了。
Awake Start Destroy OnEnable OnDisable Update OnGUI,这几个是最经常使用的函数,你仅仅要在脚本中创建这么一个函数,那它就会在合适的时机调用。 调用的方式是基于反射的,并非基于虚函数。所以函数是否是public,返回值是什么都无关紧要。可是要注意,假设是自己写的基于虚函数的override的话。就要在基类里面声明函数为virtual。子类里面声明为override,假设忘记写,编译器不会报错,可是运行不到正确的代码。
Awake是在刚绑定好脚本的时候(多数情况下就是GameObject被实例化好的时候)调用,这个时候全部的开放给编辑器配置參数都会初始化好。是脚本最先被运行的代码。
Start是物体在第一帧被渲染的时候调用。有时候你会实例化一个物体,然后再在代码中设置一些參数,而依赖于这样的操作的代码都能够放到Start里面。
Update是每一帧都会被调用的函数。与之类似的还有FixedUpdate,这个函数是固定间隔调用。时间快慢、帧率快慢、是否在后台都没有关系。基本上能够这么觉得除了物理模拟等特殊情况,否则能不用FixedUpdate就不用,能不写Update就不要再脚本中保留这个函数。
OnGUI是绘制Unity的UI的时候调用的,一般这个函数没什么用。除了測试的时候方便些(如任意两行代码写一个button。然后点击后触发一个測试的效果),不管从便捷性还是效率上都被那些GUI插件甩了几条街。
这里在额外提两个函数OnCollisionEnter和OnTriggerEnter,这两个是碰撞检測相关的。
假设物体上有碰撞盒那么就会调用该物体绑定脚本中的这个函数。假设Collider勾选了IsTrigger选项。那么碰撞和不会发生碰撞位移,纯粹是作为触发器,调用的是Trigger系列的函数。否则调用的是Collision系列的函数。 每一个系列都有Enter Stay Exist三个函数分别相应物体刚发生碰撞,持续碰撞中,物体分离的情况。
七、Unity脚本开发之属性与消息传递
每一个组件(事实上就是脚本内部),都有一些列属性能够方便的获取到我们想要的对象。属性内有gameObject、transform、rigidbody、collider、audio、render等属性。最经常使用的并且也是必定有的是gameObject和transform,它就是这个脚本所挂接的物体。假设这个物体上面同一时候还有刚体或者碰撞盒或者加入了声音组件,那么直接rigidbody等系统默认提供好的属性就能够用了。当然,你也能够手工在代码中使用GetComponent<要查找的类名>()来获取组件。
gameObject中有transform和rigidbody等属性。transform和rigidbody中相同有gameObject属性,这些引用关系能够方便的通过随意对象查找到你须要的东西。
你能够直接使用GameObject.Find("对象名字")来查找一个物体,当中对象名字能够包括层级路径。
gameObject也能够使用GetComponent或者GetComponentInChildren来在当前或者子节点中获取相应的脚本。相关的函数很丰富,你能够依据对象类型或者是Tag标签名等等来获取一个或者多个物体。
脚本内部能够使用Invoke("函数名", 延迟时间)来异步调用一个当前脚本内部的函数。或者使用SendMessage("函数名",參数)来调用一个函数,SendMessage非常方便的一点是它能够由gameObject来调用,仅仅要你获得了一个物体,就能够使用SendMessage来调用一个函数。仅仅要这个物体绑定的脚本中有一个同名函数,那么就会被调用。当然灵活也是有代价的,不管是Invoke还是SendMessage都比实际函数调用或者是托付(delegate)要低效非常多,所以不要滥用(比方在Update中使用)。
熟悉了这几个知识点,那么你就能够写出符合Unity风格的代码了。剩下的都是对基础数学、算法、图形学、设计模式的理解了,这些知识是与引擎无关的,你拿Ogre能写出来,Unity也能够轻松的实现。
(第二部分在这里告一段落,它描写叙述了Unity开发究竟是怎么回事,尽管基础,可是是经过一段时间的代码积累才总结出来的,作为入门。它更加直面本质。我一直以为。会学习的人和不会学习的人区别就在总结和对本质的把握上面。
会学习的人可以把握事物的本质。可以总结出这些东西究竟有哪几个知识点。原理是什么,原因是什么;而不会学习的人仅仅会照猫画虎。能实现功能可是不得要领,知其然而不知道其所以然)