如何给Unity写一个原生的插件

发表于2017-11-13
评论0 4k浏览

Untiy可以导入其他语言编写(和编译)的代码;他们叫做原生插件,那下面就教大家如何去构建一个原生的插件,并将构建的步骤分享给大家:

· 步骤1:创建一个C++工程
· 步骤2:编写一个库
· 步骤3:编译
· 步骤4:导入Unity
· 步骤5:在Unity中使用
· 结论


源代码:

· Visual Studio 2015 C++ 工程(DLL源码)

· Unity包(包含DLL

Unity中托管和非托管插件

连接不同代码并不是Unity发明的。若你是Windows用户,你也许听说过DLL,动态链接库的缩写。与单机应用类似,他们是编译过的软件。不同的是,他们不能被直接执行,因为他们是专门设计要被其他应用使用的。

Unity支持两种插件:托管和非托管的。前者是代码用C#编写并编译为被称为通用中间语言(CIL)的字节码语言。托管插件与C#脚本一样强大,且带有编译过的源码。非托管(或原生)插件,是使用其他语言编写的软件,典型是C++。他们没有功能上并没有区别,因为他们都被编译为机器码,他们往往并传统的脚本要快。


步骤1:创建一个C++项目

本例子中,我使用的Visual Studio 2015;只要你知道怎么编译C++代码,你可以选择任何IDE。步骤1创建一个非托管C++库就是创建一个项目。打开Visual Studio,找到文件|新建工程,选择Visual C++ | Win32 控制台程序。 


在给项目命名后(本例中为TestDLL),确保选择应用类型下的DLL,附加选项下的空项目。


至此,Visual C++解决方案已经准备好,我们可以开始编写代码了。


步骤2:编写库

C++代码通常分为两个文件。函数定义(头文件)和函数实现(实现文件)。实现文件为.cpp文件,放在Resource文件内,头文件为同名.h放在Header文件内。对于本例中我们创建一个头文件和一个实现文件;实现文件将包含所有我们要保存到DLL的功能。你可以通过单击右键创建一个文件在相应的文件夹上,然后选择添加|新选项


实现:TestDLLSort.cpp

我们开始编码,给数组排序。

#include "TestDLLSort.h"
#include <algorithm>
extern "C" {
void TestSort(int a[], int length) {
std::sort(a, a+length);
}
}

头文件TestDLLSort.h57行使用了数序库里的数组排序函数std:sort。如果你对C++11熟悉,这不是啥新鲜东西。只增加了extern "C"块,它对导出TestSort的引用到DLL中是必须的。

实现定义,必须与头文件完全一致。它必须包含TestSort原型,它是函数实现的签名。

#define TESTDLLSORT_API __declspec(dllexport) 
extern "C" {
TESTDLLSORT_API void TestSort(int a[], int length);
}

其他代码对于创建DLL是必须的。TESTDLLSORT_API是任意的,用来标记所有的导出函数。在更复杂软件中,TESTDLLSORT_API应该根据需要绑定到 __declspec(dllimport) 上。但是在本例中,没有必要。

步骤3:编译

最后一步是在Visual Studio中编译我们的DLL。请确保设置正确的发布平台(32位或64位)。然后,选择,编译|编译解决方案。

 

 

在屏幕下方的控制台上会看到输出的日志。如下所示:

1>------ Rebuild All started: Project: TestDLL, Configuration: Release x64 ------
1>  TestDLLSort.cpp
1>     Creating library C:\Users\Alan Zucconi\Documents\Visual Studio 2015\Projects\TestDLL\x64\Release\TestDLL.lib and object C:\Users\Alan Zucconi\Documents\Visual Studio 2015\Projects\TestDLL\x64\Release\TestDLL.exp
1>  Generating code
1>  All 30 functions were compiled because no usable IPDB/IOBJ from previous compilation was found.
1>  Finished generating code
1>  TestDLL.vcxproj -> C:\Users\Alan Zucconi\Documents\Visual Studio 2015\Projects\TestDLL\x64\Release\TestDLL.dll
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

若你发现有警告,比如:warning C4273: inconsistent dlllinkage,这可能意味着对不确定使用__declspec(dllimport) 和 __declspec(dllexport)。若你准备为Unity创建原生的插件,就使用后者。


步骤4:导入到Unity

根据前面编译日志,到工程文件中找到编译好的DLL。本例中,它在文件夹x64\Release中。这是你需要的唯一文件。在Unity中工作的第一步是把它拷贝到一个叫做的Plugins文件夹中。

 

原生插件通常与操作系统或平台相关。你可以使用右侧的检视板来确保每个DLL被包含。


步骤5:在Unity中使用

导入后,使用DLL相对简单。第一步是使用DLLImport定义入口。你需要指定DLL名和函数名。它会提供别名与其他函数一样可被调用。

using UnityEngine;
using System.Runtime.InteropServices;
public class TestDLL : MonoBehaviour {
    // The imported function
    [DllImport("TestDLL", EntryPoint = "TestSort")]
    public static extern void TestSort(int [] a, int length);
    public int[] a;
    void Start() {
        TestSort(a, a.Length);
    }
}

你应该注意到Unity在编辑器中不能检测非托管DLL;你必要运行游戏来检测是否成功连接。对于托管的DLL,则可以静态检测。入口的字符串必须与C++库中的名字一样。但是,你可以使用如下方法调用函数;这个是以后C#怎么调用它的。


最后

原生插件非常重要,在游戏开发中扮演着重要角色。最大好处就是速度。C#脚本需要转换为CIL(通用中间语言),而非托管DLL被编译为机器码。你可以通过标记DLL创建自己测试。使用Array.Sort排序1000000 个元素大致需要480毫秒,而使用std::sort.只需要65毫秒。快7倍啊!若你游戏有一些重度仿真(比如:动态液体或重度AI)你应该考虑那部分用C++库来编码。


其它资源

· 针对Mac机的原生插件:在这里包含关于更多文章内容,但是只针对Mac开发者。

· Unity and DLLs:一个为Unity创建托管C#和非托管插件的教程

· Writing plugins:Unity官方提供关于使用Visual Studio创建你插件的视频教程。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引