<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本篇簡單介紹如何在C#中執行Lua指令碼,傳遞資料到Lua中使用,以及Lua中呼叫C#匯出的方法等。在Unity中開發測試,並打IL2CPP的Android包在模擬器上執行通過。Lua版本使用的是Lua5.1.5。
使用VS2015建立一個空的動態連結庫專案,刪除裡面預設建立的幾個檔案(如果想自定義拓展可用保留),然後把Lua的原始碼拷貝進來,新增到專案工程中,編譯宏需要設定LUA_BUILD_AS_DLL和_CRT_SECURE_NO_WARNINGS。然後就可以編譯x86和x64的DLL動態庫,整體步驟簡單易操作。
通過NDK編譯Android需要的so動態庫,因此需要手寫Application.mk和Android.mk兩個mk檔案,下面是我使用的兩個檔案的內容,建立放在上面VS的工程裡面即可,路徑是在lua原始碼src的上一層目錄。
# Application.mk APP_PLATFORM = android-23 APP_ABI := armeabi-v7a arm64-v8a APP_STL := stlport_shared
# Android.mk LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) MY_FILES_PATH := $(LOCAL_PATH)/src MY_FILES_SUFFIX := %.c MY_UN_INCLUDE := %lua.c %luac.c # 遞迴遍歷目錄下的所有的檔案 rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)) # 獲取相應的原始檔 MY_ALL_FILES := $(foreach src_path,$(MY_FILES_PATH), $(call rwildcard,$(src_path),*.*) ) MY_SRC_LIST := $(filter $(MY_FILES_SUFFIX),$(MY_ALL_FILES)) MY_SRC_LIST := $(filter-out $(MY_UN_INCLUDE),$(MY_SRC_LIST)) MY_SRC_LIST := $(MY_SRC_LIST:$(LOCAL_PATH)/%=%) LOCAL_SRC_FILES = $(MY_SRC_LIST) #列印編譯資訊 $(warning 'src_list='$(LOCAL_SRC_FILES)) LOCAL_MODULE := CSharpLua LOCAL_LDLIBS += -ldl LOCAL_CFLAGS := $(L_CFLGAS) include $(BUILD_SHARED_LIBRARY)
將上面的mk檔案放置完成後,開啟CMD命令列,執行ndk編譯。由於並不是在Android的jni專案目錄,因此執行命令會有所不同,可以使用下面的命令執行生成,等待ndk執行完成後就生成了需要的so庫。
ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk NDK_APPLICATION_MK=./Application.mk
在Unity專案Assets目錄裡面建立Plugins目錄,用於存放不同平臺的DLL庫。Windows需要的DLL存放的目錄為Assets/Plugins/x86和Assets/Plugins/x86_64;Android需要的SO檔案存放的目錄為Assets/Android/[libs/arm64-v8a]括號裡面的目錄其實就是上面NDK編譯後生成的路徑。
大部分的動態庫中的介面直接使用以下這種方式即可使用,使用IntPtr來表示lua_State*物件,傳入引數char*可用使用byte[]或者string,但是會有一點點區別。
[DllImport("CSharpLua", EntryPoint = "luaL_newstate")] public static extern IntPtr luaL_newstate(); [DllImport("CSharpLua", EntryPoint = "luaL_openlibs")] public static extern void luaL_openlibs(IntPtr L); [DllImport("CSharpLua", EntryPoint = "luaL_loadbuffer")] public static extern int luaL_loadbuffer(IntPtr L, byte[] buff, uint size, string name); [DllImport("CSharpLua", EntryPoint = "lua_call")] public static extern void lua_call(IntPtr L, int nargs, int nresults); [DllImport("CSharpLua", EntryPoint = "lua_pcall")] public static extern int lua_pcall(IntPtr L, int nargs, int nresults, int errfunc);
1. 返回char*時,不可直接使用string替換,否則呼叫會導致崩潰,因此需要像下面程式碼展示的那樣進行一下轉換才可以使用。
[DllImport("CSharpLua", EntryPoint = "lua_tolstring")] private static extern IntPtr _lua_tolstring(IntPtr L, int idx, ref uint size); public static string lua_tolstring(IntPtr L, int idx, ref uint size) { IntPtr buffer = _lua_tolstring(L, idx, ref size); return Marshal.PtrToStringAnsi(buffer); }
2. C#函數傳遞給Lua使用時,需要使用delegate委託型別。
public delegate int LuaFunction(IntPtr L); [DllImport("CSharpLua", EntryPoint = "lua_pushcclosure")] public static extern void lua_pushcclosure(IntPtr L, LuaFunction func, int idx); public static void lua_pushcfunction(IntPtr L, LuaFunction func) { lua_pushcclosure(L, func, 0); }
3. 在lua原始碼中定義的宏程式碼是無法使用的,會提示找不到,需要在C#中手動實現,例如下面展示的2個宏。
#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s)) #define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s))
[DllImport("CSharpLua", EntryPoint = "lua_getfield")] public static extern void lua_getfield(IntPtr L, int idx, string s); public static void lua_getglobal(IntPtr L, string s) { lua_getfield(L, LUA_GLOBALSINDEX, s); } [DllImport("CSharpLua", EntryPoint = "lua_setfield")] public static extern void lua_setfield(IntPtr L, int idx, string s); public static void lua_setglobal(IntPtr L, string s) { lua_setfield(L, LUA_GLOBALSINDEX, s); }
4. 如需要將C#的類範例物件即userdata傳遞給lua,需要在C#中轉換成IntPtr後傳遞,Lua返回的則需要通過IntPtr轉換回C#的範例物件。
[DllImport("CSharpLua", EntryPoint = "lua_pushlightuserdata")] public static extern void _lua_pushlightuserdata(IntPtr L, IntPtr p); public static void lua_pushlightuserdata<T>(IntPtr L, T p) { IntPtr obj = Marshal.GetIUnknownForObject(p); _lua_pushlightuserdata(L, obj); } [DllImport("CSharpLua", EntryPoint = "lua_touserdata")] public static extern IntPtr _lua_touserdata(IntPtr L, int idx); public static T lua_touserdata<T>(IntPtr L, int idx) { IntPtr p = _lua_touserdata(L, idx); return (T)Marshal.GetObjectForIUnknown(p); }
IntPtr L = LuaDll.luaL_newstate(); LuaDll.luaL_openlibs(L);
var data = Resources.Load<TextAsset>(lua_file); int rc = LuaDll.luaL_loadbuffer(L, data.bytes, (uint)data.bytes.Length, lua_file); rc = LuaDll.lua_pcall(L, 0, 0, 0) LuaDll.lua_getglobal(L, "main"); // 傳遞引數 LuaDll.lua_pushinteger(L, 3333); LuaDll.lua_pushnumber(L, 3.3); // 執行main方法 int i = LuaDll.lua_pcall(L, 2, 0, 0);
LuaDll.lua_pushcfunction(L, LuaPrint); LuaDll.lua_setglobal(L, "print"); [MonoPInvokeCallback] // 這個主要是在Android上需要。 static int LuaPrint(IntPtr L) { Debug.Log("....."); return 0; }
static int FindAndBind(IntPtr L) { GameObject go = LuaDll.lua_touserdata<GameObject>(L, 1); string path = LuaDll.lua_tostring(L, 2); // 這裡將lua的函數放到LUA_REGISTRYINDEX上 int idx = LuaDll.luaL_refEx(L); Transform t = go.transform.Find(path); Button btn = t.GetComponent<Button>(); btn.onClick.AddListener(delegate() { // 從LUA_REGISTRYINDEX棧獲取lua的函數進行執行。 LuaDll.lua_rawgeti(L, LuaDll.LUA_REGISTRYINDEX, idx); LuaDll.lua_pcall(L, 0, 0, 0); }); return 0; }
總體來說互動呼叫還是比較的簡單方便,跟使用C/C++與Lua互動差不多。我僅僅簡單使用Lua原始碼進行編譯動態庫使用,可以方便的替換各個版本的lua進行使用。C#匯出方法給Lua使用也相對簡單,但是Unity中使用Lua的時候,不可能每個類例如GameObject、Transform等都手動寫匯出的程式碼給Lua使用。這塊就可以去看tolua、xlua的實現,需要考慮很多東西。
到此這篇關於原生實現C#與Lua相互呼叫方法的文章就介紹到這了,更多相關C#與Lua相互呼叫內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45