Hatena::Groupiphone-dev

とあるiPhone開発者とゲームエンジン このページをアンテナに追加

2011-02-14

Cocos2dへSquirrelを組み込み

02:31 |  Cocos2dへSquirrelを組み込み - とあるiPhone開発者とゲームエンジン  を含むブックマーク はてなブックマーク -  Cocos2dへSquirrelを組み込み - とあるiPhone開発者とゲームエンジン

RPGに使う敵AIには組み込みスクリプトが必要なんじゃなかろうか?

ということでCocos2dのテンプレートSquirrelを組込んでみることにしてみた。

ダウンロード&展開

調べてみると3.0 betaが出てるようだ。

ひとまず squirrel_3_0_beta3.tar.gz をダウンロードして使ってみることにする。

ダウンロードしたファイルを解凍すると、以下の画像の様にフォルダのアクセス権がロックされてて中を見る事ができない。

f:id:saika_makoto:20110215013508p:image

フォルダを選択して Command + i でフォルダ情報を表示し、everyone に読み/書き権限を設定する。このままだと下位のフォルダの権限は変更されないため、下のギアアイコンから「内包している項目に適用」を選択して全てのフォルダ権限を変更する。

f:id:saika_makoto:20110215013509p:image

これで使用準備完了。


Cocos2dプロジェクトへの組み込み

Cocos2dから生成されるテンプレートのlibsフォルダの下に先ほど展開したSQUIRREL3フォルダをコピーする。

そして、cocos2d Sourcesフォルダ内に新規にSQUIRREL3グループを作成し、更にその中に以下の表の様なグループを作成しファイルをドラッグ&ドロップで追加する。

グループ名コピーするファイル
SQUIRREL3/include libs/SQUIRREL3/include 内の全ファイル
SQUIRREL3/squirrel libs/SQUIRREL3/squirrel 内の全ファイル
SQUIRREL3/sqstdlib libs/SQUIRREL3/sqstdlib 内のsqstdrex_old.cppを除いた全ファイル

sqstdrex_old.cppを入れておくとコンパイル時にエラーになるので外した。

f:id:saika_makoto:20110215015129p:image

最後にヘッダファイルの検索パスに libs/SQUIRREL3/include を追加する。

f:id:saika_makoto:20110215015130p:image

これで組み込みは完了。


Object-CからSquirrelスクリプトの呼び出し

テストするスクリプトはこんなカンジ。

仮に test.nut とでも名付けようか。

        function foo(i, f, s) 
        { 
            print("Called foo(), i="+i+", f="+f+", s='"+s+"'"); 
        } 

ここからはCの実装になる。

最初にVMマシンを生成する。

HSQUIRRELVM v = sq_open(1024);  //1024はコールスタックサイズ

続いて、エラーレポートやprintの出力先関数を登録する。

sqstd_seterrorhandlers(v);
sq_setprintfunc(v, printfunc, printfunc); //sets the print function

プリント関数は以下のようになる。

        void printfunc(HSQUIRRELVM v, const SQChar *s, ...) 
        { 
                va_list arglist; 
                va_start(arglist, s); 
                scvprintf(s, arglist); 
                va_end(arglist); 
        } 

続いて、VMマシンにスクリプトファイルを読み込ませる。

sq_pushroottable(v);
sqstd_dofile(v, "test.nut", 0);

読み込みに成功したら、スクリプト関数のfoo()を呼出してみよう。

void call_foo(HSQUIRRELVM v, int n,float f,const SQChar *s)
{
    int top = sq_gettop(v); //saves the stack size before the call
    sq_pushroottable(v); //pushes the global table
    sq_pushstring(v,_SC("foo"),-1);
    if(SQ_SUCCEEDED(sq_get(v,-2))) { //gets the field 'foo' from the global table
        sq_pushroottable(v); //push the 'this' (in this case is the global table)
        sq_pushinteger(v,n); 
        sq_pushfloat(v,f);
        sq_pushstring(v,s,-1);
        sq_call(v,4,0); //calls the function 
    }
    sq_settop(v,top); //restores the original stack size
}

かなり端折って説明してしまったので、より詳細な解説を知りたい人は以下の資料を参考にしてみてください。

SquirrelスクリプトからC関数の呼び出し

ついでにスクリプトからC関数を呼出す方法。

、、、眠いので詳細は後ほど。


SquirrelPythonの比較

組み込みスクリプトの候補としてPythonも考えたがソースコード量が多い点がネックとなり、今回は見送りました。

種類 コードサイズ
Python ヘッダ+ソースで2MB程度
Squirrel ヘッダ+ソースで500KB程度

2MBもあったらゲーム本体のソースより多くなりそうな気がする。。。



組み込み済みのプロジェクト

今回の説明のためにCocos2dのテンプレートSquirrelを組込んでみたサンプル。

HelloWorldScene.mの-(id) initからtest.nutをロードしてfoo()関数を呼出しています。

https://files.me.com/penguin.dream/pzk5zm

※リンクは3ヶ月間のみ有効です。