2015-01-12 14 views
5

Ich benutze Lua als Skriptsprache für meine 3D-Engine. Ich habe Lua "Klassen" für mehrere Objekte und jetzt möchte ich Eigenschaften anstelle von Getter und Setter verwenden. Anstatt also so etwas wie diesLua: Methoden und Eigenschaften beim Exportieren von Klassen aus c

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

würde ich nur

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

Das Problem ist mein C++ Code für Metatables und instanzierte überschreibt die __index Methode zu schaffen. Hier ist übrigens:

  1. eine Metatabelle erstellen:

    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. Instanziieren der Klasse (die lua-Objekt enthält nur einen Zeiger auf einer tatsächlichen Daten, die in C++ Code gespeichert ist):

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

Die Frage ist, wie kann ich beide Methoden und Eigenschaften haben. Wenn ich nur __index zu CLUAScript::RegisterClass Funcs-Array hinzufügen, wird es nie aufgerufen. Und ich kann mir keinen Weg vorstellen, seine Neudefinition in CLUAScript::NewInstanceClass zu entfernen.

Wenn dieser Code nicht genug ist, ist hier die Links zu Dateien mit lua arbeiten: lua helper class, functions for UI, functions for Objects und testing lua script

+0

die Verbindung zwischen C++ Code und lua Code zu klären zu helfen, was 'ui' und was bedeutet' ui: GetChild ("property_name ")' Rückkehr? Zum Beispiel, ist 'ui' ein Userdata von C++ Land oder ist es eine Tabelle, die von 'NewInstanceClass' mit '__self = udata_object' zurückgegeben wird? – greatwolf

+0

Das "ui" ist eine Instanz eines UI-Elements wie Schaltfläche, Panel oder ein gesamter Bildschirm. Jedes Element kann untergeordnete Elemente enthalten, die mit der GetChild (name) -Methode aufgerufen werden können. Diese Childs sind auch UI-Elemente. Dies ist also eine Tabelle, die einen Zeiger auf C++ - Instanz als Benutzerdaten und einige Methoden aus Metatabelle enthält, die von der NewInstanceClass-Funktion zurückgegeben werden. In diesem Fall ist "ui" eine lokale Variable, die den gesamten Bildschirm darstellt (das Wurzelelement der UI-Struktur). –

+0

Was ist, wenn Sie 'GetChild' und' GetVisible' freistehende Funktionen in lua machen? Dann können Sie 'ui.Panel1' als eine Form von Syntax Sugar machen, die in' GetChild (ui, "Panel1") übersetzt wird. – greatwolf

Antwort

2

Die Frage ist, wie kann ich beide Methoden und Eigenschaften haben .

Grob gesagt, Methoden sind nur Eigenschaften, die zufällig zu Funktionen auflösen.

Wenn ich einfach __index zu RegisterClass funcs Array hinzufügen, wird es nie aufgerufen.

Das ist das eigentliche Problem, oder? Der Rest Ihres Posts lenkt vom eigentlichen Problem ab.

Gemäß den Dokumenten, luaL_newlib creates a new table. So auch luaL_newmetatable. Sie erstellen zwei Tabellen in RegisterClass, was keinen Sinn ergibt. Sie müssen nur das Metatable erstellen, und es ist dieses Metatable, das Sie Ihren __index und __newindex Metamethoden hinzufügen müssen.

Sie können __index nicht einfach auf eine Tabelle von funcs zeigen (der Verknüpfungsweg zum Implementieren von Klassenmethoden), nicht wenn Sie Daten von und zu Ihren C++ - Klasseninstanzeigenschaften manuell marshallen möchten. Es muss eine Funktion sein, die den Methodenzugriff (Wert stammt aus dem Klassenbereich) und den Eigenschaftszugriff (Wert stammt aus dem Instanzbereich) unterscheidet.


Hier ist ein Beispiel, wie Ihre Methode/Eigenschaft Zugriff in Lua funktionieren würde.Die Besonderheiten sind unterschiedlich den C-API verwenden, aber der Ansatz wäre das gleiche:

-- 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 
Verwandte Themen