文章申明:本文来自JacksonDunstan的博客系列文章内容摘取和翻译,版权归其全部,附上原文的连接,你们能够有空阅读原文:C++ Scripting( in Unity)c++
1、C#和C++的通讯c#
前面个人文章写过c#/c/lua是如何交互的,经过将c#的函数和属性,注册到lua虚拟机中,能够实现经过c来互相交互。编辑器
而c#和c++的交互,也是很是相似的,c#能够直接的经过P/Invoke的方式来调用c++的函数,而C++调用C#的函数,C++的函数是被封装成DLL来放在Unity的工程文件中的Plugins中,则须要基于.NET来操做,利用Marshal.GetFunctionPointerForDelegate来获取函数的指针,而后传递到c++中进行操做。函数
2、编辑器下实现实时的编译和脚本更新ui
在Unity中,咱们能够在打开的Unity中,直接编译c#的文件,这样不须要每次都关闭工程再打开来执行编译,而C++因为经过DLL来调用,每次更新的C++都须要关闭工程,而后更新DLL,而后打开工程,这样的操做,对于编辑器下的开发是极其耗费的。this
对于上面提到的反复开关工程执行DLL的更新,能够利用[DllImport]的属性来实如今编辑器下的更新:lua
该属性是基于OS的,因此不会存在跨平台的问题。spa
3、示例代码展现翻译
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, 0); 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(1024); 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 = 0; } // DLLEXPORT void MonoBehaviourUpdate(int thisHandle) { if( numCreated < 10) { //获取函数handle,而后操做
int goHandle = GameObjectNew(); int transformHandle = GameObejctGetTransform(goHandle); float comp = 10.0f * (float)numCreated; Vector3 position = {comp, comp, comp}; TransformSetPosition(transformHandle, position); numCreated++; } } }
4、总结
C#和C++的相互交互,是基于.NET和P/Invoke,那么咱们能够同理退出c#和lua的操做,其实质就是对handle进行包装,而后进行相关的操做,这个在后续的文章中在研究,先写到这儿,祝你们五一快乐,我也回家过节去了,哈哈~