https://github.com/jacksondunstan/UnityNativeScripting
Unity Native Scripting
允许在本机代码中编写Unity脚本的库:C,C ++,汇编。
目的
该项目旨在为您提供C#的可行替代方案。使用C ++编写脚本并不适合每个项目的所有部分,但现在它是一个选项。
目标
- 使用C#编写脚本与C#一样简单
- 低性能开销
- 与任何Unity项目轻松集成
- 快速编译,构建和代码生成时间
- 不要失去Unity Technologies的支持
倾向于C ++而不是C#的原因
快速设备构建时间
更改一行C#代码需要您创建一个新的游戏版本。典型的Android构建时间往往至少为10分钟,因为IL2CPP必须运行,然后必须编译大量的C ++。
通过使用C ++,我们可以在大约1秒钟内将游戏编译为C ++插件,将插件交换到APK中,然后立即安装并运行游戏。这是一个巨大的生产力提升!
快速编译时间
C ++的编译速度比C#快得多。只有一个文件更改时的增量构建 - 最常见的构建 - 比C#快15倍。随着时间的推移,更快的编译会增加生产率。更快的迭代次数使得更容易保持编程的“流程”。
没有垃圾收集器
Unity的垃圾收集器是强制性的,并且存在很多问题。它很慢,在主线程上运行,一次收集所有垃圾,分割堆,从不收缩堆。因此,您的游戏将体验“框架故障”,最终您将耗尽内存并崩溃。
需要花费大量精力来解决GC问题,并且生成的代码难以维护和缓慢。这包括像对象池这样的技术,它基本上使内存管理手动。你还必须避免像int
托管类型这样的类型,比如在某些情况下object
不使用foreach
循环,以及各种其他陷阱。
C ++没有必需的垃圾收集器,并通过“智能指针”类型(如shared_ptr)提供可选的自动内存管理功能。它提供了Unity原始垃圾收集器的绝佳替代品。
虽然使用某些.NET API仍然会涉及垃圾创建,但问题仅包含在那些API中,而不是所有代码的普遍问题。
总控制
通过直接使用C ++,您可以完全控制CPU将执行的代码。使用C ++编译器生成最佳代码比使用C#编译器,IL2CPP以及最终使用C ++编译器更容易。切断中间人,您可以利用编译器内在函数或汇编来使用强大的CPU功能(如SIMD和硬件AES加密)直接编写机器代码,从而获得巨大的性能提升。
更多功能
C ++是一种比C#更大的语言,一些开发人员更愿意使用更多的工具。以下是一些差异:
- 它的模板系统比C#泛型更强大
- 通过生成代码,可以获得极大灵活性的宏
- 便宜的函数指针而不是重量级代表
- 无开销算法而不是LINQ
- 位字段可以轻松节省内存
- 指针和永不空引用,而不仅仅是托管引用
- 多得多。C ++很庞大。
没有IL2CPP令人惊讶
虽然IL2CPP已经将C#转换为C ++,但它会产生大量开销。如果您阅读生成的C ++,会有很多惊喜。例如,使用静态变量的任何函数都有开销,而每个类的开头都存储了额外的两个指针。对于各种功能也是如此sizeof()
,例如强制性空检查等。相反,你可以直接编写C ++而不需要解决IL2CPP问题。
行业标准语言
C ++是视频游戏以及许多其他领域的标准语言。通过使用C ++编程,您可以更轻松地将技能和代码传输到非Unity项目和从非Unity项目传输。例如,您可以使用与在虚幻引擎或Lumberyard引擎中使用的相同语言(C ++)来避免锁定。
UnityNativeScripting功能
- 代码生成器将任何C#API公开给C ++
- 支持Windows,macOS,Linux,iOS和Android(编辑器和独立)
- 适用于Unity 2017.x和5.x.
- 与其他C#脚本一起玩得很好 - 不需要使用100%C ++
- 面向对象的API就像在C#中一样
GameObject go;
Transform transform = go.GetTransform();
Vector3 position(1.0f, 2.0f, 3.0f);
transform.SetPosition(position);
- 热重新加载:在不重新启动游戏的情况下更改C ++
MonoBehaviour
用C ++ 处理消息
void MyScript::Start()
{
String message("MyScript has started");
Debug::Log(message);
}
- 依赖于平台的编译(例如
#if TARGET_OS_ANDROID
) - CMake构建系统设置任何IDE项目或命令行构建
代码生成器
该项目的核心是代码生成器。它生成称为“绑定”的C#和C ++代码,使C#API可用于C ++游戏代码。它支持多种语言功能:
- 类型
class
struct
enum
- 数组(单维和多维)
- 代表们(例如
Action
) decimal
- 输入内容
- 构造函数
- 方法
- 字段
- 性能(
get
和set
喜欢obj.x
) - 索引器(
get
和set
喜欢obj[x]
) - 活动(
add
和remove
代表) - 重载运算符
- 拳击和拆箱(例如铸造
int
,object
反之亦然)
- 功能特点
out
和ref
参数- 通用类型和方法
- 默认参数
- 跨语言功能
- 例外(C#到C ++和C ++到C#)
- 使用C ++类实现C#接口
- 使用C ++类从C#类派生
请注意,代码生成器尚不支持:
Array
,string
和object
方法(例如GetHashCode
)- 非空字符串默认参数和空非字符串默认参数
- 隐含
params
参数(又名“var args”)传递 - C#指针
- 嵌套类型
- 向下铸造
要配置代码生成器,请打开Unity/Assets/NativeScriptTypes.json
并注意现有示例。添加到此文件以将更多来自Unity,.NET或自定义DLL的C#API公开给您的C ++代码。
要运行代码生成器,请NativeScript > Generate Bindings
从Unity编辑器中选择。
性能
几乎所有项目都会通过减少垃圾收集,消除IL2CPP开销以及访问编译器内在函数和汇编来获得净性能。从C ++调用C#只会导致轻微的性能损失。在极少数情况下,几乎所有代码都是对.NET API的调用,那么您可能会遇到净性能损失。
项目结构
在C ++中编写脚本时,C#仅用作“绑定”层,因此Unity可以调用C ++函数,C ++函数可以调用Unity API。代码生成器用于根据项目的需要生成大多数这些绑定。
您的所有代码以及一些绑定都将存在于单个“本机”C ++插件中。当您更改C ++代码时,您将构建此插件,然后在编辑器或部署的构建中(例如,到Android设备)播放游戏。Unity不会有任何C#代码编译,除非您运行代码生成器,这是不常见的。
标准C#工作流程如下所示:
- 在像MonoDevelop这样的C#IDE中编辑C#代码
- 切换到Unity编辑器窗口
- 等待编译完成(慢,“真正的”游戏需要5秒以上)
- 运行游戏
使用C ++,工作流程如下所示:
- 在Xcode或Visual Studio等C ++ IDE中编辑C ++代码
- 构建C ++插件(非常快,通常不到1秒)
- 切换到Unity编辑器窗口。无需编译。
- 运行游戏
入门
- 下载或克隆此回购
- 将
Unity/Assets
目录中的所有内容复制到Unity项目的Assets
目录中 - 编辑
NativeScriptTypes.json
并指定要从C ++访问的Unity,.NET和自定义DLL API的哪些部分。 - 编辑
Unity/Assets/CppSource/Game/Game.cpp
并Unity/Assets/CppSource/Game/Game.h
创建游戏。提供了一些示例代码,但可以随意删除它。随着游戏的增长,您可以在此处添加更多C ++ source(.cpp
)和header(.h
)文件。
构建C ++插件
iOS版
- 安装CMake 3.6或更高版本
- 为构建文件创建目录。无处不在。
- 打开终端应用程序
/Applications/Utilities
- 执行
cd /path/to/your/build/directory
- 执行
cmake -G MyGenerator -DCMAKE_TOOLCHAIN_FILE=/path/to/your/project/CppSource/iOS.cmake /path/to/your/project/CppSource
。替换MyGenerator
为您选择的发电机。要查看选项,请执行cmake --help
并查看底部的列表。常见的选择包括从命令行构建的“Unix Makefiles”或使用Apple的IDE的“Xcode”。 - 现在,在构建目录中生成构建脚本或IDE项目文件
- 适合您的发电机构建。例如,
make
如果您选择Unix Makefiles
作为生成器执行或打开,则执行,如果选择Xcode则NativeScript.xcodeproj
单击Product > Build
。
macOS(编辑和独立)
- 安装CMake 3.6或更高版本
- 为构建文件创建目录。无处不在。
- 打开终端应用程序
/Applications/Utilities
- 执行
cd /path/to/your/build/directory
- 执行
cmake -G "MyGenerator" -DEDITOR=TRUE /path/to/your/project/CppSource
。替换MyGenerator
为您选择的发电机。要查看选项,请执行cmake --help
并查看底部的列表。常见的选择包括从命令行构建的“Unix Makefiles”或使用Apple的IDE的“Xcode”。删除-DEDITOR=TRUE
独立版本。 - 现在,在构建目录中生成构建脚本或IDE项目文件
- 适合您的发电机构建。例如,
make
如果您选择Unix Makefiles
作为生成器执行或打开,则执行,如果选择Xcode则NativeScript.xcodeproj
单击Product > Build
。
Windows(编辑器和独立)
- 安装CMake 3.6或更高版本
- 为构建文件创建目录。无处不在。
- 单击“开始”按钮,键入“命令提示符”,然后单击应用程序,打开命令提示符
- 执行
cd /path/to/your/build/directory
- 执行
cmake -G "Visual Studio VERSION YEAR Win64" -DEDITOR=TRUE /path/to/your/project/CppSource
。替换VERSION
并YEAR
使用您要使用的Visual Studio版本。要查看选项,请执行cmake --help
并查看底部的列表。例如,"Visual Studio 15 2017 Win64"
用于Visual Studio 2017.任何版本,包括社区,都可以正常工作。删除-DEDITOR=TRUE
独立版本。 - 现在,在构建目录中生成项目文件
- 打开
NativeScript.sln
并单击Build > Build Solution
。
Linux(编辑和独立)
- 安装CMake 3.6或更高版本
- 为构建文件创建目录。无处不在。
- 根据您的Linux发行版打开适合的终端
- 执行
cd /path/to/your/build/directory
- 执行
cmake -G "MyGenerator" -DEDITOR=TRUE /path/to/your/project/CppSource
。替换MyGenerator
为您选择的发电机。要查看选项,请执行cmake --help
并查看底部的列表。最常见的选择是从命令行构建“Unix Makefile”,但也有IDE选项。删除-DEDITOR=TRUE
独立版本。 - 现在,在构建目录中生成构建脚本或IDE项目文件
- 适合您的发电机构建。例如,
make
如果您选择Unix Makefiles
作为生成器,请执行。
Android的
- 安装CMake 3.6或更高版本
- 为构建文件创建目录。无处不在。
- 打开终端(macOS,Linux)或命令提示符(Windows)
- 执行
cd /path/to/your/build/directory
- 执行
cmake -G MyGenerator -DANDROID_NDK=/path/to/android/ndk /path/to/your/project/CppSource
。替换MyGenerator
为您选择的发电机。要查看选项,请执行cmake --help
并查看底部的列表。要为Android以外的任何平台构建,请省略该-DANDROID_NDK=/path/to/android/ndk
部分。 - 现在,在构建目录中生成构建脚本或IDE项目文件
- 适合您的发电机构建。例如,
make
如果您选择Unix Makefiles
作为生成器,请执行。
更新到新版本
要更新到此项目的新版本,请Assets/NativeScript
使用此项目的Unity/Assets/NativeScript
目录覆盖Unity项目的目录,然后重新运行代码生成器。
参考
文章由作者描述此项目的开发。