Cocos2d-x手动绑定C++类到Lua

前端之家收集整理的这篇文章主要介绍了Cocos2d-x手动绑定C++类到Lua前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

Cocos2d-x手动绑定C++类到Lua

文章目录@H_301_8@

作者:glory 首发泰然,转发请注明出处。

Cocos2d-x 3.0开始,Lua Binding使用tolua++方式自动绑定底层C++类到Lua层,使用户能够用Lua方式调用引擎各种接口。但是用户还是希望手动绑定某些自定义类,所以接下来的内容将一步一步讲解如何手动将自定义C++类绑定到Lua。

创建自定义

首先,定义一个类Foo,这个类就是接下来要绑定到Lua的类。

注意:所有C++类文件必须放在 Classes 文件夹里,所有Lua文件必须放在 Resources 文件夹里。

fun.h文件添加如下代码

#include@H_301_8@ @H_301_8@<iostream>@H_301_8@
@H_301_8@#include@H_301_8@ @H_301_8@<sstream>@H_301_8@
@H_301_8@class@H_301_8@ @H_301_8@Foo@H_301_8@
@H_301_8@{@H_301_8@
@H_301_8@public@H_301_8@:@H_301_8@
    @H_301_8@Foo@H_301_8@(@H_301_8@const@H_301_8@ std@H_301_8@::@H_301_8@string@H_301_8@ @H_301_8@&@H_301_8@ name@H_301_8@)@H_301_8@ @H_301_8@:@H_301_8@ name@H_301_8@(@H_301_8@name@H_301_8@)@H_301_8@
    @H_301_8@{@H_301_8@
        std@H_301_8@::@H_301_8@cout @H_301_8@<<@H_301_8@ @H_301_8@"Foo is born"@H_301_8@ @H_301_8@<<@H_301_8@ std@H_301_8@::@H_301_8@endl@H_301_8@;@H_301_8@
    @H_301_8@}@H_301_8@
    
    std@H_301_8@::@H_301_8@string@H_301_8@ @H_301_8@Add@H_301_8@(@H_301_8@int@H_301_8@ a@H_301_8@,@H_301_8@ @H_301_8@int@H_301_8@ b@H_301_8@)@H_301_8@
    @H_301_8@{@H_301_8@
        std@H_301_8@::@H_301_8@stringstream ss@H_301_8@;@H_301_8@
        ss @H_301_8@<<@H_301_8@ name @H_301_8@<<@H_301_8@ @H_301_8@": "@H_301_8@ @H_301_8@<<@H_301_8@ a @H_301_8@<<@H_301_8@ @H_301_8@" + "@H_301_8@ @H_301_8@<<@H_301_8@ b @H_301_8@<<@H_301_8@ @H_301_8@" = "@H_301_8@ @H_301_8@<<@H_301_8@ @H_301_8@(@H_301_8@a@H_301_8@+@H_301_8@b@H_301_8@);@H_301_8@
        @H_301_8@return@H_301_8@ ss@H_301_8@.@H_301_8@str@H_301_8@();@H_301_8@
    @H_301_8@}@H_301_8@
    
    @H_301_8@~@H_301_8@Foo@H_301_8@()@H_301_8@
    @H_301_8@{@H_301_8@
        std@H_301_8@::@H_301_8@cout @H_301_8@<<@H_301_8@ @H_301_8@"Foo is gone"@H_301_8@ @H_301_8@<<@H_301_8@ std@H_301_8@::@H_301_8@endl@H_301_8@;@H_301_8@
    @H_301_8@}@H_301_8@
    
@H_301_8@private@H_301_8@:@H_301_8@
    std@H_301_8@::@H_301_8@string@H_301_8@ name@H_301_8@;@H_301_8@
@H_301_8@};@H_301_8@

这个类有三个函数,构造函数、Add函数和析构函数。作用是输出不同字符串,以判断各函数是否被调用

绑定自定义类到Lua

开始前,先了解下绑定C++类的一些基本原理。

首先创建一个userdata来存放C++类对象指针,然后给userdata添加元表,用index元方法映射C++类中的对象方法

userdata

Lua中userdata为自定义类型,即用户自定义C++类类型,非Lua基本类型。绑定过程中用来存放C++类对象指针,从而将C++类映射到Lua中。

