转载请标明出处:http://www.cnblogs.com/zblade/c++
在实际的项目中,大部分业务逻辑 程序员只须要负责lua层编写逻辑便可,或者在c#层添加一些静态函数,供lua层调用。那么对于具体的相互之间的交互,又是如何进行的?本文就写一写我的的一些探究笔记吧。本文会写不少代码,我就用截图来展现吧,编辑写代码不大方便,有点蛋疼~程序员
1、c#函数的导出c#
我就从外部接口开始理一遍总体思路吧,想了一下,仍是从代码思路来解释比较容易。函数
首先咱们的工程中都会有一个slua的导出接口:lua
这样的一个接口,是用来将UnityEngine中的类导出的实现API,其总体的思路是:spa
1)首先加载UnityEngine这个程序集:3d
Assembly assembly = Assembly.Load("UnityEngine")
2)而后获取资中的可导出类型:code
Type[] types = assembly.GetExportedTypes();
3) 作一次过滤,主要是对于某些须要导出的类和不须要导出的类作一次过滤剔除和添加,这个不一样项目不同,不作展现;blog
4)将这些过滤后的类型,逐个作一次导出,好比相机类,能够导出为:接口
5)将这些导出的类Lua_xxx合并在一块儿做为一个Bind, 提供一个静态获取方法GetBindList()
这是第一步,完成对c#和unity中的方法导出,将每一个不一样程序集中的类中的方法和属性都暴露出来,作一个导出。
2、导出的c#文件的注册到Lua虚拟机中
这部分须要结合游戏的启动来理解,在游戏的启动时刻,咱们都会启动一个Lua的虚拟机,好比这样:
在启动虚拟机后,须要执行虚拟机的Init操做:
m_LuaSvr.init(xxxx)
在这个函数中,执行Bind的操做:doBind
其中的关键操做为collectBindInfo, 这个函数分为2部分:
1)获取当前程序集,以及程序集中设置为LuaBinderAttribute的类型:
2)根据获取的类型,逐个反射执行第一部分最后的GetBindList函数:
这样经过c#的反射,就能够动态的获取前面导出的全部LuaXXX类文件了,回到Bind操做,对于这些获取的Lua_XXX文件,执行Lua虚拟机的注册操做:
action(L)
也就是导出文件中的reg操做:
看看其操做,首先是newtable的操做:
建立2个table,分别用来作static和instance的填充,而后填充的操做addMember:
对于不一样的参数,会重载不一样的addMember操做,这儿就举例一个,pushValue就是将func注册到该table中:
LuaDll.lua_pushcclosure(L, function, 0)
就是将该函数填充到lua表中,能够经过key名的查找来获取该函数,从而执行相关的调用。
最后会在该reg操做中为该类建立一个metatable
回到最初的,不断的循环执行,就能够加载整个c#相关导出类到Lua虚拟机中
总结:到如今为止,能够知道整个c#函数在导出过程当中的操做,在启动时候如何经过程序集和反射来实现动态的加载,最后Lua的虚拟机中都会注册前面导出的类文件的相关函数和属性。
而咱们已经知道,lua文件在执行的时候,是会编译成字节码在lua的虚拟机中执行的,这样lua的字节码和c#的导出文件,都在同一个环境中执行,调用pcall就能够相互的执行和调用了。
写这篇文章是基于偶然翻看到老外写的一个在unity中用c++作脚原本编写游戏逻辑,而且实现了c#和c++之间的相互交互调用,因此我也翻看了一下c#是如何实现的,固然写的比较简陋,还有不少细节须要推敲,你们能够翻看本身的项目代码,留言讨论