Search code examples
c++lualua-apilua-userdata

Create properties and methods Lua C++


This is rather tricky to explain and I could not find anything on this in the documentation or anywhere on the net so I thought this would be a suitable place for this question.

I'm trying to register properties and methods on an object in Lua using C++.

This is what I'm trying to achieve in Lua:

player = createPlayer()
player:jump() // method
player.x = player.x + 3 // properties

I can easily achieve the first line in the example using C++

int create_player(lua_State *L)
{
    Player* player = new Player();
    ..

    return 0;
}

int main(int args, char * argv[])
{
    lua_State* L = lua_open();
    luaL_openlibs(L);    

    lua_register(L, "createPlayer", create_player);

    luaL_dofile(L, "main.lua");

    ..
    return 0;
}

But how do I create the method :jump() and properties .setX and .getX for createPlayer?


Solution

  • What you could have searched is "Binding C++ to Lua".

    Since it's a rather popular question, I'll post an answer with a project compilable online:

    Starting from a C++ class:

    class Player {
      int x;
    public:
      Player() : x(0) {}
      int get_x() const { return x; }
      void set_x(int x_) { x = x_; }
      void jump() {}
    };
    

    You can then create bindings using LuaBridge without writing the boilerplate for each of the bound members yourself:

    void luabridge_bind(lua_State *L) {
     luabridge::getGlobalNamespace(L)
     .beginClass<Player>("Player")
      .addConstructor<void (*)(), RefCountedPtr<Player> /* shared c++/lua lifetime */ >()
      .addProperty("x", &Player::get_x, &Player::set_x)
      .addFunction("jump", &Player::jump)
     .endClass()
     ; 
    }
    

    Using a dedicated Lua State wrapper LuaState, you can then open a Lua state and perform the bindings:

    lua::State state;
    luabridge_bind(state.getState());
    

    Running the script using some trace output:

    try {
      static const char *test =
      "player = Player() \n"
      "player:jump() \n"
      "player.x = player.x + 3"
      ;
      state.doString(test);
    }
    catch (std::exception &e) {
      std::cerr << e.what() << std::endl;
    }
    

    Produces the following output:

    Player
    jump
    get_x
    set_x 3
    ~Player
    

    You can see the whole thing live at Travis-CI