Luabind備忘録

現在Luabindを用いて部のゲームプログラムにLuaを持ち込んでいますが、クラスをバインドすることも多いです。で、クラスのメンバ関数のバインドコードがオーバーロードされているとき非常にめんどくさくて投げたくなるのは仕方がない。

struct drawable
{
    void draw( float, float ) const;
    void draw( float, float, float );
};

void binding( lua_State* L )
{
    using namespace ::luabind;
    module(L)
    [
        class_<drawable>("drawable")
            .def(constructor<>())
            .def("draw",static_cast<void(drawable::*)(float,float) const>(&drawable::draw))
            .def("draw",static_cast<void(drawable::*)(float,float,float)>(&drawable::draw))
    ];
}

まあ、Luabindを使わずにクラスや関数をバインドするのはきっと非常に面倒なのでこれだけで済んでいて良かったと考えるのが良さそうです。だって自前でグルーコード書くのしんどいんですもの。そんなことより、Luabindの使い方のようなものを適当にメモっておく。以下大体がコード片です。

Enumのバインド

enum State
{
    Move, Attack, Jump
};

module(L)
[
    class_<State>("State")
        .enum_("constants")
        [
            value("Move",Move),
            value("Attack",Attack),
            value("Jump",Jump)
        ]
];

// バインドを行う列挙体と名前空間が同じならばこんなマクロがあると良いかも
// #define LUABIND_ENUM_VALUE(v) ::luabind::value(#v,v)
local i = State.Move

if i == State.Move then
    print( "true" )
end

どうもenumもLuabindではclass_関数を用いて定義してやらないといけないようです。

グローバル変数のバインド

struct foo {};

const foo foo_instance;

object global_object = globals(L);

global_object[ "foo_instance" ] = boost::ref(foo_instance);
// boost::refで参照である事を明示

上記の方法でSingletonもバインドできるようです。

非メンバ関数をLua内でメンバ関数として設定

struct point
{
    float x;
    float y;
    point(float _x, float _y) : x(_x), y(_y) {}
    point() : x(0), y(0) {}
};

void move( point& p, float mx, float my )
{
    p.x += mx;
    p.y += my;
}

module(L)
[
    class_<point>("point")
        .def(constructor<float,float>())
        .def(constructor<>())
        .def("move",&move)
        .def_readonly("x",&point::x)
        .def_readonly("y",&point::y)
];
pos = point(32,32)
pos:move(-4,5)

関数の第1引数がオブジェクト自身になっていれば、Lua内でクラスメンバとして振る舞えるようです。Pythonのクラスに似てるな、と思ったりしました。Luabindだけの事ではないような気もしますが、書いてて知ったので一応。