元表(Metatable)

带有索引的集合的表,绑定过程中用来存放和映射C++类中的对象和对象方法

__index

元表索引,指向用来存放userdata的元表。用来索引已创建的元表栈中的C++类名以及类方法名。

接下来完成实现部分,在 fun.cpp添加如下代码

#include@H_301_8@ @H_301_8@"fun.h"@H_301_8@

@H_301_8@extern@H_301_8@ @H_301_8@"C"@H_301_8@
@H_301_8@{@H_301_8@
@H_301_8@#include@H_301_8@ @H_301_8@<lua.h>@H_301_8@
@H_301_8@#include@H_301_8@ @H_301_8@<lauxlib.h>@H_301_8@
@H_301_8@#include@H_301_8@ @H_301_8@<lualib.h>@H_301_8@
@H_301_8@}@H_301_8@

@H_301_8@// 1.@H_301_8@
@H_301_8@int@H_301_8@ l_Foo_constructor@H_301_8@(@H_301_8@lua_State @H_301_8@*@H_301_8@ l@H_301_8@)@H_301_8@
@H_301_8@{@H_301_8@
    @H_301_8@const@H_301_8@ @H_301_8@char@H_301_8@ @H_301_8@*@H_301_8@ name @H_301_8@=@H_301_8@ luaL_checkstring@H_301_8@(@H_301_8@l@H_301_8@,@H_301_8@ @H_301_8@1@H_301_8@);@H_301_8@
 
    @H_301_8@Foo@H_301_8@ @H_301_8@**@H_301_8@ udata @H_301_8@=@H_301_8@ @H_301_8@(@H_301_8@Foo@H_301_8@ @H_301_8@**)@H_301_8@lua_newuserdata@H_301_8@(@H_301_8@l@H_301_8@,@H_301_8@ @H_301_8@sizeof@H_301_8@(@H_301_8@Foo@H_301_8@ @H_301_8@*));@H_301_8@
    
    @H_301_8@*@H_301_8@udata @H_301_8@=@H_301_8@ @H_301_8@new@H_301_8@ @H_301_8@Foo@H_301_8@(@H_301_8@name@H_301_8@);@H_301_8@
    
    @H_301_8@return@H_301_8@ @H_301_8@1@H_301_8@;@H_301_8@
@H_301_8@}@H_301_8@

@H_301_8@// 2.@H_301_8@
@H_301_8@Foo@H_301_8@ @H_301_8@*@H_301_8@ l_CheckFoo@H_301_8@(@H_301_8@lua_State @H_301_8@*@H_301_8@ l@H_301_8@,@H_301_8@ @H_301_8@int@H_301_8@ n@H_301_8@)@H_301_8@
@H_301_8@{@H_301_8@
    @H_301_8@return@H_301_8@ @H_301_8@*(@H_301_8@Foo@H_301_8@ @H_301_8@**)@H_301_8@luaL_checkudata@H_301_8@(@H_301_8@l@H_301_8@,@H_301_8@ n@H_301_8@,@H_301_8@ @H_301_8@"luaL_Foo"@H_301_8@);@H_301_8@
@H_301_8@}@H_301_8@

@H_301_8@// 3.@H_301_8@
@H_301_8@int@H_301_8@ l_Foo_add@H_301_8@(@H_301_8@lua_State @H_301_8@*@H_301_8@ l@H_301_8@)@H_301_8@
@H_301_8@{@H_301_8@
    @H_301_8@Foo@H_301_8@ @H_301_8@*@H_301_8@ foo @H_301_8@=@H_301_8@ l_CheckFoo@H_301_8@(@H_301_8@l@H_301_8@,@H_301_8@ @H_301_8@1@H_301_8@);@H_301_8@
    
    @H_301_8@int@H_301_8@ a @H_301_8@=@H_301_8@ luaL_checknumber@H_301_8@(@H_301_8@l@H_301_8@,@H_301_8@ @H_301_8@2@H_301_8@);@H_301_8@
    @H_301_8@int@H_301_8@ b @H_301_8@=@H_301_8@ luaL_checknumber@H_301_8@(@H_301_8@l@H_301_8@,@H_301_8@ @H_301_8@3@H_301_8@);@H_301_8@
    
    std@H_301_8@::@H_301_8@string@H_301_8@ s @H_301_8@=@H_301_8@ foo@H_301_8@->@H_301_8@Add@H_301_8@(@H_301_8@a@H_301_8@,@H_301_8@ b@H_301_8@);@H_301_8@
    lua_pushstring@H_301_8@(@H_301_8@l@H_301_8@,@H_301_8@ s@H_301_8@.@H_301_8@c_str@H_301_8@());@H_301_8@
    
    @H_301_8@return@H_301_8@ @H_301_8@1@H_301_8@;@H_301_8@
@H_301_8@}@H_301_8@

