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,~)で自動的にそれを選択するヘッダを作る
関数群
スタック管理
// スタックの指定インデックスのアイテムの内容を表示する
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