Mono基本介绍
Mono组件
C#编译器——MCS:MCS的作用就是将C#编译为CIL(通用中间语言)
Mono运行时(mono Runtime):运行时中的编译器将CIL的Byte Code在转译为原生码,同时提供即时编译(JIT),提前编译(AOT),完全静态编译(Full-AOT)三种转译方式
基础类库:提供广泛的基础类
Mono类库:提供额外的有用功能,尤其是构建Linux方面
Mono如何提供脚本功能
总所周知Unity是由C++写成的,将Mono运行时嵌入到由C++写成的应用后,该应用便会获取一个完整的虚拟机环境 。Mono的嵌入接口就会将Mono运行时暴露给C++代码,哪些C/C++代码被称为非托管代码,经CIL编译器生成的CIL代码被称为托管代码。
Mono运行时嵌入应用可分为3个步骤:
- 编译C++程序和链接Mono运行时
- 初始化Mono运行时
- C/C++ 和C#/CIL的交互
假设我们要实现Unity中的组件系统,在C#中定义Component类,C#端中主要目的是为游戏脚本提供相应接口,而不是具体逻辑的实现。我们在C/C++中实现具体逻辑,再以该代码中创建的实例为样本,调用Mono提供的方法在托管环境中创建相同的类型实例。
我们可以看出,虽然引擎底层是由C/C++实现的,但是他通过Mono提供了一套C#的接口作为其脚本语言,方便我们快速开发游戏
UNITY如何跨平台
原理就是CIL!
由于CIL的存在,不同平台的代码编译只需要两个步骤:从代码本身到CIL,从CIL到本地指令的即时编译
这样我们就不用根据不同的平台部署不同内容
什么是CIL
CIL(Common Intermediate Language)是指令集。
CIL主要有以下特点:
- CIL基于堆栈而非CPU
- 面向对象
- 以一个“.”开头,可读性较低
CIL其实没有在本地运行,他是在运行在虚拟机中的,具体到Unity中就是Mono运行时,运行在本地的是被编译后的原生代码
Unity中的脚本语言
哈人!Unity除了可以使用C#之外,还可以使用Boo、UnityScript(和JavaScript的相同点就是后缀相同)
C#效率比UnityScript更快,因为UnityScript涉及频繁的拆箱装箱,但他们是同一个层级的语言(都需要一个CIL的过渡过程)。至于Boo已经在Unity5.0之后停止文档支持了
Unity的脚本编译
无论是哪种语言编写的源代码,最后都不能供CPU运行,需要先被翻译为本地代码(也就是二进制的机器语言)
脚本编译流程概览
Unity并非直接将游戏脚本编译为二进制脚本而是将他编译为新的.NET dll文件,再通过Mono内部的 JIT 编译器编译为二进制代码(IOS平台不行,这也是为何Unity平台不能给出热更新方案,IOS一般采用完全静态编译)
但是呢Unity的游戏脚本中经常会存在相互引用彼此定义的类型的情况,所以脚本编译将会按4个阶段的顺序进行,取决于他所在的文件夹,是的,也就是Asset,Plugins,Editor那些文件夹。
- 编译运行时的脚本:这些脚本位于Standard Asset,Plugins,Pro Standard Asset(存放专业版才有的功能)文件夹中,这些文件夹中的脚本肯定不会访问外部变量
- 编译Editor的脚本:位于Plugins/Editor,Standard Asset/Editor,Pro Standard Asset/Editor中,我们使用了UnityEditor命名空间的脚本都要放在上述文件夹中,比如我们想要拓展Unity编辑器使用的脚本都要放在上述文件夹中
- 所有不在Editor中的脚本:基本就是我们开发过程中创建的游戏逻辑脚本
- 剩余的脚本:不在特殊文件夹的Editor中的,而在其他Editor文件夹中的脚本(好拗口解密)
JIT即时编译
定义:一个程序在他运行时创建并且运行了全新的代码
编译器不仅会生成CIL代码,还会在托管模块中生成数据表集合,又叫metadata元数据。用来描述该模块定义了什么,引用了什么,所以进行JIT编译的时候就不需要额外的C++头文件的支持。
相较于传统的直接将脚本编译为原生代码,JIT可以跨平台,而且具备了对生成的原生代码进行性能优化的能力,虽然即时编译会影响运行时的效率,但Mono优化之后并不明显。
不同平台上的编译
Android
在打包成apk之前,首先需要一套Android开发环境,具体步骤为:
- 在Android Developer SDK界面下载最新的SDK,安装解压
- 将Android设备与计算机相连,识别成功后在Unity中设置Android SDK路径,第一次发布的时候需要提供Android SDK安装的根目录(在Preference中修改)
生成Android引用程序也分为两个主要步骤:生成apk和将该文件部署到Android设备上。我们点击Build and Run会执行两个步骤
IOS
需要使用AOT编译方式(Ahead-Of-Time提前编译),先将游戏脚本源码提前编译,这样运行时直接加载已经编译好的原生源码而不是即时编译。相比JIT主要优势是减少启动时间、节约内存、生成的原生源码性能可能更好