@H_301_8@// 4.@H_301_8@
@H_301_8@int@H_301_8@ l_Foo_destructor@H_301_8@(@H_301_8@lua_State @H_301_8@*@H_301_8@ l@H_301_8@)@H_301_8@
@H_301_8@{@H_301_8@
    @H_301_8@Foo@H_301_8@ @H_301_8@*@H_301_8@ foo @H_301_8@=@H_301_8@ l_CheckFoo@H_301_8@(@H_301_8@l@H_301_8@,@H_301_8@ @H_301_8@1@H_301_8@);@H_301_8@
    
    @H_301_8@delete@H_301_8@ foo@H_301_8@;@H_301_8@
    
    @H_301_8@return@H_301_8@ @H_301_8@0@H_301_8@;@H_301_8@
@H_301_8@}@H_301_8@

@H_301_8@// 5.@H_301_8@
@H_301_8@void@H_301_8@ @H_301_8@RegisterFoo@H_301_8@(@H_301_8@lua_State @H_301_8@*@H_301_8@ l@H_301_8@)@H_301_8@
@H_301_8@{@H_301_8@
    luaL_Reg sFooRegs@H_301_8@[]@H_301_8@ @H_301_8@=@H_301_8@
    @H_301_8@{@H_301_8@
        @H_301_8@{@H_301_8@ @H_301_8@"new"@H_301_8@,@H_301_8@ l_Foo_constructor @H_301_8@},@H_301_8@
        @H_301_8@{@H_301_8@ @H_301_8@"add"@H_301_8@,@H_301_8@ l_Foo_add @H_301_8@},@H_301_8@
        @H_301_8@{@H_301_8@ @H_301_8@"__gc"@H_301_8@,@H_301_8@ l_Foo_destructor @H_301_8@},@H_301_8@
        @H_301_8@{@H_301_8@ NULL@H_301_8@,@H_301_8@ NULL @H_301_8@}@H_301_8@
    @H_301_8@};@H_301_8@
    
    luaL_newMetatable@H_301_8@(@H_301_8@l@H_301_8@,@H_301_8@ @H_301_8@"luaL_Foo"@H_301_8@);@H_301_8@
    
    luaL_register@H_301_8@(@H_301_8@l@H_301_8@,@H_301_8@ NULL@H_301_8@,@H_301_8@ sFooRegs@H_301_8@);@H_301_8@
   
    lua_setfield@H_301_8@(@H_301_8@l@H_301_8@,@H_301_8@ @H_301_8@-@H_301_8@1@H_301_8@,@H_301_8@ @H_301_8@"__index"@H_301_8@);@H_301_8@
    
    lua_setglobal@H_301_8@(@H_301_8@l@H_301_8@,@H_301_8@ @H_301_8@"Foo"@H_301_8@);@H_301_8@
@H_301_8@}@H_301_8@

代码详解:

1. C++绑定到Lua的构造函数luaL_checkstring用来检查构造函数的形参是否为string类型并返回这个string。利用lua_newuserdata创建一个userdata来存放Foo类对象指针。luaL_getMetatable将与名为luaL_Foo相关联的元表推入栈中。此时,Lua栈中的内容如下:

3@H_301_8@|@H_301_8@ Metatable @H_301_8@"luaL_foo"@H_301_8@   @H_301_8@|-@H_301_8@1@H_301_8@
@H_301_8@2@H_301_8@|@H_301_8@ userdata               @H_301_8@|-@H_301_8@2@H_301_8@
@H_301_8@1@H_301_8@|@H_301_8@ @H_301_8@string@H_301_8@ parameter       @H_301_8@|-@H_301_8@3@H_301_8@

