簡體   English   中英

C中的嵌套Lua元表

[英]Nested Lua Metatables in C

在3D場景中,我有一個對象,該對象的位置要使用Lua移動。

例如。 box.position.x = 10

框具有一個元表(“對象”),位置也具有(“ Vec”)。 Object設置了__newindex__index來分別調用C函數NewIndexObjectIndexObject 與Vec相同( NewIndexVecIndexVec )。

對象有一個ID,因此可以在存儲在場景中的列表中對其進行標識,並且在訪問box.position時一切都很好,調用了C函數IndexObject,並且我可以從堆棧中提取ID,就在box.position.x = 10被執行'Ne​​wIndexVec'被調用,並且堆棧上唯一的東西是{table,x,10},因此無法識別對象來更改其x位置。

無論如何,有將價值推到本地狀態的方法嗎? 救命!

更新:感謝您迅速與我聯系,下面我盡可能地精煉了代碼。 如果您運行此代碼,它似乎可以正常工作,但我在卡住的位置添加了注釋,它只是獲取數組中的第一個對象,但我需要通過其ID選擇它,謝謝。

struct Obj
{
    std::string id;
    int x,y,z;
    Obj()
    {
        x = 10; y = 20; z = 30;
        id = "12345";
    }
};

//array of external objects
std::vector<Obj> objects;

int NewObject(lua_State * L)
{
    Obj obj;
    objects.push_back(obj);

    lua_newtable(L); 

    luaL_getmetatable(L, "MT_Object");
    lua_setmetatable(L, -2);

    lua_pushstring(L, "id");
    lua_pushstring(L, obj.id.c_str());
    lua_settable(L, 1);

    lua_newtable(L); 
    luaL_getmetatable(L, "MT_Vec");
    lua_setmetatable(L, -2);

    lua_pushinteger(L, obj.x);
    lua_setfield(L, -2, "x"); 

    lua_pushinteger(L, obj.y);
    lua_setfield(L, -2, "y"); 

    lua_pushinteger(L, obj.z);
    lua_setfield(L, -2, "z"); 

    lua_setfield(L, -2, "position");



    return 1;
}

int IndexVec(lua_State * L)
{
    // How do I get the correct object so I can pass its value back
    Obj &dunnoObj =  objects[0];

    std::string key = luaL_checkstring(L,-1);
    if(key == "x")
        lua_pushinteger(L,dunnoObj.x);
    else if(key == "y")
        lua_pushinteger(L,dunnoObj.y);
    else if(key == "z")
        lua_pushinteger(L,dunnoObj.z);
    return 1;
}


int NewIndexVec(lua_State * L)
{
    // How do I know which object's value to update
    Obj &dunnoObj =  objects[0];

    std::string key = luaL_checkstring(L,-2);
    int value = luaL_checkinteger(L,-1);

    if(key == "x")
        dunnoObj.x = value;
    else if(key == "y")
        dunnoObj.y = value;
    else if(key == "z")
        dunnoObj.z = value;

    return 0;
}

int main()
{
    lua_State * L = luaL_newstate();
    luaL_openlibs(L);


    luaL_Reg objreg[] =
    {
        { "new", NewObject },   
        { NULL, NULL }
    };
    luaL_newmetatable(L, "MT_Object");
    luaL_register(L, 0, objreg);
    lua_setglobal(L, "Object");


    luaL_Reg reg[] =
    {
        { "__index", IndexVec },    
        { "__newindex", NewIndexVec },
        { NULL, NULL }
    };
    luaL_newmetatable(L, "MT_Vec");
    luaL_register(L, 0, reg);
    lua_setglobal(L, "Vec");


    int res = luaL_dostring(L, "box = Object.new()   box.position.x = 1000   print(box.id .. \" , \" ..box.position.x .. \" , \" ..  box.position.y .. \" , \" .. box.position.z)");
    if(res)
        printf("Error: %s\n", lua_tostring(L, -1));



    lua_close(L);

    return 0;
}

如果我理解正確,則您無需執行任何操作。 表通過引用跟蹤,所以NewIndexVec並不需要知道什么box當第一個參數是box.position

如果由於某種原因該答案無法解決,那么我需要有關您的數據結構的更多信息以了解您的問題。

基本上, box.position需要返回一些obj.x = 10是有效操作的obj ,並精確地更改您想要更改的內容。


問題是您試圖將相同的數據保存在兩個不同的位置。 將所有數據保留在C ++結構中,然后讓NewObject返回一個偽裝成表的userdata。 Object和position字段都應該是相同的Obj* ,但是它們可能具有不同的元表來模擬不同的字段集。

謝謝,我已經發布了有效的代碼

struct Obj
{
    unsigned int id;
    int x,y,z;
    Obj()
    {
        x = 10; y = 20; z = 30;
        id = rand();
    }
};

//array of external objects
std::map<unsigned int,Obj> objects;

int NewObject(lua_State * L)
{
    Obj obj;
    objects[obj.id] = obj;

    lua_pushinteger(L, obj.id);
    luaL_getmetatable(L, "MT_Object");
    lua_setmetatable(L, -2);

    return 1;
}


int IndexObj(lua_State * L)
{
    unsigned int objid = luaL_checkinteger(L,1);

    std::string key = luaL_checkstring(L,-1);

    if(key == "position" )
    {
        Obj *a = (Obj *)lua_newuserdata(L, sizeof(Obj));
        *a = objects[objid];

        luaL_getmetatable(L, "MT_Vec");
        lua_setmetatable(L, -2);
    }
    else if(key == "id")
        lua_pushinteger(L, objid);  
    else
        lua_pushnil(L);

    StackDump(L);
    return 1;
}

int IndexVec(lua_State * L)
{
    Obj *a = (Obj *)lua_touserdata(L, 1);

    std::string key = luaL_checkstring(L,-1);
    if(key == "x")
        lua_pushinteger(L,a->x);
    else if(key == "y")
        lua_pushinteger(L,a->y);
    else if(key == "z")
        lua_pushinteger(L,a->z);
    return 1;
}


int NewIndexVec(lua_State * L)
{
    Obj *a = (Obj *)lua_touserdata(L, 1);
    Obj &objRef =  objects[a->id];

    std::string key = luaL_checkstring(L,-2);
    int value = luaL_checkinteger(L,-1);

    if(key == "x")
        objRef.x = value;
    else if(key == "y")
        objRef.y = value;
    else if(key == "z")
        objRef.z = value;

    return 0;
}

int main()
{
    lua_State * L = luaL_newstate();
    luaL_openlibs(L);


    luaL_Reg objreg[] =
    {
        { "new", NewObject },   
        { "__index", IndexObj },
        { "__newindex", NewIndexObj },
        { NULL, NULL }
    };
    luaL_newmetatable(L, "MT_Object");
    luaL_register(L, 0, objreg);
    lua_setglobal(L, "Object");


    luaL_Reg reg[] =
    {
        { "__index", IndexVec },    
        { "__newindex", NewIndexVec },
        { NULL, NULL }
    };
    luaL_newmetatable(L, "MT_Vec");
    luaL_register(L, 0, reg);
    lua_setglobal(L, "Vec");

    int res = luaL_dostring(L,  "box = Object.new()   box.position.x = 1000 "
                                "print(box.id .. \" , \" ..box.position.x .. \" , \" ..  box.position.y .. \" , \" .. box.position.z)");
    if(res)
        printf("Error: %s\n", lua_tostring(L, -1));

    lua_close(L);

    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM