#c #lua #metatable #lua-api
#c #lua #Метатабли #lua-api
Вопрос:
В 3D-сцене у меня есть объект, у которого есть позиция, которую я хотел бы переместить с помощью Lua.
например. box.position.x = 10
box имеет метатаблицу («Объект»), а также позицию («Vec»). Объект имеет __newindex
и __index
установлен для вызова функций C NewIndexObject
и IndexObject
соответственно. То же самое с Vec ( NewIndexVec
и IndexVec
).
Объект имеет идентификатор, поэтому его можно идентифицировать в списке, который хранится в сцене, и при box.position
обращении к нему все в порядке, вызывается функция C IndexObject, и я могу извлечь идентификатор из стека, просто при box.position.x = 10
выполнении вызывается ‘NewIndexVec’ и единственное, что находится в стекеявляется {table, x, 10}, поэтому нет способа идентифицировать объект для изменения его позиции x.
Есть ли возможность переноса значений в локальное состояние? Помогите!
ОБНОВЛЕНИЕ: спасибо, что быстро перезвонили мне, ниже я максимально переработал код. Если вы запустите этот код, он, похоже, будет работать, но у меня есть комментарии, в которых я застрял, это просто получение первого объекта в массиве, но мне нужно выбрать его по его идентификатору, заранее спасибо
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 amp;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 amp;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: %sn", lua_tostring(L, -1));
lua_close(L);
return 0;
}
Ответ №1:
Если я вас правильно понял, вам не нужно ничего делать. Таблицы отслеживаются по ссылке, поэтому NewIndexVec
не нужно ничего знать о box
том, является ли его первый аргумент box.position
.
Если этот ответ по какой-то причине не может сработать, мне понадобится дополнительная информация о вашей структуре данных, чтобы понять вашу проблему.
По сути, box.position
необходимо вернуть some obj
, для которого obj.x = 10
это допустимая операция, и изменяет именно то, что вы хотите, чтобы она изменилась.
Проблема в том, что вы пытаетесь сохранить одни и те же данные в двух разных местах. Сохраните все данные в структуре C , затем NewObject
верните userdata, который притворяется таблицей. И объект, и position
поле должны быть одинаковыми Obj*
, но они могут иметь разные метатаблицы для имитации разных наборов полей.
Комментарии:
1. Спасибо за быстрый ответ, я обновил свой вопрос, включив код
Ответ №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 amp;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: %sn", lua_tostring(L, -1));
lua_close(L);
return 0;
}