lua_setMetatable 将位于Lua栈中-2位置的 userdata 添加到元表 luaL_foo 中。最后,返回值1使得Lua可以得到userdata,之后栈将会被清空。

2. luaL_checkudata 用来检测形参是否为 luaL_Foo 元表中的userdata,并返回这个userdata。

3. 此函数是将C++类中的Add()函数映射到Lua中, lua_pushstring 将字符串压入栈中,返回值1使得字符串返回给Lua调用函数

4. 此函数是将C++类中的析构函数映射到Lua中。

5. 此函数注册C++类到Lua和注册所有已绑定的C++函数到Lua。 sFooRegs 给每个已绑定的C++函数一个能被Lua访问的名字。 luaL_newMetatable 创建一个名为luaL_Foo的元表并压入栈定, luaL_register 将 sFooRegs 添加到luaL_Foo中。 lua_pushvalue 将luaL_Foo元表中元素的拷贝压入栈中。 lua_setfield 将luaL_Foo元表的index域设为 __index lua_setglobal 将元表luaL_Foo重命名为Foo并将它设为Lua的全局变量,这样Lua可以通过识别Foo来访问元表luaL_Foo,并使Lua脚本能够覆盖元表Foo,即覆盖C++函数。如此一来,用户可以用Lua代码自定功能,覆盖掉C++类中函数功能,极大地提高了代码灵活性。

现在添加绑定函数函数声明至 fun.h 中:

int@H_301_8@ l_Foo_constructor@H_301_8@(@H_301_8@lua_State @H_301_8@*@H_301_8@ l@H_301_8@);@H_301_8@

@H_301_8@Foo@H_301_8@ @H_301_8@*@H_301_8@ l_CheckFoo@H_301_8@(@H_301_8@lua_State @H_301_8@*@H_301_8@ l@H_301_8@,@H_301_8@ @H_301_8@int@H_301_8@ n@H_301_8@);@H_301_8@

@H_301_8@int@H_301_8@ l_Foo_add@H_301_8@(@H_301_8@lua_State @H_301_8@*@H_301_8@ l@H_301_8@);@H_301_8@

@H_301_8@int@H_301_8@ l_Foo_destructor@H_301_8@(@H_301_8@lua_State @H_301_8@*@H_301_8@ l@H_301_8@);@H_301_8@

@H_301_8@void@H_301_8@ @H_301_8@RegisterFoo@H_301_8@(@H_301_8@lua_State @H_301_8@*@H_301_8@ l@H_301_8@);@H_301_8@

Lua测试代码

添加如下代码fun.lua

function@H_301_8@ @H_301_8@Foo@H_301_8@:@H_301_8@speak@H_301_8@()@H_301_8@
    @H_301_8@print@H_301_8@(@H_301_8@"Hello,I am a Foo"@H_301_8@)@H_301_8@
@H_301_8@end@H_301_8@
 
@H_301_8@local@H_301_8@ foo @H_301_8@=@H_301_8@ @H_301_8@Foo@H_301_8@.@H_301_8@new@H_301_8@(@H_301_8@"fred"@H_301_8@)@H_301_8@
@H_301_8@local@H_301_8@ m @H_301_8@=@H_301_8@ foo@H_301_8@:@H_301_8@add@H_301_8@(@H_301_8@3@H_301_8@,@H_301_8@ @H_301_8@4@H_301_8@)@H_301_8@
 
@H_301_8@print@H_301_8@(@H_301_8@m@H_301_8@)@H_301_8@
 
foo@H_301_8@:@H_301_8@speak@H_301_8@()@H_301_8@
 
@H_301_8@Foo@H_301_8@.@H_301_8@add_ @H_301_8@=@H_301_8@ @H_301_8@Foo@H_301_8@.@H_301_8@add
@H_301_8@// 1.@H_301_8@
@H_301_8@function@H_301_8@ @H_301_8@Foo@H_301_8@:@H_301_8@add@H_301_8@(@H_301_8@a@H_301_8@,@H_301_8@ b@H_301_8@)@H_301_8@
    @H_301_8@return@H_301_8@ @H_301_8@"here comes the magic: "@H_301_8@ @H_301_8@..@H_301_8@ @H_301_8@self@H_301_8@:@H_301_8@add_@H_301_8@(@H_301_8@a@H_301_8@,@H_301_8@ b@H_301_8@)@H_301_8@
