2015-01-12 4 views
5

私は3Dエンジンのスクリプト言語としてluaを使用します。私はいくつかのオブジェクトのためのルア "クラス"を持っています。そして今、ゲッタとセッタの代わりにプロパティを使いたいと思います。だから、代わりにこのLua:cからクラスをエクスポートするときのメソッドとプロパティ

local oldState = ui:GetChild("Panel1"):GetVisible() 
ui:GetChild("Panel1"):SetVisible(not oldState) 

のようなもの、私はちょうど

ui.Panel1.visible = not ui.Panel1.visible 

問題は__index方法メタテーブルとインスタンス化オーバーライドを作成するための私のC++コードであるだろう。ここでは、方法によるものである。

  1. はメタテーブルの作成:

    void CLUAScript::RegisterClass(const luaL_Reg funcs[], std::string const& className) 
    { 
        luaL_newmetatable(m_lua_state, std::string("Classes." + className).c_str()); 
        luaL_newlib(m_lua_state, funcs); 
        lua_setglobal(m_lua_state, className.c_str()); 
    } 
    
  2. (LUAオブジェクトのみC++コードに格納されている実際のデータへのポインタを保持している)クラスをインスタンス化:

    int CLUAScript::NewInstanceClass(void* instance, std::string const& className) 
    { 
        if (!instance) 
        { 
         lua_pushnil(m_lua_state); 
         return 1; 
        } 
    
        luaL_checktype(m_lua_state, 1, LUA_TTABLE); 
    
        lua_newtable(m_lua_state); 
    
        lua_pushvalue(m_lua_state,1);  
        lua_setmetatable(m_lua_state, -2); 
    
        lua_pushvalue(m_lua_state,1); 
        lua_setfield(m_lua_state, 1, "__index"); 
    
        void **s = (void **)lua_newuserdata(m_lua_state, sizeof(void *)); 
    
        *s = instance; 
        luaL_getmetatable(m_lua_state, std::string("Classes." + className).c_str()); 
        lua_setmetatable(m_lua_state, -2); 
        lua_setfield(m_lua_state, -2, "__self"); 
    
        return 1; 
    } 
    

質問は、私はメソッドとプロパティの両方を持つことができる方法です。私がちょうど__indexCLUAScript::RegisterClass funcsの配列に追加すると、決して呼び出されません。そして、私はCLUAScript::NewInstanceClassでその再定義を取り除く方法を想像することはできません。

このコードは十分でない場合は、ここではLUAでの作業ファイルへのリンクです: lua helper classfunctions for UIfunctions for Objects、および testing lua script

+0

C++コードとLuaのコードとの間の接続を明確に支援するために、 'ui'と何' UIを何です:でGetChild(「PROPERTY_NAME ")'戻りますか?例えば、 'ui'はC++の土地のユーザデータですか?' __self = udata_object'がセットされた 'NewInstanceClass'によって返されたテーブルですか? – greatwolf

+0

"ui"は、ボタン、パネル、または画面全体のようなUI要素のインスタンスです。すべての要素は子要素を持つことができ、GetChild(name)メソッドを使用してアクセスできます。これらの子もUI要素になります。これは、ユーザーデータとしてのC++インスタンスへのポインタと、NewInstanceClass関数によって返されたメタテーブルからのいくつかのメソッドを含むテーブルです。この場合、「ui」は画面全体(UIツリーのルート要素)を表すローカル変数です。 –

+0

'GetChild'と' GetVisible'をluaで自由に動作させるとどうなるでしょうか?次に 'ui.Panel1'を' GetChild(ui、 "Panel1") 'に変換する構文糖の形式として作ることができます。 – greatwolf

答えて

2

質問は、私はメソッドとプロパティの両方を持つことができる方法であります。

大まかに言えば、メソッドは関数に解決されるプロパティです。

__indexをRegisterClass funcs配列に追加するだけでは呼び出されません。

これは実際の問題です。残りのあなたのポストは、本当の問題から気をそらす。

文書によれば、luaL_newlib creates a new table。 luaL_newmetatableもそうです。 RegisterClassに2つのテーブルを作成していますが、意味がありません。メタテーブルのみを作成する必要があります。メタタイプを__index__newindexというメタメソッドに追加する必要があります。

__indexは、C++クラスのインスタンスプロパティとの間でデータを手作業でマーシャリングする場合を除き、funcのテーブル(クラスメソッドを実装するショートカット方法)を指すことはできません。メソッドのアクセス(値はクラススコープに由来)とプロパティアクセス(値はインスタンススコープに由来)を区別する関数である必要があります。


ここでは、メソッド/プロパティへのアクセスがLuaでどのように機能するかの例を示します。具体的には、CのAPIを使用して異なっているが、アプローチは同じのようになります。

-- This is the metatable you create in RegisterClass for the C++ class 'Foo' 
Foo = { } 

-- This is pretty close to how your __index metamethod would work in the C++ code, 
-- except you're going to have to write code that resolves which field on the C++ object 
-- corresponds to 'key', if any, and push that onto the stack. 
function Foo.__index(instance,key) 
    local method = rawget(Foo,key) 
    if method then 
     return method 
    end 
    return instance.properties[key] 
end 

-- This is pretty close, too, except that if you want users to be able to add properties to the Lua object 
-- that coexist with the C++ object properties, you'll need to write the value to the right place. 
function Foo.__newindex(instance,key,value) 
    instance.properties[key] = value 
end 

-- this doesn't have to be a method on the metatable 
function Foo:new(state) 
    return setmetatable({ properties = state}, self) 
end 

-- example of a class method 
function Foo:dump() 
    print('dump:', self.x, self.y) 
end 

-- simulation of the userdata, an instance of your C++ class 
cppClassInstance = { 
    x = 10, 
    y = 20, 
} 

obj = Foo:new(cppClassInstance) 
print(obj.x) -- read `x`, which is resolved to cppClassInstance.x 
obj.x = 5150 -- write to 'x', which writes to cppClassInstance.x 
print(obj.x) -- witness our change 
obj:dump() -- call a class method 
関連する問題