2015-01-12 15 views
5

Tôi sử dụng lua làm ngôn ngữ kịch bản cho công cụ 3d của tôi. Tôi có lua "lớp" cho một số đối tượng và bây giờ tôi muốn sử dụng tài sản thay vì getters và setters. Vì vậy, thay vì một cái gì đó như thế nàyLua: phương pháp và thuộc tính khi xuất lớp từ c

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

tôi sẽ chỉ

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

Vấn đề là C++ của tôi mã cho tạo metatables và ghi đè instanced phương pháp __index. Dưới đây là bằng cách này:

  1. Tạo một metatable:

    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. Khởi tạo các lớp (đối tượng lua chỉ nắm giữ một con trỏ đến một dữ liệu thực tế được lưu trữ trong C++ code):

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

Câu hỏi đặt ra là làm cách nào tôi có thể có cả phương pháp và thuộc tính. Nếu tôi chỉ thêm __index vào CLUAScript::RegisterClass mảng funcs thì nó sẽ không bao giờ được gọi. Và tôi không thể tưởng tượng một cách để loại bỏ định nghĩa lại của nó trong CLUAScript::NewInstanceClass.

Nếu mã này là không đủ, ở đây là các liên kết đến các tập tin làm việc với lua: lua helper class, functions for UI, functions for Objects, và testing lua script

+0

Để giúp làm rõ mối liên hệ giữa C++ và lua mã, những gì là 'ui' và những gì' ui: GetChild ("property_name ")' trả về? Ví dụ, là 'ui' một userdata từ đất C++ hay là một số bảng được trả về bởi' NewInstanceClass' với '__self = udata_object' được đặt? – greatwolf

+0

"ui" là một thể hiện của phần tử giao diện người dùng như nút, bảng điều khiển hoặc toàn bộ màn hình. Mỗi phần tử có thể có các phần tử con, có thể được sử dụng bằng phương thức GetChild (name). Những đứa trẻ này cũng sẽ là các yếu tố giao diện người dùng. Vì vậy, đây là một bảng có chứa một con trỏ tới C++ instance như một userdata và một số phương thức từ metatable được trả về bởi hàm NewInstanceClass. Trong trường hợp này, "ui" là một biến cục bộ đại diện cho toàn bộ màn hình (phần tử gốc của cây giao diện người dùng). –

+0

Điều gì sẽ xảy ra nếu bạn thực hiện các chức năng đứng tự do 'GetChild' và' GetVisible' trong lua? Sau đó, bạn chỉ có thể tạo 'ui.Panel1' như một dạng đường cú pháp dịch sang' GetChild (ui, "Panel1") '. – greatwolf

Trả lời

2

Câu hỏi đặt ra là làm thế nào tôi có thể có cả hai phương pháp và tài sản .

Nói chung, các phương pháp chỉ là các thuộc tính xảy ra để giải quyết các chức năng.

Nếu tôi chỉ thêm __index vào mảng RegisterClass funcs thì không bao giờ được gọi.

Đây là vấn đề thực tế, phải không? Phần còn lại của bài đăng của bạn phân tâm từ vấn đề thực sự.

Theo tài liệu, luaL_newlib creates a new table. Vì vậy, luaL_newmetatable. Bạn đang tạo hai bảng trong RegisterClass, điều này không có ý nghĩa gì cả. Bạn chỉ cần tạo metatable và điều này có thể đạt được mà bạn cần phải thêm các metamethods __index__newindex của mình vào.

Bạn sẽ không thể có __index chỉ cần trỏ đến bảng funcs (cách tắt để triển khai phương thức lớp), không phải nếu bạn muốn sắp xếp thủ công dữ liệu đến và từ thuộc tính thể hiện lớp C++ của bạn. Nó cần phải là một hàm phân biệt truy cập phương thức (giá trị xuất phát từ phạm vi lớp) và truy cập thuộc tính (giá trị đến từ cá thể phạm vi).


Đây là ví dụ về cách truy cập phương pháp/thuộc tính của bạn hoạt động trong Lua.Các chi tiết cụ thể khác nhau bằng cách sử dụng API C, nhưng phương pháp này sẽ là như nhau:

-- 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 
Các vấn đề liên quan