@H_301_8@end@H_301_8@
 
m @H_301_8@=@H_301_8@ foo@H_301_8@:@H_301_8@add@H_301_8@(@H_301_8@9@H_301_8@,@H_301_8@ @H_301_8@8@H_301_8@)@H_301_8@
 
@H_301_8@print@H_301_8@(@H_301_8@m@H_301_8@)@H_301_8@

1. 同名函数覆盖绑定的C++函数,提高扩展性。

绑定检测

#include “fun.h” 添加AppDelegate.cpp 中,并在 AppDelegate.cpp 中的 applicationDidFinishLaunching 函数添加如下代码

// register lua engine@H_301_8@
    @H_301_8@auto@H_301_8@ engine @H_301_8@=@H_301_8@ @H_301_8@LuaEngine@H_301_8@::@H_301_8@getInstance@H_301_8@();@H_301_8@
    @H_301_8@ScriptEngineManager@H_301_8@::@H_301_8@getInstance@H_301_8@()->@H_301_8@setScriptEngine@H_301_8@(@H_301_8@engine@H_301_8@);@H_301_8@
    
    @H_301_8@// Adding code here...@H_301_8@
    @H_301_8@// register lua binding@H_301_8@
    
    @H_301_8@RegisterFoo@H_301_8@(@H_301_8@engine@H_301_8@->@H_301_8@getLuaStack@H_301_8@()->@H_301_8@getLuaState@H_301_8@());@H_301_8@
    
    std@H_301_8@::@H_301_8@string@H_301_8@ path @H_301_8@=@H_301_8@ @H_301_8@FileUtils@H_301_8@::@H_301_8@getInstance@H_301_8@()->@H_301_8@fullPathForFilename@H_301_8@(@H_301_8@"fun.lua"@H_301_8@);@H_301_8@
    engine@H_301_8@->@H_301_8@executeScriptFile@H_301_8@(@H_301_8@path@H_301_8@.@H_301_8@c_str@H_301_8@());@H_301_8@

注意: 因为Cocos2d-x Lua Binding目前不支持多个状态,所以在注册已绑定的C++类时,只能使用当前运行的状态。

运行程序,如果得到下面的输出结果证明已经绑定成功:

Foo@H_301_8@ @H_301_8@is@H_301_8@ born
cocos2d@H_301_8@:@H_301_8@ @H_301_8@[@H_301_8@LUA@H_301_8@-@H_301_8@print@H_301_8@]@H_301_8@ fred@H_301_8@:@H_301_8@ @H_301_8@3@H_301_8@ @H_301_8@+@H_301_8@ @H_301_8@4@H_301_8@ @H_301_8@=@H_301_8@ @H_301_8@7@H_301_8@
cocos2d@H_301_8@:@H_301_8@ @H_301_8@[@H_301_8@LUA@H_301_8@-@H_301_8@print@H_301_8@]@H_301_8@ @H_301_8@Hello@H_301_8@,@H_301_8@ I am a @H_301_8@Foo@H_301_8@
cocos2d@H_301_8@:@H_301_8@ @H_301_8@[@H_301_8@LUA@H_301_8@-@H_301_8@print@H_301_8@]@H_301_8@ here comes the magic@H_301_8@:@H_301_8@ fred@H_301_8@:@H_301_8@ @H_301_8@9@H_301_8@ @H_301_8@+@H_301_8@ @H_301_8@8@H_301_8@ @H_301_8@=@H_301_8@ @H_301_8@17@H_301_8@

Android环境测试:

如果希望在Android环境下调试,在执行 proj.android/build_native 脚本前,需要在 proj.android/jni/Android.mk 文件添加 fun.cpp 文件包含:

LOCAL_SRC_FILES @H_301_8@:=@H_301_8@ hellolua@H_301_8@/@H_301_8@main@H_301_8@.@H_301_8@cpp \
                   @H_301_8@../../@H_301_8@Classes@H_301_8@/@H_301_8@AppDelegate@H_301_8@.@H_301_8@cpp \
                   @H_301_8@../../@H_301_8@Classes@H_301_8@/@H_301_8@fun@H_301_8@.@H_301_8@cpp@H_301_8@

项目文件在此下载

猜你在找的Cocos2d-x相关文章