文章申明:本文来自JacksonDunstan的博客系列文章内容摘取和翻译,版权归其所有,附上原文的链接,大家可以有空阅读原文:C++ Scripting( in Unity)

一、C#和C++的通信

前面我的文章写过c#/c/lua是如何交互的,通过将c#的函数和属性,注册到lua虚拟机中,可以实现通过c来互相交互。

而c#和c++的交互,也是非常类似的,c#可以直接的通过P/Invoke的方式来调用c++的函数,而C++调用C#的函数,C++的函数是被封装成DLL来放在Unity的工程文件中的Plugins中,则需要基于.NET来操作,利用Marshal.GetFunctionPointerForDelegate来获取函数的指针,然后传递到c++中进行操作。

二、编辑器下实现实时的编译和脚本更新

在Unity中,我们可以在打开的Unity中,直接编译c#的文件,这样不需要每次都关闭工程再打开来执行编译,而C++由于通过DLL来调用,每次更新的C++都需要关闭工程,然后更新DLL,然后打开工程,这样的操作,对于编辑器下的开发是极其耗费的。

对于上面提到的反复开关工程执行DLL的更新,可以利用[DllImport]的属性来实现在编辑器下的更新:

该属性是基于OS的,所以不会存在跨平台的问题。

三、示例代码展示

show the code

c# code part:

