私はiOS5.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」という名前のグローバルが定義されます。このようなスクリプトからこの変数にアクセスしようとしています
Runtime:addEventListener("enterFrame", enterFrame)
次のエラーが発生します。
attempt to index global 'Runtime' (a userdata value)
これはuserdata値ですが、Luaで直接作成する場合は問題にならないようです。メタテーブルバインディングは、メソッドとメタメソッドへのアクセスを提供します。繰り返しますが、これは、オブジェクトがCで作成されたときではなく、Luaから作成された場合に正常に機能します。
私がここで間違っていること、またはユーザーデータからグローバルを作成する正しい方法についてのアイデアはありますか?
編集
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
。toを呼び出すとluaL_newmetatable
、新しいメタテーブルが作成され、レジストリ内でキーに関連付けられますGEMINI_OBJECT_LUA_KEY
。 GEMINI_OBJECT_LUA_KEY
ヘッダーで定義された一意の文字列です。 luaL_setfuncs
実際に関数ポインタをメタテーブルに追加し、オブジェクトのメソッドとして使用できるようにします。