全日本ゲーム開発者連合 第 3 回交流会 Squirrel を用いた幸せなゲーム開発 q@nonoil( 理科大 ) 全体の流れ ・自己紹介 ・ Squirrel って何さ? ・動的リロード。問題と解決 ・デモ ・快適なスクリプティングのための Tips ・まとめ 自己紹介 ・自己紹介 ・ Squirrel って何さ? ・動的リロード。問題と解決 ・デモ ・快適なスクリプティングのための Tips ・まとめ 自己紹介 このスライドでは割愛させて頂きます。 Squirrel って何さ? ・自己紹介 ・ Squirrel って何さ? ・動的リロード。問題と解決 ・デモ ・快適なスクリプティングのための Tips ・結び Squirrel って何さ? (1/6) ・ Lua 、 xtal 、 AngelScript 、などのような 他の言語に組み込まれる用途のスクリプト。 ・読みは英語講師談だと「すくわぁれる」。 今回は「スクイール」で統一します。 ・「ゲームでスクリプト」というと、間違いなく Lua 。 ・最近、他のスクリプトでも採用事例が出初めてきた。 ・今回話す Squirrel は FF クリスタルクロニクルに 2 回連続で採用されたりして注目を浴びています。 Squirrel って何さ? (2/6) ○ 特徴 1 整数と浮動小数点が別。 ・ Lua は double のみ。 ・ double が、 16 桁程度の範囲をカバーできるた め、別途 int(10 桁 ) が不要だと Lua の作者はメーリ ングリストで弁解していた。 ・ DirectX では明示的に設定しないと double が float に。 ・ので int と float が別なのはうれしい。 Squirrel って何さ? (3/6) ○ 特徴 2 メモリ管理 ・ Lua は GC( ガーベッジコレクション ) を用いている これはリアルタイムなゲームだとちょっと問題。 ( 最新の Lua だとインクリメンタル GC というのが あるらしいが。。。 ) ・ Squirrel では GC+ 参照カウンタ方式 ・オプションで参照カウンタのみにでもできる。 循環参照が嫌なので、多分やめたほうがいい。 Squirrel って何さ? (4/6) ○ 特徴 3 その他 ・明示的なグローバル変数 ・コルーチン ・例外 ・テーブルと配列が別 ・継承 ※ 今日話す動的リロードは機能としては 組み込まれていません。 Squirrel って何さ? (5/6) ○ 短所 ・ ( まともな ) デバッガがない。 Lua の Decoda に比べるとまだまだ完成度低い。 クリスタルクロニクルでは、 スタックダンプ +print デバッグのみだったらしい。 ・参照カウンタを用いている分実行速度は犠牲に。 Squirrel って何さ? (6/6) ○ 今日、やらないこと。 ・他の組み込み言語との比較。 ・ Squirrel 自体の実装について。 ・バインドコードの生成などの儀式。 ○ 今日、やること。 ・動的リロードについて。泥臭い解決策について。 ・スクリプティング Tips 動的リロード。問題と解決 ・自己紹介 ・ Squirrel って何さ? ・動的リロード。問題と解決 ・デモ ・快適なスクリプティングのための Tips ・結び 動的リロードとは? すごいローカル用語な気がするので説明。 ・ゲーム”起動中に”スクリプトをロードし直すこと。 ・ゲームをプレイしながら、製作することができます。 ・ゲームをプレイしながら、調整ができます。 ・再コンパイルの必要がありません。 ・ ( ほとんどの場合 ) 一部だけをリロードするため、 リロードもほとんど時間がかかりません。 やったね。 動的リロード大まかな流れ 1. 全てのスクリプトファイルのタイムスタンプを記録 2. たまにタイムスタンプを確認し、 新しくなっていたら、リロード デバッグ用のリロードボタンが押された、 ウィンドウがアクティブになった等々のタイミング がいいと思います。 結構簡単そうです。よかった。 動的リロードの問題と解決 (1/9) いくつか問題があります。 動的リロードの問題と解決 (2/9) 1. リロードされる前のクラスのインスタンスを 参照しているのところを新しいのに置き換える。 2. リロードされる前のクラスのインスタンスが 参照していたものを新しいインスタンスに渡す。 動的リロードの問題と解決 (2/9) 図にするとこんな感じ。 ・武器が新しくなったことを キャラクタが知るには? ・武器がもともと持っていた マテリアを継続するには どうしたらいいか? 動的リロードの問題と解決 (3/9) 解決策は色々あるようです。 1. 丸ごとシリアライズ、デシリアライズ 2.Squirrel のソースを弄る。 3. 全スクリプトを読み直してしまう。 4. 部分的にリロード 1,3 は、少し大げさです。 2 は見当もつかない。 4 を今回はチャレンジしてみました。 動的リロードの問題と解決 (4/9) 1. リロードされる前の クラスのインスタンスを 参照しているのところを 新しいのに置き換える。 ( 武器が更新されたことを キャラクタが気づく ) 動的リロードの問題と解決 (5/9) 1. 普通にリロードするだけで OK? ・古いインスタンスは、そのまま残っています。 これをした後に、ちゃんと置き換えないとだめ。 2. 古いインスタンスかを逐一判定していく。 ・ルートテーブルから再帰的に、 onReload() OnReload() 内でリロードされたクラスかを判定。 ・クラス名の判定は GetName() メンバ関数 ( ルートテーブル内のクラス定義はリロード後 は上書きされているので利用できません。 ) 3. 古いものだとわかったら、新しくコピー。 動的リロードの問題と解決 (6/9) ○ 下準備 (1/2) クラスをファイル単位で分割したいので、下準備。 ・ import 拡張 「 //import hoge.nut 」 と書くと、そのファイルが事前に読み込まれる。 単純に文字列として挿入してもいいですが、 ファイルごとに sq_compilebuffer を連続して 使っても問題ありません。 ・全てのスクリプトファイルは「クラス名 .nut 」 にする。 例 )/*hoge.nut*/class hoge{} 動的リロードの問題と解決 (7/9) ○ 下準備 (2/2) ・全クラスに GetName() をつけます。 これはクラス名を文字列で返します。 ・全クラスに onReload() をつけます。 1. 全てのメンバー変数のインスタンスの onReload() を呼び出します。 2. リロード対象クラスかを判定し、古い場合は 新しいものに上書きします。 3. このとき、専用のコピーを呼び出します。 ( 後述 ) cloud_ = Cloud.copy(cloud_) 動的リロードの問題と解決 1 (8/9) ○ 実際の流れ (1/2) ・ターゲットのファイルのリロード (C++) ↓ ・ sq のグローバル関数 onReload(strClassName) を呼び出し ↓ ・ルートテーブルにある全インスタンスに対して onReload( strClassName ) を呼び出す。 (sq) ↓ ・インスタンスとなっているメンバー変数の onReload( strClassName ) を呼び出す。 (sq) 動的リロードの問題と解決 1 (9/9) ○ 実際の流れ (2/2) ・インスタンスであるメンバー変数の onReload( strClassName ) を呼び出す。 (sq) ↓ ・ onReload() 内で、古いインスタンスだとわかったも のを新しくし、メンバー変数の onReload() を呼び出 す。 (sq) ※Lua ではクラス=テーブルなので、メンバー関数に onReload を作らなくても、勝手に回して同じことがで きそうですが、 squirrel ではインスタンスに対して foreach はできないため、手動で作成しています。 ( メタメソッドを使えばできますが。。。 ) 動的リロードの問題と解決 2 (1/3) 2. ロードされる前のクラス のインスタンスが参照して いたものを新しい インスタンスに渡す。 ( 直前まで使っていた マテリアを継続して使う。 ) 動的リロードの問題と解決 2 (2/3) 単に古いインスタンスに上書きするだけだと、 メンバー変数が渡せません。 × ragnarok_ = Ragnarok() 対処法として、 ・ Copy 関数 (Clone 関数 ) を作る のは間違いないのですが、メンバー変数の数が変化する ことを念頭に入れなくてはいけません。 案 1. 可変長引数にし、メンバー全てを渡す。 引数の数でバージョン管理。 案 2. 「 in 」を利用する。 1 はちょっときついです。 2 を使います。 動的リロードの問題と解決 2 (3/3) ・ in とは、クラス / テーブル内にその要素があるかを 教えてくれるものです。 /*Ragnarok::copy()*/ /* マテリアが前のバージョンであるなら、それを使う。 */ if( "materia_" in oldRagnarok ) { newRagnarok.materia_ = oldRagnarok.materia_; } 全てのメンバー変数に関してそのメンバー変数が 「あったか?」を判定していきます。 デモ ・自己紹介 ・ Squirrel って何さ? ・動的リロード。問題と解決 ・デモ ・快適なスクリプティングのための Tips ・結び デモ このスライドでは割愛させていただきます。 Tips ・自己紹介 ・ Squirrel って何さ? ・動的リロード。問題と解決 ・デモ ・快適なスクリプティングのための Tips ・結び Tips ・初期化コンストラクタを使おう。 ・文字列はなるべく加工しない。 ・アロケーターは何か別のものに置換しよう。 ・テーブルより配列を ・空行が最速 ・保守の観点から悪名高いハンガリアン記法を使おう → Making Wrong Code Look Wrong. (Joel on software) (http://www.joelonsoftware.com/articles/Wrong.html) ※ 詳細は省きます。推測してください。 まとめ ・自己紹介 ・ Squirrel って何さ? ・動的リロード。問題と解決 ・デモ ・快適なスクリプティングのための Tips ・まとめ まとめ ・スクリプトすばらしい。 ・ Squirrel でもなんとか動的リロードできます。 ・でも下準備がかなり手間。 ・多分もっとスマートな方法はあります。 理解が容易であること (≒ 実装が簡単 ) との費用対効果を考えるとこれでも 悪くはないとも思ってます。 ・ですが、私はまだ Lua を使います。 もし誰かがデバッガを作るなら ....... ああ , 終わった 終わった .. ご清聴ありがとうございました 参考文献など ・ Squirrel (http://squirrel-lang.org/) ・ SqPlus (http://wiki.squirrel-lang.org/default.aspx/SquirrelWiki/SqPlus.html) ・ Squirrel 2.2 リファレンスマニュアル (http://muffin.cias.osakafu-u.ac.jp/~matumoto/cgi-bin/xt.cgi?prog/squirrel_lang) ・ Lua/ 組み込み言語 wiki (http://wikiwiki.jp/lua/) ・ Squirrel のデバッグ API (http://practical-scheme.net/wiliki/wiliki.cgi? デバッガ : デバッグ API の実例 #H-tvtiv6) ・ Joel on software (http://www.joelonsoftware.com/) ( 書籍 http://www.amazon.co.jp/More-Joel-Software-Spolsky/dp/4798118923/ )
© Copyright 2024 Paperzz