Squirrel - 全日本学生ゲーム開発者連合(全ゲ連)資料置き場

全日本ゲーム開発者連合 第 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/ )