【问题标题】:Nested Lua Metatables in CC 中的嵌套 Lua 元表
【发布时间】:2014-08-12 23:51:40
【问题描述】:

在 3D 场景中,我有一个想要使用 Lua 移动的位置的对象。

例如。 box.position.x = 10

box 有一个元表(“Object”),因此也有一个位置(“Vec”)。对象有__newindex__index 设置为分别调用C 函数NewIndexObjectIndexObject。与 Vec 相同(NewIndexVecIndexVec)。

对象有一个 id,因此可以在存储在场景中的列表中识别它,当访问 box.position 时一切正常,调用 C 函数 IndexObject,我可以从堆栈中提取 id,它只是当box.position.x = 10 被执行时,'NewIndexVec' 被调用并且堆栈上唯一的东西是 {table, x, 10} 所以无法识别对象来改变它的 x 位置。

是否有将值推送到本地状态的方法?救命!

更新:感谢您快速回复我,下面我已经尽可能地提炼了代码。如果您运行此代码,它似乎可以工作,但我有 cmet,我被卡住了,它只是获取数组中的第一个对象,但我需要通过它的 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;
}

【问题讨论】:

    标签: c lua metatable lua-api


    【解决方案1】:

    如果我对您的理解正确,您无需执行任何操作。表是通过引用来跟踪的,所以如果NewIndexVec 的第一个参数是box.position,则NewIndexVec 不需要知道任何关于box 的信息。

    如果这个答案由于某种原因不能工作,那么我需要更多关于你的数据结构的信息来理解你的问题。

    基本上,box.position 需要返回一些 obj,其中 obj.x = 10 是一个有效的操作,并且会准确地更改您希望它更改的内容。


    问题是您试图将相同的数据保存在两个不同的位置。将所有数据保存在 C++ 结构中,然后让 NewObject 返回一个伪装成表的用户数据。 Object 和position 字段应该是相同的Obj*,但它们可能有不同的元表来模拟不同的字段集。

    【讨论】:

    • 感谢您的快速回复,我已更新我的问题以包含代码
    【解决方案2】:

    谢谢,我已经发布了有效的代码

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-18
      • 2013-06-03
      • 2014-01-23
      • 1970-01-01
      • 2014-09-23
      • 1970-01-01
      • 2018-11-21
      • 1970-01-01
      相关资源
      最近更新 更多