2012-04-07 2 views
0

iOS 5.x에서 게임의 루아 (5.2) 스크립팅을 허용하기 위해 라이브러리 작업을하고 있습니다. 클래스를 만들고 바인딩을 추가하여 Lua를 만들고 액세스 할 수있게했습니다. 루아에서 호출 C의 초기화 방법에 대하여 주어진다userdata에서 Objective C/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; 

} 

이것은 다양한 방법에 대한 액세스를 제공하는 다른 설정 메타 테이블을 할당한다. 또한 스크립트 코드가 개체에 특성을 할당 할 수 있도록 테이블을 사용자 값으로 연결합니다.

나는 문제없이 루아 스크립트에서 이러한 개체를 만들 수 있습니다

다음 objectTouched
require "gemini" 
x = gemini.new() 
x:addEventListener("touch", objectTouched) 

는 터치 이벤트를 처리 다른 곳에서 정의 루아 방법입니다. 여기 addEventListenertouch 이벤트에 바인드합니다.

이 개체는 정상적으로 작동합니다. 그러나 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에서 글로벌하게 만드는 올바른 방법은 무엇입니까? ? 보여주지 (이 코드는 함수의 라이브러리를 등록

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; 
} 

: GEMINI_OBJECT_LUA_KEY에 대한 혼란에 대한 아래의 의견을 바탕으로 편집

, 나는 실제로 바인딩에서 사용되는 코드를 나열 것이라고 생각 여기에서) GeminiObjects에 대한 방법과 메타 메소드를 제공합니다. luaL_newmetatable을 호출하면 새 메타 테이블이 만들어지고 레지스트리에 키 GEMINI_OBJECT_LUA_KEY과 연결됩니다. GEMINI_OBJECT_LUA_KEY은 헤더에 정의 된 고유 한 문자열입니다. luaL_setfuncs은 실제로 함수 포인터를 메타 테이블에 추가하여 객체의 메소드로 사용할 수 있도록합니다.

+0

정말 개체 설정 도구를 함수로 분해해야합니다. 복사 및 붙여 넣기 코딩이 좋지 않습니다. 또한'GEMINI_OBJECT_LUA_KEY'는 어떻게 작동합니까? 항상 같은 장소에 있지는 않습니다. 스택에 푸시하지 않으면 (그리고 심지어 그렇다고해도 반드시 * 생각한 위치에 있지는 않습니다). –

+0

그것에 대해 생각한 후에,이 신비한'GEMINI_OBJECT_LUA_KEY' 건과 관련이 있다고 생각합니다. 당신은 잘못된 테이블을 얻었고 사용자 데이터의 메타 테이블에'nil' 값을 설정 한 것 같습니다. –

+0

@ NicolBolas 의견을 보내 주셔서 감사합니다.하지만 내 코드가 기능 상에 없다고 생각하는 이유가 확실하지 않습니다. 분명히 여기에 두 개의 함수 인'newGeminiObject'가 루아에 의해 호출 된 C 함수의 표준 프로토 타입 다음에 오는 C 함수와'Runtime' 객체의 단일 인스턴스를 생성하는 Objective C 함수 인'addRuntimeObject'를 나열했습니다. 또한 잘라 내기 및 붙여 넣기 코드가 없으므로 그 이유를 알 수 없습니다. 'GEMINI_OBJECT_LUA_KEY'와 관련하여, 이것은이 객체 유형에 대한 메타 테이블을 설정할 때 별도의 메소드에서 사용되는 상수입니다. 이것은 표준 물건입니다. – James

답변

2

누구나 여전히 관심이있는 경우, 루아 메일 링리스트의 친절한 사람들이 내 질문에 대한 답변을 얻었습니다. 여기서 문제는 라이브러리 바인딩 함수 luaopen_geminiObjectLib이 호출되기 전에 addRuntimeObject에 호출되지 않는다는 것입니다.

iOS는 동적 라이브러리를 지원하지 않으므로 Lua 소스 linit.cpreloadedlibs 어레이에 대한 포인터를 추가하여 정적으로 라이브러리를 추가했습니다.불행히도이 방법으로 추가 된 라이브러리는 require('libname')이 루아 스크립트에서 실행될 때까지로드되지 않습니다. Lua 스크립트를 실행하기 전에 addRuntimeObject 메서드를 호출 했으므로 라이브러리가 아직로드되지 않았습니다.

해결 방법은 동일한 linit.c 파일의 loadedlibs 배열에 luaopen_geminiObjectLib에 대한 포인터를 추가하는 것입니다. 이렇게하면 Lua가 시작될 때 라이브러리가로드되어 require의 스크립트가 필요하지 않습니다.