简体   繁体   English

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

[英]Accessing user data as a member of another user data in LUA C++

I am trying to index into a user data called entity to get to another user data called transform component.我正在尝试索引一个称为实体的用户数据,以获取另一个称为转换组件的用户数据。 I am relatively new to lua w/ c++ binding but after I got my entity up and running with metatables and an index method that would allow me to do stuff like this in Lua:我对带有 c++ 绑定的 lua 相对较新,但是在我启动并使用元表和索引方法运行实体之后,我可以在 Lua 中执行此类操作:

entity1 = Entity.create()
entity1:setID(4)
print(entity1)

This works perfectly but I also have a user data called TransformComponent that looks like this in LUA这很好用,但我还有一个名为 TransformComponent 的用户数据,在 LUA 中看起来像这样

transform1 = TransformComponent.create()
transform1:setPosition(4,3)
print(transform1)

Here is where I get stuck.这是我卡住的地方。 What I WANT to be able to do in LUA is something like this:我希望能够在 LUA 中做的事情是这样的:

entity1 = Entity.create()
entity1.transform:setPosition(4,3)
print(entity1)

How do I (in C++) set up this kind of relationship where Entity is a table that contains all its methods but also contains a key called "transform" that maps to the TransformComponent table.我如何(在 C++ 中)建立这种关系,其中 Entity 是一个包含其所有方法的表,但还包含一个名为“transform”的键,该键映射到 TransformComponent 表。 In C++ I tried setting it as a key and I tried reading the "transform" key from the index method and placing the TransformComponent methods in the table but that didn't work.在 C++ 中,我尝试将其设置为键,并尝试从索引方法中读取“转换”键并将 TransformComponent 方法放入表中,但这不起作用。

Any help is extremely appreciated.非常感谢任何帮助。

EDIT编辑

I initially didn't want to include the attempts I made because they were futile and I knew it but what I attempted to do was during the entity index, I would push the table for TransformComponent and hope the next part of the index (ie the methods for TransformComponent)我最初不想包括我所做的尝试,因为它们是徒劳的,我知道,但我试图做的是在实体索引期间,我会为 TransformComponent 推送表格并希望索引的下一部分(即TransformComponent 的方法)

So here is the index method for Entity所以这里是实体的索引方法


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

If i print out the result of "index" its just transform, I can never get it to try and parse "setPosition".如果我打印出“索引”的结果,它只是转换,我永远无法让它尝试解析“setPosition”。 I have no Idea how to progress here.我不知道如何在这里取得进展。 Here is the code to setup the tables:这是设置表的代码:


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

I started thinking this was impossible to accomplish or I am just unable to do this Lua.我开始认为这是不可能完成的,或者我只是无法做到这一点 Lua。 I am unsure but I am definitely not talented enough to figure this out.我不确定,但我绝对没有足够的天赋来解决这个问题。

EDIT2 EntityClass + TransformComponent: EDIT2 EntityClass + 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编辑3

_LUA_CreateTransform method _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;
}

Again any help is super appreciated.再次感谢任何帮助。

Your _LUA_index C++ function is more-or-less equivalent to this in pure Lua:您的_LUA_index C++ function 或多或少等同于纯 Lua:

function EntityMetaTable.__index(luaEntity1, index)
    if tostring(index) == 'transform' then
        return TransformComponent
    end
    return rawget(Entity, index)
end

Thus, when you do entity1.transform:setPosition(4,3) , it's basically equivalent to TransformComponent:setPosition(4,3) .因此,当您执行entity1.transform:setPosition(4,3)时,它基本上等同于TransformComponent:setPosition(4,3) The problem is that you can't do setPosition directly on the TransformComponent table.问题是您不能直接在TransformComponent表上执行setPosition You need to do it on a userdata that TransformComponent.create() gives you, like transform1 is, instead.您需要在TransformComponent.create()提供给您的用户数据上执行此操作,就像transform1一样。 If you want to avoid making a fresh TransformComponent userdata every time, you can save the result as a uservalue (or environment if you're on Lua 5.1 still) on your entity userdata.如果您想避免每次都创建新的TransformComponent用户数据,您可以将结果保存为实体用户数据上的用户值(或环境,如果您仍在 Lua 5.1 上)。


Edit: Now that I see more of your code, here's what you should do.编辑:现在我看到了更多你的代码,这就是你应该做的。 In your Entity class, change TransformComponent transform to TransformComponent *transform .在您的Entity class 中,将TransformComponent transform更改为TransformComponent *transform Then, in your _LUA_CreateEntity function, set up transform the same way that you do in _LUA_CreateTransform .然后,在您的_LUA_CreateEntity function 中,以与_LUA_CreateTransform中相同的方式设置transform Then set the transform userdata as the environment or uservalue (depending on Lua version) of the entity userdata.然后将变换 userdata 设置为实体 userdata 的环境或用户值(取决于 Lua 版本)。 Finally, in your index method, return that environment/uservalue instead of doing lua_getglobal(L, "TransformComponent");最后,在您的 index 方法中,返回该环境/用户值,而不是执行lua_getglobal(L, "TransformComponent"); . .

You are returning a static class/table ( TransformComponent in this case) when your entity's index transform is called.当调用实体的索引transform时,您将返回 static 类/表(在本例中为TransformComponent )。 What you really need is the actual instance of your transform that is present inside your entity class.您真正需要的是实体 class 中存在的转换的实际实例。 So technically, you want properties of your object to be accessible from Lua easily by calling ent.transform .所以从技术上讲,您希望通过调用ent.transform从 Lua 轻松访问 object 的属性。

To achieve this, you can use sol which is "a fast, simple C++ and Lua Binding".为此,您可以使用sol ,它是“一种快速、简单的 C++ 和 Lua 绑定”。

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

Additionally, you can have properties that are read-only which would fit your transform property perfectly since you do not want it to be replaced with a new transform and rather you want the transform properties to be changed.此外,您可以拥有完全适合您的转换属性的只读属性,因为您不希望将其替换为新的转换,而是希望更改转换属性。

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

As a side note, be sure to first register your TransformComponent with all it's functions and properties and then register your Entity.作为旁注,请务必先注册您的TransformComponent及其所有功能和属性,然后注册您的实体。

Have a look atsol properties and sol classes instruction for more details.查看sol 属性sol 类指令以获取更多详细信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM