我正在开发一个库以允许在 iOS 5.x 中编写游戏的 Lua (5.2) 脚本。我创建了一个类并添加了绑定以允许从 Lua 创建和访问它。从 Lua 调用的 C 初始化方法如下所示:
static int newGeminiObject(lua_State *L){
GeminiObject *go = [[GeminiObject alloc] initWithLuaState:L];
GeminiObject **lgo = (GeminiObject **)lua_newuserdata(L, sizeof(GeminiObject *));
*lgo = go;
luaL_getmetatable(L, GEMINI_OBJECT_LUA_KEY);
lua_setmetatable(L, -2);
lua_newtable(L);
lua_setuservalue(L, -2);
NSLog(@"New GeminiObject created");
// add this new object to the globall list of objects
[[Gemini shared].geminiObjects addObject:go];
return 1;
}
这分配了一个在其他地方设置的元表,以提供对各种方法的访问。此外,它附加一个表作为用户值,以允许脚本代码将属性分配给对象。
我可以毫无问题地在 Lua 脚本中创建这些对象:
require "gemini"
x = gemini.new()
x:addEventListener("touch", objectTouched)
这里 objectTouched 是在别处定义的处理触摸事件的 Lua 方法。这里addEventListener
将它绑定到touch
事件。
这些对象工作得很好。但是,当我尝试从 C 创建一个时,我遇到了问题。我可以创建对象,但尝试将其分配给全局然后在脚本中调用它失败。
以下 C 代码运行
-(void) addRuntimeObject {
GeminiObject *rt = [[GeminiObject alloc] initWithLuaState:L];
GeminiObject **lruntime = (GeminiObject **)lua_newuserdata(L, sizeof(GeminiObject *));
*lruntime = rt;
// set the metatable - effectively declaring the type for this object
luaL_getmetatable(L, GEMINI_OBJECT_LUA_KEY);
lua_setmetatable(L, -2);
// add a table to hold anything the user wants to add
lua_newtable(L);
lua_setuservalue(L, -2);
// create an entry in the global table
lua_setglobal(L, "Runtime");
// empty the stack
lua_pop(L, lua_gettop(L));
}
这应该定义一个名为“运行时”的全局。试图从这样的脚本中访问这个变量
Runtime:addEventListener("enterFrame", enterFrame)
导致以下错误:
attempt to index global 'Runtime' (a userdata value)
这是一个 userdata 值,但是当我直接在 Lua 中创建一个时,这似乎并不重要。元表绑定提供对方法和元方法的访问。同样,如果对象是从 Lua 创建的,这很好用,而不是在 C 中创建时。
关于我在这里做错了什么的任何想法,或者从用户数据创建全局的正确方法是什么?
编辑
基于以下关于 GEMINI_OBJECT_LUA_KEY 混淆的评论,我想我会列出绑定中实际使用的代码:
static const struct luaL_Reg geminiObjectLib_f [] = {
{"new", newGeminiObject},
{NULL, NULL}
};
static const struct luaL_Reg geminiObjectLib_m [] = {
{"addEventListener", addEventListener},
{"__gc", geminiObjectGC},
{"__index", l_irc_index},
{"__newindex", l_irc_newindex},
{NULL, NULL}
};
int luaopen_geminiObjectLib (lua_State *L){
// create the metatable and put it into the registry
luaL_newmetatable(L, GEMINI_OBJECT_LUA_KEY);
lua_pushvalue(L, -1); // duplicates the metatable
luaL_setfuncs(L, geminiObjectLib_m, 0);
// create a table/library to hold the functions
luaL_newlib(L, geminiObjectLib_f);
NSLog(@"gemini lib opened");
return 1;
}
此代码注册了为GeminiObjects
. 调用luaL_newmetatable
创建一个新的元表并将其在注册表中与 key 相关联GEMINI_OBJECT_LUA_KEY
。 GEMINI_OBJECT_LUA_KEY
只是在标头中定义的唯一字符串。 luaL_setfuncs
实际上将函数指针添加到元表,使它们可用作对象的方法。