
AngelScriptという組み込み用途のスクリプト言語を弄ってて、とても素晴らしいと思ったのだけれど、(国内では)マイナーなのかあまり目ぼしい資料が見当たらなかったので数回に分けてブログ記事にしてみる。(全ゲ連でSquirrelをやった直後にこれというのはなんともという感じだが。。。)
AngelScript(正式名称「AngelCode Scripting Library」以下AS)とは、Andreas J?nsson氏が2003年あたりから(※1) 開発している(恐らく)ゲーム用途(※2)の組み込みスクリプト。まずはフューチャーというか自分的うれしい点を列挙してみる。
・静的型付!!!
・スタックでごにょごにょやならなくていい!!
・開発頻度が今超Hot!
・C/C++ライクな構文。クラスは当たり前のようにあり、名前空間(Module)がサポートされている。
・当たり前のようにintとfloatは別
・バインダが付属
・インターフェイスがC++。(Cも選べる)
・コルーチン
・スレッドセーフ
・参照カウンタと、GC。循環参照時のみGC(?)
・かなり自由な値のC/C++⇔ASのやりとり。
・デバッガ用インターフェイスが親切(??)
やはり一番目を引くのは静的に型付けできる点。他の組み込みスクリプトで有力なLuaとSquirrel、そしてxtalは全て動的型付け。ObjectiveCに触れて多少は考えが変わったけれどそれでもやはりできるならば静的に型をつけてくれるとうれしい。動的なばかりに付け足されるテストや、保守に気を張らないといけないというのはどうも納得いかない。次にうれしいのが、スタックでごにょごにょやらずに直接引数を指定できる点。なんだがよくわからない(≒だんだんわからなくなってくる)スタック操作から解放される。最後にもしかしたらこれが一番重要かもしれないけれど、(他の有力なスクリプトと比較して)アップデートがかなり頻繁に行われている点。(※3)
今回はとりあえずHellowWorldまで持っていくことに。
現在最新版のAngelScript 2.17.1 (September 16th, 2009)を利用する。ダウンロード⇒パス通しは割愛するとして、ASで「Hellow world!」をする最小のコードを書いてみる。
#include <cstdio>
#include <angelscript.h>
#include "scriptstring.h" /*最初からついているAngelScriptのアドオン*/
#ifdef _DEBUG
#pragma comment(lib,"angelscriptd.lib")
#else
#pragma comment(lib,"angelscript.lib")
#endif
/**/
void MessageCallback(const asSMessageInfo *msg, void *param)
{
const char *type = "ERR ";
if( msg->type == asMSGTYPE_WARNING )
type = "WARN";
else if( msg->type == asMSGTYPE_INFORMATION )
type = "INFO";
printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message);
}
/**/
void Print( std::string& value )
{
puts(value.c_str());
}
/**/
int main(int argc, char **argv)
{
int r;
asIScriptContext *ctx = NULL;
asIScriptEngine *engine = NULL;
engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
if( !engine )
return -1;
/*コンパイラメッセージの設定*/
r = engine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL);
if( r < 0 )
goto EXIT;
/*addonにあるstringの登録。const char* は使えないため。*/
RegisterScriptString(engine);
/*printの設定*/
r = engine->RegisterGlobalFunction("void Print(string &in)", asFUNCTION(Print), asCALL_CDECL);
if( r < 0 )
goto EXIT;
/*スクリプト本体*/
const char* scriptString =
"void hellow()"
"{"
" Print( \"hellow world\" );"
"}";
/*モジュールを作成し、スクリプトをコンパイル*/
asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
r = mod->AddScriptSection("script", scriptString, strlen(scriptString) );
if( r < 0 )
goto EXIT;
r = mod->Build();
if( r < 0 )
goto EXIT;
if( r < 0 )
goto EXIT;
/*実行するためのコンテキストを作成する*/
ctx = engine->CreateContext();
if( !ctx )
goto EXIT;
/*関数を検索する*/
int funcId = engine->GetModule(0)->GetFunctionIdByDecl("void hellow()");
if( funcId < 0 )
goto EXIT;
/*実行前にその関数を準備。これは一番最初だけやればよい。*/
r = ctx->Prepare(funcId);
if( r < 0 )
goto EXIT;
/*実行*/
r = ctx->Execute();
if( r != asEXECUTION_FINISHED )
puts("失敗");
else
puts("成功");
EXIT:
if( ctx ) ctx->Release();
if(engine) engine->Release();
return 0;
}
これでとりあえずhellowworldができると思う。他の言語と違って面白いのが関数呼び出しがすべて文字列で完結するという点。テンプレートを使ったばかりに地獄を見るということがかなり避けられる。またバインドが失敗すると、コンパイル時に知らせてくれるのもうれしい。次回は、クラスのバインドについて触れたいと思う。
参考:
プログラム/AngelScript L.I.W.
※1 0.*系の一番最初のChangeLogが2003年になっている。
※2 こちらに利用例が掲載されている。
※3 ここをみると一月一回更新という鬼のような速度で更新されています。