【Cocos2dx】【二】fairyGUI lua 接入
【Cocos2dx】【二】fairyGUI lua 接入
或者看这篇官方推荐的博客:
FairyGUI在Cocos2d-x下的多平台接入和lua绑定
其中有两个步骤暂时不理解。
一.conversions.yaml
definitions:
# the names of the functions - we use this to generate the code and to register the functions in
# the javascript class
ifunction: "lua_${generator.prefix}_${class_name}_${func_name}"
sfunction: "lua_${generator.prefix}_${class_name}_${func_name}"
constructor: "lua_${generator.prefix}_${class_name}_constructor"
conversions:
# some times you want to use a special native type when converting from spidermonkey to native
# the most common case would be from JS-boolean to bool. Using "bool" will fail here since we
# pass the address to the conversion method, and a JSBool is defined as an integer in spidermonkey
native_types:
float: "double"
short: "int32_t"
"unsigned char": "uint16_t"
"char": "int32_t"
ns_map:
......
......
"fairy::": "fgui."
to_native:
# lua to native
int: "ok &= luaval_to_int32(tolua_S, ${arg_idx},(int *)&${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
"unsigned int": "ok &= luaval_to_uint32(tolua_S, ${arg_idx},&${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
"unsigned char": "ok &= luaval_to_uint16(tolua_S, ${arg_idx},&${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
short: "ok &= luaval_to_int32(tolua_S, ${arg_idx},&${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
"unsigned short": "ok &= luaval_to_ushort(tolua_S, ${arg_idx}, &${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
char: "ok &= luaval_to_int32(tolua_S, ${arg_idx},&${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
bool: "ok &= luaval_to_boolean(tolua_S, ${arg_idx},&${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
float: "ok &= luaval_to_number(tolua_S, ${arg_idx},&${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
double: "ok &= luaval_to_number(tolua_S, ${arg_idx},&${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
ssize_t: "ok &= luaval_to_ssize_t(tolua_S, ${arg_idx}, &${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
"long long": "ok &= luaval_to_long_long(tolua_S, ${arg_idx},&${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
"string": "ok &= luaval_to_std_string(tolua_S, ${arg_idx},&${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
"string_view": "ok &= luaval_to_std_string_view(tolua_S, ${arg_idx},&${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
"String*": "std::string ${out_value}_tmp; ok &= luaval_to_std_string(tolua_S, ${arg_idx}, &${out_value}_tmp, \"${lua_namespaced_class_name}:${func_name}\"); ${out_value} = ax::String::create(${out_value}_tmp)"
"char*": "std::string ${out_value}_tmp; ok &= luaval_to_std_string(tolua_S, ${arg_idx}, &${out_value}_tmp, \"${lua_namespaced_class_name}:${func_name}\"); ${out_value} = ${out_value}_tmp.c_str()"
"Point": "ok &= luaval_to_point(tolua_S, ${arg_idx}, &${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
......
......
......
object: "ok &= luaval_to_object<${arg.to_string($generator).replace(\"*\", \"\")}>(tolua_S, ${arg_idx}, \"${scriptname}\",&${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
from_native:
# native to lua
int: "tolua_pushnumber(tolua_S,(lua_Number)${in_value})"
"unsigned int": "tolua_pushnumber(tolua_S,(lua_Number)${in_value})"
"unsigned short": "tolua_pushnumber(tolua_S,(lua_Number)${in_value})"
"unsigned char": "tolua_pushnumber(tolua_S,(lua_Number)${in_value})"
short: "tolua_pushnumber(tolua_S,(lua_Number)${in_value})"
char: "tolua_pushnumber(tolua_S,(lua_Number)${in_value})"
"long long": "tolua_pushnumber(tolua_S,(lua_Number)${in_value})"
"string": "lua_pushlstring(tolua_S,${in_value}.c_str(),${in_value}.length())"
"string_view": "lua_pushlstring(tolua_S,${in_value}.data(),${in_value}.length())"
"__thread_id": "std_thread_id_to_luaval(tolua_S, ${in_value})"
"char*": "tolua_pushstring(tolua_S,(const char*)${in_value})"
"String*": "tolua_pushstring(tolua_S, ${in_value}->getCString())"
bool: "tolua_pushboolean(tolua_S,(bool)${in_value})"
float: "tolua_pushnumber(tolua_S,(lua_Number)${in_value})"
double: "tolua_pushnumber(tolua_S,(lua_Number)${in_value})"
long: "tolua_pushnumber(tolua_S,(lua_Number)${in_value})"
ssize_t: "tolua_pushnumber(tolua_S,(lua_Number)${in_value})"
"unsigned long": "tolua_pushnumber(tolua_S,(lua_Number)${in_value})"
"Point": "point_to_luaval(tolua_S, ${in_value})"
......
......
......
object: "object_to_luaval<${ntype.replace(\"*\", \"\").replace(\"const \", \"\")}>(tolua_S, \"${scriptname}\",(${ntype.replace(\"const \", \"\")})${in_value})"
1.什么是yaml?
查阅了以下,就是 xml 、json 这种东西。数据按照固定规则排布的数据文件。.yml 和 .yaml是它的文件后缀。
2.文件内容和什么是Margin?
没有在 conversions.yaml添加代码会报这个错误。而Margin指的是fairygui自带的Margin类。
那这行代码是啥意思呢?为什么不在 yaml 中填它的配置就会这样?先看看yaml各参数。
a.ns_map:
FairyGUIMacros.h
ns_map:
// C++ | lua
//错误的
"fairy::": "fgui."
//正确的
“fairygui::”:"fgui."
ns_map 是对应关系,左边是 fairygui C++ 里的命名空间,右边对应的是在lua中的命名空间。
-
左侧的是C++对应的命名空间,一定要填对,找到fairygui在C++使用的命名空间名称。填错会有这个报错。
Exception: The namespace (fairygui::UIConfig) conversion wasn’t set in ‘ns_map’ section of the conversions.yaml
-
右侧的是lua里的命名空间,记得也要填对。因为这里也会在生成中,匹配替换到代码里。
很纳闷,这里的 fgui. 不会和 .ini 里重复了吗?待测试。
b.to_native:
指的是Lua这边传出的数据,对应C++要如何处理。并且在生成的时候,会进行对应的匹配替换。
"Point": "ok &= luaval_to_point(tolua_S, ${arg_idx}, &${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
c.from_native:
反过来的,C++这边传出的类型,对应的是Lua这边的哪个类型,以及处理。并且在生成的时候,会进行对应的匹配替换。
"Point": "point_to_luaval(tolua_S, ${in_value})"
二.manual
1.LuaBasicConversion .cpp .hpp
和 conversions.yaml 有关。配置文件中,在 to_native 和 from_native 中填入了 fairygui::Margin 与 lua 交互时,应该如何传递数据。
比如自定义类 Point
"Point": "ok &= luaval_to_point(tolua_S, ${arg_idx}, &${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
LuaBasicConversion .cpp
/**
* Get a Vec2 object value from the given acceptable index of stack.
* At current, the Point is typedef of Vec2.
* @see luaval_to_vec2
*/
static inline bool luaval_to_point(lua_State* L, int lo, cc::Vec2* outValue, const char* funcName = "")
{
return luaval_to_vec2(L, lo, outValue);
}
bool luaval_to_vec2(lua_State* L, int lo, cc::Vec2* outValue, const char* funcName)
{
if (nullptr == L || nullptr == outValue)
return false;
bool ok = true;
tolua_Error tolua_err;
//是不是table
if (!tolua_istable(L, lo, 0, &tolua_err))
{
#if _COCOS_DEBUG >= 1
luaval_to_native_err(L, "#ferror:", &tolua_err, funcName);
#endif
ok = false;
}
// assertion: since we only have vec2, you should never passing rect as vec2 to native
const auto objlen = lua_objlen(L, lo);
assert(objlen != 4);
if (ok)
{
// x 压入栈中
lua_pushstring(L, "x");
// 获取 lo 深度的 table
lua_gettable(L, lo);
// 栈顶是否为nil
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_pushstring(L, "width");
lua_gettable(L, lo);
}
// 从栈中获取x值
outValue->x = lua_isnil(L, -1) ? 0.0f : (float)lua_tonumber(L, -1);
//清空栈
lua_pop(L, 1);
// 重复取x的步骤来获取y
lua_pushstring(L, "y");
lua_gettable(L, lo);
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_pushstring(L, "height");
lua_gettable(L, lo);
}
outValue->y = lua_isnil(L, -1) ? 0.0f : (float)lua_tonumber(L, -1);
lua_pop(L, 1);
}
return ok;
}
而 LuaBasicConversion 里写的就是这些转换的逻辑代码(luaval_to_point等)。
一般int,float这种是不需要咱们写的,只需要写出来一些自己定义的,需要特殊逻辑处理的类型即可。
2.fairygui::Margin —> LuaBasicConversion
如上面的代码,就得自己写一个luaval_to_margin了。当然,可以咱们自己练练手,也可以直接拿其他人写好的。因为fairygui很多项目和demo以及cocos的社区版都实现过,咱们直接拿来对比拷贝以下就可以了。
Cocos2d-Lua-Community - Cocos2dx社区版
= = 额,社区版的竟然没写在 LuaBasicConversion 里,而是直接写在了manual里,牛的。
流程没问题,能对的上就行。
3.lua_xxx_manual.cpp .hpp
根据个人观察, lua_xxx_manual 基本都是放一些拓展和总入口用的。
拿社区般的 spine manual 来看看,总共有这些代码文件。
lua_cocos2dx_spine_manual.cpp
注册,LuaStack调用的
// c++注册lua
int register_spine_module(lua_State* L)
{
lua_getglobal(L, "_G");
if (lua_istable(L,-1))//stack:...,_G,
{
// auto里。
// 注册auto生成的
register_all_cocos2dx_spine(L);
// 同个文件,没贴出来。
// 注册manual需要的
register_spine_manual(L);
//下面哪个 lua_spSkeletonData.cpp 里。
// 注册它需要的
register_spSkeletonData_manual(L);
}
lua_pop(L, 1);
return 1;
}
manaul样例
static int lua_cocos2dx_spine_SkeletonAnimation_createWithData(lua_State* L)
{
if (nullptr == L)
return 0 ;
int argc = 0;
#if COCOS2D_DEBUG >= 1
tolua_Error tolua_err;
if (!tolua_isusertable(L,1,"sp.SkeletonAnimation",0,&tolua_err)) goto tolua_lerror;
#endif
argc = lua_gettop(L) - 1;
if (1 == argc)
{
#if COCOS2D_DEBUG >= 1
if (!tolua_isusertype(L,2,"sp.SkeletonData",0,&tolua_err)) goto tolua_lerror;
#endif
lua_spSkeletonData *luaSpData = static_cast<lua_spSkeletonData *>(tolua_tousertype(L,2,0));
auto tolua_ret = LuaSkeletonAnimation::createWithData(luaSpData->data, false);
int nID = (tolua_ret) ? (int)tolua_ret->_ID : -1;
int* pLuaID = (tolua_ret) ? &tolua_ret->_luaID : NULL;
toluafix_pushusertype_ccobject(L, nID, pLuaID, (void*)tolua_ret,"sp.SkeletonAnimation");
return 1;
}
luaL_error(L, "'createWithData' function of SkeletonAnimation has wrong number of arguments: %d, was expecting %d\n", argc, 1);
#if COCOS2D_DEBUG >= 1
tolua_lerror:
tolua_error(L,"#ferror in function 'createWithData'.",&tolua_err);
#endif
return 0;
}
-----------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------
static int lua_cocos2dx_spine_SkeletonAnimation_createWithJsonFile(lua_State* L)
{
if (nullptr == L)
return 0 ;
int argc = 0;
#if COCOS2D_DEBUG >= 1
tolua_Error tolua_err;
if (!tolua_isusertable(L,1,"sp.SkeletonAnimation",0,&tolua_err)) goto tolua_lerror;
#endif
argc = lua_gettop(L) - 1;
if (2 == argc)
{
#if COCOS2D_DEBUG >= 1
if (!tolua_isstring(L, 2, 0, &tolua_err) ||
!tolua_isstring(L, 3 ,0, &tolua_err))
{
goto tolua_lerror;
}
#endif
const char* skeletonDataFile = tolua_tostring(L, 2, "");
const char* atlasFile = tolua_tostring(L, 3, "");;
auto tolua_ret = LuaSkeletonAnimation::createWithJsonFile(skeletonDataFile, atlasFile);
int nID = (tolua_ret) ? (int)tolua_ret->_ID : -1;
int* pLuaID = (tolua_ret) ? &tolua_ret->_luaID : NULL;
toluafix_pushusertype_ccobject(L, nID, pLuaID, (void*)tolua_ret,"sp.SkeletonAnimation");
return 1;
} else if (3 == argc)
{
#if COCOS2D_DEBUG >= 1
if (!tolua_isstring(L, 2, 0, &tolua_err) ||
!tolua_isstring(L, 3 ,0, &tolua_err) ||
!tolua_isnumber(L, 4 ,0, &tolua_err))
{
goto tolua_lerror;
}
#endif
const char* skeletonDataFile = tolua_tostring(L, 2, "");
const char* atlasFile = tolua_tostring(L, 3, "");
LUA_NUMBER scale = tolua_tonumber(L, 4, 1);
auto tolua_ret = LuaSkeletonAnimation::createWithJsonFile(skeletonDataFile, atlasFile, scale);
int nID = (tolua_ret) ? (int)tolua_ret->_ID : -1;
int* pLuaID = (tolua_ret) ? &tolua_ret->_luaID : NULL;
toluafix_pushusertype_ccobject(L, nID, pLuaID, (void*)tolua_ret,"sp.SkeletonAnimation");
return 1;
}
luaL_error(L, "'createWithJsonFile' function of SkeletonAnimation has wrong number of arguments: %d, was expecting %d\n", argc, 2);
#if COCOS2D_DEBUG >= 1
tolua_lerror:
tolua_error(L,"#ferror in function 'createWithJsonFile'.",&tolua_err);
#endif
return 0;
}
比如这两个
-
lua_cocos2dx_spine_SkeletonAnimation_createWithData
没太懂为啥要自己写
-
lua_cocos2dx_spine_SkeletonAnimation_createWithJsonFile
这个就简单了,根据不同参数调用不同生成方法而已
其他的功用就请自行去看了,我也没有很深的了解了。