読者です 読者をやめる 読者になる 読者になる

プログラミングの魔物

エラー、バグ、仕様変更と戦うブログ

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

スクリプト言語による効率的ゲーム開発 5章

5章はどのような内容かというと、VistualStudioでLuaを組み込む所から始まり、RPGに出てくるような「道具屋」をテキストベースで作成する。
この章にはC関数をLuaへ公開するためのグルーコードを自分で組む手順も載っている。

Luaの組み込み方

VisualStudioでの組み込み方と、サンプルプログラム上でLuaをオープンする方法が載っている。

スタック

C言語Luaの間で値をやり取りするためのもの。
Luaのスタックは文字だけではイメージしづらいが、本は図が載っているので分かりやすい。

はてな記法のテーブルを使って説明するとこんな感じ

スタックのイメージ

データ インデックス(正) インデックス(負)
400 4 -1
table 3 -2
123.45 2 -3
"one" 1 -4

Lua

hoge("one", 123.45, {}, false)

C言語

//スタックトップのインデックス(=要素の数)
printf("%d\n", lua_gettop(L));     // 4

//要素を取得して表示
printf("%s\n", lua_tostring(L, 1));   // one
printf("%d\n", lua_tointeger(L, -1));  //400  (スタックトップの要素)

スタック外のオブジェクトにアクセスする擬似インデックス

  • LUA_GLOBALSINDEX
  • LUA_REGISTRYINDEX
  • LUA_ENVIRONINDEX(Lua5.2では削除)
  • lua_upvalueindex(n)

スタックが増えるタイミング

ステート作成時やスクリプトからスクリプトを呼んでその中でC関数を呼び出した時などに作られる。デフォルトのスタックサイズは20個なので気をつける。

自動リロード

スクリプトロード時にエラーが起きたら、入力待ちのウェイト後にリロードするような状態にしておくと楽。

エラー処理関数

lua_pcallでエラー処理関数を指定できる。標準ライブラリにあるエラー処理関数はdebug.traceback

C言語の関数をLuaで使えるようにする(バインド)

C言語の関数はそのままの状態ではLuaで使うことができない。
そこで、Luaの様式に合わせるための中継関数(グルーコード)を用意する必要がある。

とりあえずグルーコードの例の1つを載せておく。

//hogeListから数値を取得するC関数
int GetHoge(int index){
  if (index < 0 || index >= hogeList.size()) return -1;
  return hogeList[index];
}

//GetHogeのグルーコード
int GetHogeGlue(lua_State *L){
  int index = (int)lua_tonumber(L, 1);  //Lua側から渡された引数を取得
  int hoge = GetHoge(index);  //GetHoge実行
  lua_settop(L, 0);
  lua_pushnumber(L, hoge);  //Lua側へ返す値
  return 1;  //返り値の数
}

//ステートを作成した後、LuaにC関数を登録する
lua_register(L, "GetHoge", GetHogeGlue);

あと5章ではtolua++の使い方が書かれている。これは以前に記事を書いているのでそちらを参照。
tolua++を使うと上記のグルーコードを自動生成できる。
tolua++の使い方(主にMac) - プログラミングの魔物

Luaヘルパークラス

本のおまけのようなもの。次の機能を持つ

  • Lua関数の呼び出し、Luaスクリプトファイルの実行
  • スタック操作不要
  • 簡潔に記述できる
  • 引数・返り値には数値、文字列、ブール値、nil値を扱える
  • エラーメッセージの取得

この記事で読み進めている本

スクリプト言語による効率的ゲーム開発 新訂版 (LuaとC/C++連携プログラミング)

スクリプト言語による効率的ゲーム開発 新訂版 (LuaとC/C++連携プログラミング)