![](/img/trans.png)
[英]Behaviour of lua_pushlightuserdata metatables across different modules in c
[英]Nested Lua Metatables in C
在3D场景中,我有一个对象,该对象的位置要使用Lua移动。
例如。 box.position.x = 10
框具有一个元表(“对象”),位置也具有(“ Vec”)。 Object设置了__newindex
和__index
来分别调用C函数NewIndexObject
和IndexObject
。 与Vec相同( NewIndexVec
和IndexVec
)。
对象有一个ID,因此可以在存储在场景中的列表中对其进行标识,并且在访问box.position
时一切都很好,调用了C函数IndexObject,并且我可以从堆栈中提取ID,就在box.position.x = 10
被执行'NewIndexVec'被调用,并且堆栈上唯一的东西是{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.