这篇文章主要介绍“怎么实现C#与lua相互调用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么实现C#与Lua相互调用”文章能帮助大家解决问题。一、编译Lua动态链接库1. 编译windows下使
这篇文章主要介绍“怎么实现C#与lua相互调用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么实现C#与Lua相互调用”文章能帮助大家解决问题。
使用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.mkAPP_PLATFORM = android-23APP_ABI := armeabi-v7a arm64-v8aAPP_STL := stlport_shared
# Android.mkLOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)MY_FILES_PATH := $(LOCAL_PATH)/srcMY_FILES_SUFFIX := %.cMY_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 := CSharpLuaLOCAL_LDLIBS += -ldlLOCAL_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);
返回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);}
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);}
在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);}
如需要将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#与Lua相互调用”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网精选频道,小编每天都会为大家更新不同的知识点。
--结束END--
本文标题: 怎么实现C#与Lua相互调用
本文链接: https://www.lsjlt.com/news/327372.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-04-28
2024-04-28
2024-04-28
2024-04-28
2024-04-28
2024-04-28
2024-04-28
2024-04-28
2024-04-28
2024-04-28
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0