Luaについて軽く学習

  • 参考文献
    • スクリプト言語による効率的ゲーム開発 浜中誠 SoftBankCreative

Luaって名前かわいいよね!


必要最小限の話だけ覚えておこう備忘録


大概の話はリファレンスみればいいよね!

テーブルについて

  • 配列として使える
  • 連想配列として使える
  • メタテーブル

メタテーブル

  • テーブルやユーザーデータを使用したときの演算子の役割を置き換える
  • テーブル内の要素を参照するときの動作を変更することができる
  • 二項演算子の場合は、左項の要素を持つメタテーブルの処理が優先

クラスの実装


テンプレート
--クラスの作成
ClassName = {}

--インスタンス作成関数
function ClassName:new()
	--インスタンスとして使用するテーブル
	local t = {}
	
--メンバ変数の定義
	
--継承
ClassName.__index = Point
setmetatable(t, ClassName)
return t
end

--以下メンバ関数の定義
function ClassName:Sample()
end

--クラスの利用
local sample = ClassName:new()

sample:Sample()
こんな感じで書けばオブジェクト指向チックにLuaを使うことができる。
ところで、delete()がないのはLuaはガベージコレクションができるからって認識でいいのかな。
中身としては、まずClassNameというテーブルを用意する。
そのテーブルの要素として、new()という関数をいれる。
ClassName:new() というのは、ClassName.new(self)と同意義。
ただ、クラス風に使うなら前者の方が見やすい。
ローカル変数は、そのスクリプトファイル内のその変数定義した場所以降で使える。
メタテーブルの __index 指定に関数ではなく連想配列を指定した場合、 メタテーブルが設定された値に対して連想配列としての参照 (今回の使い方では メソッドの呼び出しに相当) を行い値が見つからなかったら、 代わりに指定した連想配列を参照するようになります。(Luaで組んでみるより)
連想配列って便利ですね。

LuaをC/C++プログラムに組み込む


VC++2008への組み込み方の備忘録

  • [プロジェクトの設定]>[構成プロパティ]>[C/C++]>[全般]
    • 「追加のインクルードディレクトリ」の項目に、「..\lua5.1\include」
  • [プロジェクトの設定]>[構成プロパティ]>[リンカ]>[全般]
    • 「追加のライブラリディレクトリ」の項目に、「..\lua5.1\lib\static」
  • [プロジェクトの設定]>[構成プロパティ]>[リンカ]>[入力]
    • 「追加の依存ファイル」の項目に、「lua5.1.lib」

ソースファイルの変更

C/C++のソースに以下のように変更
(略)
#include <lua.hpp>

int main(int argc, char* argv[])
{
       // LuaのVMを生成する
       lua_State *L = lua_open();
       // Luaの標準ライブラリを開く
       luaL_openlibs(L);

       (略)

       // LuaのVMを閉じる
       lua_close(L);
       return 0;
}
lua_open()とluaL_newstate()は同じ関数。

ビルドの際にでる問題

LINK : warning LNK4098: defaultlib 'LIBCMT' は他のライブラリの使用と競合しています。/NODEFAULTLIB:library を使用してください。
[構成プロパティ]>[C/C++]>[コード生成]>ランタイムライブラリを/MDdから/MTに変更で警告は出なくなる。
正しい解決方法は
  • LuaのライブラリをCRT毎に6種類全部ビルドする
  • #ifdefと#pragma comment(lib,~)で自動的にそれを選択するヘッダを作る
らしい。が、よくわからないので放棄。動くしいいよね。
【Lua】組み込み系言語総合【Squirrel】の437-442より)

関数群


スタック管理

  • スタックの内容を出力する
// スタックの指定インデックスのアイテムの内容を表示する
static void PrintStackItem(lua_State *L, int idx)
{
int type = lua_type(L, idx);
switch(type){
case LUA_TSTRING:
	// 文字列アイテムの内容表示
	printf("index %2d : type=%s : \"%s\"\n",
	idx, lua_typename(L, type), lua_tostring(L, idx));
	break;
case LUA_TNUMBER:
	// 数値アイテムの内容表示
	printf("index %2d : type=%s : %f\n",
	idx, lua_typename(L, type), lua_tonumber(L, idx));
	break;
case LUA_TBOOLEAN:
	// ブール値アイテムの内容表示
	printf("index %2d : type=%s : \"%s\"\n",
	idx, lua_typename(L, type), lua_toboolean(L, idx)?"true":"false");
	break;
default:
	// その他ならば型だけ表示
	printf("index %2d : type=%s\n", idx, lua_typename(L, type));
	break;
}
}

// スタックのアイテムの内容を一覧で出力する
void PrintStack(lua_State *L)
{
printf("----- stack -----\n");
int top = lua_gettop(L);
// 正のインデックスで指定
for(int i = top; i>=1; i--){
	PrintStackItem(L, i);
}
printf("-----------------\n");
for(int i = -1; i >= -top; i--){
	PrintStackItem(L, i);
}
printf("-----------------\n");
}
  • スタック要素数の管理
// 現時点のスタックに積まれている要素数を記録しておく
int top = lua_gettop(L);
(スタック操作)
// スタックの要素数を元に戻す
lua_settop(L, top);

グルー関数

  • 基本的なグルー関数の作り方
(略)
// Sample
int Sample(int i)
{
       return i+1;
}
// グルーコード
int SampleGlue(lua_State *L)
{
       printf("Sample() 関数実行\n");
       // スタック表示
       PrintStack(L);
       // 引数を取得
       int index = (int)lua_tonumber(L, 1);
       // 目的の関数を実行
       int sample = Sample(index);
       // スタックをクリア
       lua_settop(L,0);
       // 返り値を格納
       lua_pushnumber(L, sample);

       return 1; // 返り値の数(1個)
}
  
int main(){
       (略)
       // C関数を登録
       lua_registre(L, "Sample", SampleGlue);

int ret = luaL_dostring(L, "print(Sample(5))");
if(ret != 0){
	// エラー処理
	printf("error: %s\n", lua_tostring(L,-1));
	lua_pop(L,1);
}
       (略)
}
returnで、返り値の数を返す理由がよくわからないんですが、いったん放置で。
  • マクロとして設定されている定数をLua内のグローバル変数に設定する方法
// DEFINEの数値をLuaのグローバル変数DEFINEにセット
lua_pushnumber(L, DEFINE);
lua_setglobal(L, "DEFINE");
lua_setglobal
void lua_setglobal (lua_State *L, const char *name);
スタックから値を取り除き、それをグローバル変数 name の新しい値として設定する。これはマクロとして定義されている。
  • 変数のバインドの方法
Get/Set関数を作成し、Luaに公開することで、変数をバインドできる
static int a = 0;
int GetNumber()
{
       return a;
}
void SetNumber(int b)
{
       a = b;
}
int GetNumberGlue(lua_State *L)
{
       int temp = GetNumber();
       lua_settop(L, 0);
       lua_pushnumber(L, temp);
       return 1; // 返り値1つ
}
int SetNumberGlue(lua_State *L)
{
       int index = (int)lua_tonumber(L,1);
       SetNumber(index);
       lua_settop(L, 0);
       return 0; // 返り値なし
}
これらの関数をmain関数内でlua_registerしていけばいい。
  • スクリプトのロードを実行を切り分ける
Lua側全体を関数としてくくり、呼び出しはlua_pcallを使う。
lua_getglobal(L, "Sample");
int ret = lua_pcall(L, 0, 0, NULL);
スタックに変数(この場合関数)を積んで、呼び出す。

タグ:

+ タグ編集
  • タグ:
最終更新:2009年02月16日 21:07