using System;
using System.IO;
using System.Runtime.InteropServices;
using UnityEngine; class TestScript:MonoBehaviour
{
#if UNITY_EDITOR
// pointer handle to the C++ DLL
public IntPtr libarayHandle;
public delegate void InitDelegate(IntPtr gameObjectNew,
IntPtr gameObjectGetTransform, IntPtr transformSetPosition);
#endif
} #if UNITY_EDITOR_OSX || UNITY_EDITOR_LINUX
//OSX 和Linux下的导入
[DLLImport("__Internal")]
public static extern IntPtr dlopen(string path, int flag);
[DllImport("__Internal")]
public static extern IntPtr dlsym(IntPtr handle, string symbolName);
[DllImport("__Internal")]
public static extern int dlclose(IntPtr handle); public static IntPtr OpenLibrary(string path)
{
IntPtr handle = dlopen(path, );
if(handle == IntPtr.Zero)
{
throw new Exception("Couldn't open native library: "+ path);
}
return handle;
} public static void CloseLibrary(IntPtr libraryHandle)
{
dlclose(libraryHandle);
} public static T GetDelegate<T>(IntPtr libraryHandle, string functionName)
where T: class
{
IntPtr symbol = dlsym(libraryHandle, functionName);
if(symbol == IntPtr.Zero)
{
throw new Exception("Couldn't get function:" + functionName);
}
return Marshal.GetDelegateForFunctionPointer(symbol, typeof(T)) as T;
}
#elif UNITY_EDITOR_WIN
// win 编辑器下
[DllImport("kernel32")]
public static extern IntPtr LoadLibrary(string path); [DllImport("kernel32")]
public static extern IntPtr GetProcAddress(IntPtr libraryHandle,
string symbolName); [DllImport("kernel32)]
public static extern bool FreeLibrary(IntPtr libraryHandle); public static IntPtr OpenLibrary(string path)
{
IntPtr handle = LoadLibrary(path);
if(handle == IntPtr.Zero)
{
throw new Exception("Couldn't open native library: "+ path);
}
return handle;
} public static void CloseLibrary(IntPtr libraryHandle)
{
FreeLibrary(libraryHandle);
} public static T GetDelegate<T>(IntPtr libraryHandle, string functionName)
where T: class
{
IntPtr symbol = GetProcAddress(libraryHandle, functionName);
if(symbol == IntPtr.Zero)
{
throw new Exception("Couldn't get function:" + functionName);
}
return Marshal.GetDelegateForFunctionPointer(symbol, typeof(T)) as T;
}
#else
//本地加载
[DllImport("NativeScript")]
static extern void Init(IntPtr gameObjectNew,
IntPtr gameObjectGetTransform, IntPtr transformSetPosition); [DllImport("NativeScript")]
static extern void MonoBehaviourUpdate();
#endif delegate int GameObjectNewDelegate();
delegate int GameObjectGetTransformDelegate(int thisHandle);
delegate void TransformSetPositionDelegate(int thisHandle, Vector3 position); #if UNITY_EDITOR_OSX
const string LIB_PATH = "/NativeScript.bundle/Contents/MacOS/NativeScript";
#elif UNITY_EDITOR_LINUX
const string LIB_PATH = "/NativeScript.so";
#elif UNITY_EDITOR_WIN
const string LIB_PATH = "/NativeScript.dll";
#endif void Awake()
{
#if UNITY_EDITOR
//open the native library
libraryHandle = OpenLibrary(Application.dataPath + LIB_PATH);
InitDelegate Init = GetDelegate<InitDelegate>(libraryHandle, "Init");
MonoBehaviourUpdate = GetDelegate<MonoBehaviourUpdateDelegate>(
libraryHandle,"MonoBehaviourUpdate");
#endif //init the C++ Library
ObjectStore.Init();
Init(
Marshal.GetFunctionPointerForDelegate(new GameObjectNewDelegate(GameObjectNew)),
Marshal.GetFunctionPointerForDelegate(new GameObjectGetTransformDelegate(GameObjectGetTransform)),
Marshal.GetFunctionPointerForDelegate(new TransformSetPositionDelegate(TransformSetPosition))
); } void Update()
{
MonoBehaviourUpdate();
} void OnApplicationQuit()
{
#if UNITY_EDITOR
CloseLibrary(libraryHandle);
libraryHandle = IntPtr.Zero;
#endif
} //c# function for c++ call
static int GameObjectNew()
{
GameObject go = new GameObject();
return ObjectStore.Store(go);
} static int GameObjectGetTransform(int thisHandle)
{
GameObject go = (GameObject)ObjectStore.Get(thisHandle);
Transform transform = go.transform;
return ObjectStore.Store(transform);
} static void TransformSetPosition(int handle, Vector3 position)
{
Transform t =(Transform)ObjectStore.Get(handle);
t.position = position;
}
}

c++ code part:

#ifdef _WIN32
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT
#endif extern "C"
{
//C# VECTOR STRUCT
struct Vector3
{
float x;
float y;
float z;
}
//c# function for c++ to call
int(*GameObjectNew)();
int(*GameObjectGetTransform)(int thisHandle);
void(*TransformSetPosition)(int thisHandle, Vector3 position); //c++ functions for c# to call
int numCreated; DLLExport void Init(
int(*gameObjectNew)(),
int(*gameObjectGetTrasform)(int),
void(*transformSetPosition)(int, Vector3)
)
{
GameObjectNew = gameObjectNew;
GameObjectGetTransform = gameObjectGetTransform;
TransformSetPosition = trasformSetPosition; numCreated = ;
}
//
DLLEXPORT void MonoBehaviourUpdate(int thisHandle)
{
if( numCreated < )
{
//获取函数handle,然后操作
int goHandle = GameObjectNew();
int transformHandle = GameObejctGetTransform(goHandle);
float comp = 10.0f * (float)numCreated;
Vector3 position = {comp, comp, comp};
TransformSetPosition(transformHandle, position);
numCreated++;
}
}
}

四、总结

C#和C++的相互交互,是基于.NET和P/Invoke,那么我们可以同理退出c#和lua的操作,其实质就是对handle进行包装,然后进行相关的操作,这个在后续的文章中在研究,先写到这儿,祝大家五一快乐,我也回家过节去了,哈哈~

最新文章

  1. 使用block进行界面之间的反向传值
  2. LeetCode&mdash;&mdash;Single Number II(找出数组中只出现一次的数2)
  3. 运行两个以上tomcat的设置及内存设置
  4. ubuntu 远程开机
  5. JAVA生产者消费者的实现
  6. Studio for ASP.NET Wijmo:使用 C1Pager 对 DataList 控件分页
  7. Windows系统端口占用情况检查脚本
  8. jsonp实现原理详细介绍
  9. Filter Blue Light for Better Sleep(APP 推荐)
  10. SPL 全面剖析
  11. Windows上帝模式
  12. poj 1144 Network(割点)
  13. windows 下搭建 apache + php52 + postgreSQL7/8/9环境
  14. Redis性能调优:保存SNAPSHOT对性能的影响
  15. Laravel中使用Redis
  16. [Haskell] 为什么列表操作++很昂贵?
  17. 异常-----web.xml文件报错 Multiple annotations found at this line: - cvc-complex-type.2.4.b: The content of element &#39;welcome-file-list&#39; is not complete. One of &#39;{&quot;http://java.sun.c
  18. C语言数据类型作业
  19. 谈谈PCI的GXL
  20. 【C语言程序】输出前50个素数

热门文章

  1. eclipse+Maven插件报错:-Dmaven.multiModuleProjectDirectory system propery is not set. Check $M2_HOME environment variable and mvn script match.
  2. 查看eclipse ADT SDK JDK版本号
  3. 重启Apache报错
  4. JS中全等和相等操作符的区别和比较规则
  5. python 正则详解
  6. 04、NetCore2.0下Web应用之Startup源码解析
  7. bs4解析要获取被注掉的部分需先将注释符号去掉
  8. git的理论基础
  9. 单例模式详解及java常用类
  10. 学习React系列(六)——更新dom细节于原理