Lua スクリプトによるゲーム開発、はぢめました

冬コミに向け本格的なゲーム製作をするにあたって、常々思っていた「なんかスクリプトっぽい言語を組み込めると面白いなぁ」的アイデアが実現できそうなので報告。
使う言語は、候補としては PythonPerlRuby なんかがあったわけですが、今回は Lua を選択。決め手となったのは corutine の存在で、こいつを使えば弾幕スクリプトっぽい記述が簡単に出来そうだったから。ついでに言うと、こいつは C/C++ 言語と組み合わせてプログラミングする前提で言語が作られているため、C言語関数とかが比較的楽に呼び出せるっぽい。さらに副次的なメリットとして、スクリプト言語の中ではトップレベルの高速性も持つという。うむ、ゲーム組み込みには最適だなぁ。



つーわけで早速インストール。環境は cygwin を使うので、公式サイト(http://www.lua.org/)からソースコードを落として来て手動で make する。どうやら最新版のバージョンは 5.1.4 らしいので、適当なフォルダで

fget http://www.lua.org/ftp/lua-5.1.4.tar.gz
tar -zxfv lua-5.1.4.tar.gz

って感じでダウンロード&解凍(もちろん cygwin からダウン&解凍する必要は無いけど、コマンドラインでやった方が格好いいよね)。
んで make して install するわけだが、このときプラットフォームを指定する必要があるっぽい。調べてみたところ、どうやら cygwin では posix を指定するのがベストのようだ。
がしかし、posixコンパイルした場合、出来上がった実行ファイルが cygwin 上でしか実行できなくなってしまう(あるいは DLL を用意する必要がある)という欠点がある。ゲーム開発ではそれは嫌なので、なんとかして -mno-cygwin コンパイラオプションをつけて実行したいところだ。それには、このように入力する:

make CC='gcc -mno-cygwin' mingw
make test
make install

参考サイト様: http://lua-users.org/lists/lua-l/2008-02/msg00120.html
これにより -mno-cygwin オプションに対応した lua 環境が整えられる・・のだが、このままでは実はうまくいかない。 gcc に -mno-cygwin オプションをつけて実行した場合、ヘッダやライブラリが参照されるパスは /usr/local/include や /usr/local/lib ではなく /usr/i686-pc-mingw32/include や /usr/i686-pc-mingw32/lib なので、必要なヘッダやライブラリは適当にそちらにコピー。んでさらに、-mno-cygwin オプションをつけない場合にもコンパイルが通るようにするため、今度は普通に

make clean
make posix
make test
make install

とかやってインストールする。これで完成。


早速テスト。まずテスト用の hello.lua を適当に作って

-- hello.lua

-- 普通の実行のテスト
print( "Hello, world!" )

function f()	-- C/C++ からの関数呼び出しテスト
	print( "called f()." )
end

ちょいちょいと実行。

lua hello.lua

次は C++ から呼び出す。test.cc を適当に作って

#include "lua.hpp"

#include <iostream>
using namespace std;

int main()
{
	// スクリプト名、関数名
	char *filename = "hello.lua", *funcname = "f";
	
	// Lua インターフェイスを開く
	lua_State* L = lua_open();
	
	// Lua 標準ライブラリを読み込ませる
	luaL_openlibs(L);
	
	clog << "loading file '" << filename << "':\n" << endl;
	
	// ファイル実行
	int top = lua_gettop(L);
	if( luaL_dofile( L, filename ) != 0 )
	{
		cerr << "error: " << lua_tostring( L, -1 ) << endl;
	}
	lua_settop( L, top );
	
	clog << "\ndone.\n";
	clog << "calling function '" << funcname << "':\n" << endl;
	
	// 関数実行。事前に関数定義の書かれたスクリプトを実行しておく必要あり
	top = lua_gettop(L);
	lua_getglobal( L, funcname );
	if( lua_pcall( L, 0, 0, 0 ) != 0 )
	{
		cerr << "error: " << lua_tostring( L, -1 ) << endl;
	}
	lua_settop( L, top );
	
	clog << "\npress any key to continue...";
	getchar();
	
	// 後処理
	lua_close(L);
}

コンパイル。注意すべき点は liblua.a をリンクさせる事くらい。

g++ test.cc -llua

出来上がったファイルを実行。ちゃんと動いてるっぽいのでOKってことにしよう。うむ。
もちろん -mno-cygwin オプションをコンパイラに渡せば、 cygwin なしでの実行も可能。これでゲーム製作が楽になりそうだ。