我正试图向一个名为 "实体 "的用户数据中建立索引,以获取另一个名为 "变换组件 "的用户数据,我对lua和c++绑定比较陌生。我对lua和c++绑定比较陌生,但在我用元数据表和索引方法让我的实体建立并运行后,我就可以在lua中做这样的事情了。
entity1 = Entity.create()
entity1:setID(4)
print(entity1)
这工作非常完美 但我还有一个用户数据叫TransformComponent 它在LUA中是这样的:
transform1 = TransformComponent.create()
transform1:setPosition(4,3)
print(transform1)
这就是我被卡住的地方。我希望能够在LUA中做的是这样的事情。
entity1 = Entity.create()
entity1.transform:setPosition(4,3)
print(entity1)
我如何(在C++中)建立这样的关系 Entity是一个包含所有方法的表 但也包含一个叫做 "transform "的键映射到TransformComponent表上 在C++中,我试着将它设置为一个键,我试着从索引方法中读取 "transform "键,并将TransformComponent方法放在表中,但没有成功。
任何帮助都是非常感激的。
EDIT
我最初不想包括我所做的尝试,因为它们是徒劳的,我知道这一点,但我尝试做的是在实体索引期间,我会推送TransformComponent的表,并希望索引的下一部分(即TransformComponent的方法)。
所以这里是实体的索引方法
static int _LUA_index(lua_State* L) {
assert(lua_isstring(L, -1));
Entity* luaEntity1 = (Entity*)lua_touserdata(L, -2); assert(luaEntity1);
std::string index = lua_tostring(L, -1);
if (index == "transform") {
lua_getglobal(L, "TransformComponent");
return 1;
}
lua_getglobal(L, "Entity");
lua_pushstring(L, index.c_str());
lua_rawget(L, -2);
return 1;
}
如果我打印出 "index "的结果,它只是变换,我永远无法让它尝试并解析 "setPosition"。我不知道如何在这里进步。这里是设置表格的代码。
lua_State* L = luaL_newstate();
luaL_openlibs(L);
/* --------- Transform table ----------- */
lua_newtable(L);
int transformTableIndex = lua_gettop(L);
lua_pushvalue(L, transformTableIndex);
lua_setglobal(L, "TransformComponent");
lua_pushcfunction(L, TransformComponent::_LUA_CreateTransform);
lua_setfield(L, -2, "create");
lua_pushcfunction(L, TransformComponent::_LUA_SetPosition);
lua_setfield(L, -2, "setPosition");
/* --------- Transform Meta table ----------- */
luaL_newmetatable(L, "TransformComponentMetaTable");
lua_pushcfunction(L, TransformComponent::_LUA_gc);
lua_setfield(L, -2, "__gc");
lua_pushcfunction(L, TransformComponent::_LUA_eq);
lua_setfield(L, -2, "__eq");
lua_pushcfunction(L, TransformComponent::_LUA_tostring);
lua_setfield(L, -2, "__tostring");
lua_pushcfunction(L, TransformComponent::_LUA_index);
lua_setfield(L, -2, "__index");
/* --------- Entity table --------- */
lua_newtable(L);
int entityTableIndex = lua_gettop(L);
lua_pushvalue(L, entityTableIndex);
lua_setglobal(L, "Entity");
constexpr int NUM_OF_UPVALUES = 1;
lua_pushlightuserdata(L, &manager);
lua_pushcclosure(L, Entity::_LUA_CreateEntity, NUM_OF_UPVALUES);
//lua_pushcfunction(L, Entity::_LUA_CreateEntity);
lua_setfield(L, -2, "create");
lua_pushcfunction(L, Entity::_LUA_MoveEntity);
lua_setfield(L, -2, "move");
lua_pushcfunction(L, Entity::_LUA_DrawEntity);
lua_setfield(L, -2, "draw");
/* --------- Entity Meta table --------- */
luaL_newmetatable(L, "EntityMetaTable");
lua_pushstring(L, "__gc");
lua_pushcfunction(L, Entity::_LUA_gc);
lua_settable(L, -3);
lua_pushstring(L, "__eq");
lua_pushcfunction(L, Entity::_LUA_eq);
lua_settable(L, -3);
lua_pushstring(L, "__tostring");
lua_pushcfunction(L, Entity::_LUA_tostring);
lua_settable(L, -3);
lua_pushstring(L, "__index");
lua_pushcfunction(L, Entity::_LUA_index);
lua_settable(L, -3);
我开始认为这是不可能完成的,或者说我无法完成这个Lua。我不确定,但我绝对没有足够的天赋来解决这个问题。
EDIT2EntityClass + TransformComponent。
struct _API SpriteComponent {
const char* fileName;
};
struct _API TransformComponent {
glm::vec2 position;
glm::vec3 rotation;
TransformComponent();
~TransformComponent();
static int _LUA_CreateTransform(lua_State* L);
static int _LUA_SetPosition(lua_State* L);
static int _LUA_gc(lua_State* L);
static int _LUA_eq(lua_State* L);
static int _LUA_index(lua_State* L);
static int _LUA_tostring(lua_State* L);
};
class _API Entity{
public:
TransformComponent transform;
SpriteComponent sprite;
Entity();
~Entity();
void moveEntity(float x, float y);
void drawEntity();
static int _LUA_CreateEntity(lua_State* L);
..etc etc
EDIT3
_LUA_CreateTransform方法。
int TransformComponent::_LUA_CreateTransform(lua_State* L) {
void* entityPointer = lua_newuserdata(L, sizeof(TransformComponent));
new(entityPointer) TransformComponent(); assert(entityPointer);
luaL_getmetatable(L, "TransformComponentMetaTable");
lua_setmetatable(L, -2);
return 1;
}
再次超级感谢任何帮助。
你的 _LUA_index
在纯Lua中,C++函数或多或少地等同于此。
function EntityMetaTable.__index(luaEntity1, index)
if tostring(index) == 'transform' then
return TransformComponent
end
return rawget(Entity, index)
end
因此,当你做 entity1.transform:setPosition(4,3)
基本上等同于 TransformComponent:setPosition(4,3)
. 问题是,你不能做 setPosition
直接在 TransformComponent
表。你需要在一个用户数据上进行操作,这个用户数据是 TransformComponent.create()
给你,像 transform1
是,而不是。如果你想避免做一个新鲜的 TransformComponent
userdata,你可以将结果保存为实体userdata上的一个uservalue(或环境,如果你还在使用Lua 5.1)。
编辑: 现在我看到了你更多的代码,这里是你应该做的。在你的 Entity
类,改变 TransformComponent transform
到 TransformComponent *transform
. 然后,在你的 _LUA_CreateEntity
功能,建立 transform
和你一样 _LUA_CreateTransform
. 然后将变换后的userdata设置为实体userdata的环境或uservalue(取决于Lua版本)。最后,在你的索引方法中,返回那个环境值,而不是做那个 lua_getglobal(L, "TransformComponent");
.
你正在返回一个静态的classtable (TransformComponent
在这种情况下),当您的实体的索引 transform
被调用。你真正需要的是存在于实体类中的变换的实际实例。所以从技术上讲,您希望您的对象的属性可以通过调用 ent.transform
.
要实现这一点,你可以使用 溶洞 这是 "一个快速、简单的 C++ 和 Lua Binding"。
class _API Entity{
public:
TransformComponent transform;
TransformComponent get_transform() {
return transform;
}
void set_transform(TransformComponent value) {
transform = value;
}
...
#include <sol/sol.hpp>
int main (int, char*[]) {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<Entity>( "Entity",
"transform", sol::property(&Entity::get_transform, &Entity::set_transform)
);
此外,您可以拥有只读属性,这将非常适合您的变换属性,因为您不希望它被一个新的变换所取代,而是希望变换属性被改变。
sol::usertype<Entity> type_ent = lua.new_usertype<Entity>("Entity",
sol::constructors<Entity()>());
// Read only property (Still, you can call your Transform methods on it).
type_ent.set("transform", sol::readonly(&Entity::get_transform));
作为一个补充说明,请确保首先注册你的 TransformComponent
与它的所有功能和属性,然后注册你的实体。