在LUA C++中作为另一个用户数据的成员访问用户数据。

问题描述 投票:2回答:1

我正试图向一个名为 "实体 "的用户数据中建立索引,以获取另一个名为 "变换组件 "的用户数据,我对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;
}

再次超级感谢任何帮助。

c++ lua
1个回答
3
投票

你的 _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 transformTransformComponent *transform. 然后,在你的 _LUA_CreateEntity 功能,建立 transform 和你一样 _LUA_CreateTransform. 然后将变换后的userdata设置为实体userdata的环境或uservalue(取决于Lua版本)。最后,在你的索引方法中,返回那个环境值,而不是做那个 lua_getglobal(L, "TransformComponent");.


1
投票

你正在返回一个静态的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 与它的所有功能和属性,然后注册你的实体。

请看一下 溶洞属性辅导班 更多细节。

© www.soinside.com 2019 - 2024. All rights reserved.