本文書では、吉里吉里/KAGを題材に、スクリプタの方々を対象として、ノベルゲームの システムの作り方について述べる。
正直に言えば、書きたいのは「作り方」なんて大それたものではなくて、 以下で述べる「『システム』の目的」を達成するために、 『何をどう用意したら効率的か』を、 経験則を絡めながら備忘録的にメモしたものだと思って頂ければ幸いであるよ。 とはいえ、我輩が今まで作成してきたノベルゲームでは全て同じ構成を採用しており、 特に大きな不具合も出ていないことから、そこそこ汎用性はあると考えている。 というかそう信じたい。
現実社会で、 ダメプログラマのダメプログラムに仕込まれたダメバグに いつも悩まされているためか、 やたらと愚痴っぽい文章になっていることにはご容赦頂きたい。
『システム』とは、目的を効率よく達成するための手段を提供する「系」である。 従って、ノベルゲームにおける『システム』は、 ノベルゲームを効率よく製作・完成させる「系」であり、 それ以外であってはならない。 この定義はよく覚えておく必要がある。システムを設計する場合、 この定義に合致しない設計思想を導入してはならない。簡単だけど忘れがち。
ノベルゲームはシナリオテキストだけで作られるわけではない。立ち絵、表情、背景、 メッセージウィンドウ、パラメータウィンドウ、BGM、SEなどなど、さまざまな 素材を、スクリプトでつなぎ合わせて作られている。 とはいえ、ただつなぎ合わせるだけなら、 スクリプトを書く上でノウハウなど要らないし、システムなんてものも不要だ。 スクリプト中に、単純に絵や音を順次表示・再生していくようにベタ書きすればいい。
しかし、世の多くのノベルゲームはそうなっていない。何故か?それがすなわち、 『システム』を作る理由である。システムを作ることにより、 以下の三点が実現できる。
判りやすい例を示そう。メッセージ枠の表示と消去について考えてみる。 通常メッセージ枠の大きさや表示位置は決まっている。だったら、表示のたびに
(snip) ; メッセージ枠を表示 [backlay] [position layer=message0 page=back visible=true frame="メッセージ枠" left=24 top=427 width=580 height=171 marginl=59 margint=12 marginr=42 marginb=16] [trans method=crossfade time=200][wt] [current layer=message0 page=fore] (キャラクタ表示、セリフ表示など) ; メッセージ枠を消去 [backlay] [position layer=message0 page=back frame="" color=0 opacity=0] [trans method=crossfade time=200][wt] (別キャラクタ表示) ; メッセージ枠を表示 [backlay] [position layer=message0 page=back visible=true frame="メッセージ枠" left=24 top=427 width=580 height=171 marginl=59 margint=12 marginr=42 marginb=16] [trans method=crossfade time=200][wt] [current layer=message0 page=fore] (更にシナリオは続く) |
…などとスクリプト中に書くのは無駄の無駄無駄だし、コピー&ペーストしたとしても 間違いも入り込みやすい。 それよりは、上の一連のスクリプトをマクロ化する方がいい。 [メッセージ枠表示]及び[メッセージ枠消去]というマクロを定義し、
(snip) [メッセージ枠表示] (キャラクタ表示、セリフ表示など) [メッセージ枠消去] (別キャラクタ表示) [メッセージ枠表示] (更にシナリオは続く) |
のようにマクロを使った方が、タイプ量は減るし、後から見てわかりやすくなるし、 バグも混入しにくくなくなるし、 メッセージウィンドウの大きさや場所を変更した場合にも、 一箇所(マクロ定義の中)を修正すればゲーム中全てに反映できて メンテナンス性も飛躍的に向上する。生産性が向上するいいことずくめ。
モノスゴい演出が画面上でぐりんぐりん動く…のは、実はシステムの目的ではない。 システムとは須らく地味なものである。 『いかに使う側(ここでは上位のスクリプト)が楽になるようにするか』、 これがシステム化への第一歩だ。 「こういうタグが吉里吉里/KAGにあればいいのに」と思ったなら、 それをマクロ化することを考えてみよう。 それが即ち、『使う側に優しいシステム』的な発想だ。
本当はデバッグの仕方にも、テストクライテリア決めてー、チェックリスト書いてー、 モジュールテストしてー、プログラムテストしてー、トータルテストしてー、 のような方法論はあるけれど、今回はそこまで書かない。とりあえず、 『デバッグも下層から実施する』ことだけ知っておけばいい…んじゃ…ないか…な?
まずは、設計が必要だ。設計とは、難しく言えば、要求分析し、 基本仕様・機能仕様・詳細仕様を纏めることだ。もっと簡単に言えば、 「何を実現したいのか」、「そのためには何を決めておかなければならないか」、 「最終的にどのような仕様にするか」 を明確にすること。我輩がいつも使っているシステムを例に、記述してみよう。
…などが守れれば、実現できると思ってみる。
これらのうち、1.は大体もう判ったので、以下では2.以降を考えていく。 まずは、ノベルゲームを構成する要素をばらばらに分解してみよう。
ノベルゲームを構成するものを、要素に分解するとどのようになるだろうか。 百論あるとは思うが、この文書では、大きく「絵」と「音」に分け、 それを更に以下のように分解してみた。
大項目 | 中項目 | 小項目 | 備考 |
---|---|---|---|
絵 | 背景 | 最背景 | 最も背面の背景 |
前景 | キャラクタ立ち絵よりも前に表示される背景 | ||
キャラクタ | 立ち絵 | 一画面に複数表示でき、画面上では横に並ぶものとする。一キャラに複数種類の立ち絵を許容する | |
表情差分 | 微笑、怒り、憮然、破顔など | ||
漫符 | 赤面、汗、#、!、?など | ||
システムテキスト | メッセージウィンドウ | 地の文やセリフを表示するウィンドウ | |
システムボタン | セーブ・ロード・早送りなどの画面上に表示されたボタン | ||
その他(画面上の日付窓など) | 画面デザイン毎に異なる | ||
音 | BGM | - | いわゆるBGM |
SE | - | いわゆる効果音 | |
キャラボイス | - | いわゆるキャラクタボイス | |
その他システム画面 |
| - | ゲーム毎に全く異なり、ほぼ毎回新規作成のため、今回は考慮しない |
このような要素に分解したら、中項目ごとに(小項目ごとでもいいが、 それだと細か過ぎる気がする)別々の細分化した管理システムを作り、 最後に全てを組み合わせて全体システムを構築することを考える。 即ち、中項目ごとにほぼ独立した管理システムを構築することとなる。 従って、これから構築する管理システムは、 上記ピンクで示した六つの中項目に「全体統括システム」を加えた、 以下の七つに分類される。
これらを階層的にあらわすと、こんなカンジになるだろう。 緑部分が今回「システム」と呼ぶ部分で、 シナリオスクリプトからは全てこの「システム」を通して 吉里吉里を操作するようにする。
ユーザ | |||||
シナリオスクリプト | |||||
全体統括システム | |||||
背景管理システム | キャラクタ管理システム | テキスト管理システム | BGM管理システム | SE管理システム | キャラボイス管理システム |
吉里吉里(KAG/TJS) |
大体どういう管理システムを作るかが決まったら、 管理システム毎にもう少し具体的な仕様を決める。 仕様が決まらないうちにスクリプトを作り出してはならない。 よほどプログラムに慣れた人で無い限り、ソラで書いたものが最終的にカッチリ 組み合わさってうまく動くことは決してない。どのようなものを作るかについて、 必ず文書を書くこと。
以下、例として、上の六つの管理システムのうち、 画像関係三システムと全体統括システムについて、 どのようなものを作るかを具体的に決めてみる。 シナリオとにらめっこしながら欲しい機能を列挙し、 管理システムのどこでそれを実装するかを分類すれば、自ずと表ができるはずだ。 以下に簡単な例を示す。
管理システム | 実装すべき機能 | 機能詳細 |
---|---|---|
背景管理システム | 背景表示 | 背景を表示・非表示する | 画面遷移 | [trans]タグを実行するラッパマクロ |
キャラクタ管理システム | キャラ表示 | キャラクタを画面上にフェード表示する | キャラ消去 | キャラクタを画面からフェード消去する | キャラ移動 | キャラクタの立ち位置を変更する | 全キャラ消去 | 画面上のキャラクタを全て消去する |
テキスト管理システム | メッセージ枠表示 | メッセージ枠をフェード表示する | メッセージ枠消去 | メッセージ枠をフェード消去する | 改行 | メッセージウインドウ内でテキストを改行する | 改ページ | メッセージウインドウ内でテキスト改ページする |
全体統括システム | 場面切替 | 場面を切り替える。表示されていた全キャラクタを消去し、メッセージ枠も消してから場面を切り替え、メッセージ枠を再び表示する | 全フェード | 背景・キャラクタ・テキストを全て同時にフェードする | キャラ表示・消去 | キャラクタを表示・消去する。表示前には自動的にメッセージ枠を消し、表示後には自動的にメッセージ枠を再表示する |
『実装すべき機能』で述べた機能は、 全て1マクロで実行できるように纏めるのが望ましい。 そうすることで、シナリオスクリプトのタイプ量が劇的に減少し、 後から読んでも判りやすいスクリプトになるからだ。
ということを前提に、以下、もう少し詳しい仕様を決めていく。
なお、ここで述べる要求仕様・マクロ仕様はそれぞれあくまで例であり、
異様に非常に簡単になっている。
実際にはもっともっと複雑で厳密な仕様定義が必要となることはご了承頂きたい。
[背景表示 画像=<背景画像> 時間=<指定>|1000 遷移=<false>|true] [画面遷移 時間=<指定>|1000] |
[キャラ表示 画像=<キャラ画像> 位置=<左|中央|右> 時間=<指定>|300 遷移=<false>|true] [キャラ消去 位置=<左|中央|右> 時間=<指定>|300 遷移=<false>|true] [キャラ移動 from=<左|中央|右> to=<左|中央|右> 時間=<指定>|300 遷移=<false>|true] [全キャラ消去 時間=<指定>|300 遷移=<false>|true] |
[メッセージ枠表示 遷移=<false>|true] [メッセージ枠消去 遷移=<false>|true] [nl] [np] |
シナリオスクリプトの殆どの動作は、このセクションに書かれたマクロだけで できるように、厳選しかつ高機能なマクロを定義すること。
[場面切替 画像=背景画像 遷移=<false>|true 時間=<指定>|1000] [全フェード 画像=背景画像 遷移=<false>|true 時間=<指定>|1000] [キャラ 画像=<キャラ画像> 位置=<左|中|右> 時間=<指定>|300] |
上記を実装した例を作成したので、 ダウンロードして試してみて欲しい。 吉里吉里の実行バイナリは入っていないので、 data ディレクトリが存在するディレクトリに krkr.exe(多分Ver2.30) をコピーして実行して欲しい。 first.ks を見て、シナリオスクリプトはここまで単純化できることを 知って頂ければ幸いであるよ。
リリース後は、ノベルゲームといえどメンテナンスモードに入る。 メンテナンスモードとは、「何も無い限り何もしない」モードだ。とはいえ、 致命的なバグが発見されたり、どうしても新機能を追加したいのであれば この限りではない。そういう場合、アップデートパッチを提供することになる。
しかし、だ。 いきなり否定してしまって恐縮だが、 本来、パッチなんてものは提供すべきではないことを知らねばならない。 これは『不具合を修正するな』と言っているわけではない。 そもそも最初から不具合を作りこまないようにせよ、と言っていると思って欲しい。
一般ゲームも含め、世の供給側の人々は、安易にパッチリリースに頼りすぎている。 何故最初からカンペキを目指さないのか、 何故目の前にある既知のバグを全て取り去る前にリリースしてしまうのか。 特に同人では締め切りは好きなだけ延ばせるのだから、 『冬がダメなら次の夏で』くらいの気持ちで、 既知の不具合が全て解消するまで、リリースを伸ばすべきだと思う。 どうしても取れないバグは、アナタの技術不足が原因だ。 それをユーザに押し付けるべきではない。
製品というものは世に出た瞬間から『製品』である。 全てをWebで、しかも無償で提供するので無い限り、 『製品』は変わらないからこそ『製品』なのであって、 パッチという形での機能・シナリオの修正・追加は極力すべきではない (ただし、 ネットワーク経由で接続されることが大前提になっているならこの限りではない)。 これには、本質的には以下のような理由がある。
パッチのリリース可否は、 以上の「ユーザに負わせるリスク」を熟考した上で判断することを強くお勧めする。 ユーザから要求があれば、アップデートが終了した完全版メディアを、 (元メディアと交換などの条件で)無償配布するくらいの覚悟で臨んで欲しい。
もうひとつ。スクリプタ・プログラマの評価は、以下の二つで絶対的に決まる。
ここには、バグの修正速度や修正の正確性は含まれない。 スクリプタ・プログラマは、バグを作りこんだ時点で圧倒的に負けだからだ。 バグは判明したら直せばいい、システムは後から改善すればいい、 と思っている人は、即刻スクリプタ・プログラマを降りて欲しい。 常に最善を目指す努力をしない人間は、製作現場には必要ない。 否、周囲の足を引っ張りかねないから、居ない方がいい。
自信と、それに見合う実力を持って仕事をしよう。
アップデートパッチの提供動機には、以下の四つが挙げられる。
このように、パッチ提供動機は、大きく『修正』と『追加』のどちらかに 分類される。それぞれについて見ていこう。
致命的なバグが発見された場合、もちろんそれを修正する必要がある。
実は修正には「勘所」がある。しかし、世のスクリプタ・プログラマはそれを
知らなすぎ、安易に色々やりすぎだと思う。
ソフトウェア工学を一から全て学べとは言わないが、その基礎は知った上で
スクリプタ・プログラマを名乗るようになって欲しいと切に願う。
口うるさいことは十分に承知しながらも、以下にそれらを列挙する。
を再帰的に考えていくことだ。そのためには論理的な思考が必要になるが、
まがりなりにもスクリプト・プログラムを組んでいるアナタには
その能力は既に備わっているものと信じる。
逆に、論理的思考ができないならスクリプタ・プログラマには向いてないので、
今すぐ足を洗った方がいい。
さて、幸い、吉里吉里/KAGではデバッグウィンドウが表示できるので、
バグが再現できたら、その近辺で内部情報を表示して、
根本原因を探っていくことができる。
上の再帰的思考でリストアップされた可能性を、
再現環境で内部情報を確認しつつひとつづつ潰していけばいい。
そんなの時間かかっちゃうよぅ、などと言うのは、
右の脳味噌だけでモノを考えている証拠だ。右脳が悪いわけではないが、
非論理的思考で発見したバグは、論理的に問題点を抽出できていないため、
修正漏れが存在する可能性が極めて高い。その状態で修正してしまうと、
後に再び同じバグを、二度手間三度手間をかけて修正する羽目になる。
論理的思考が出来るスクリプタ・プログラマになろう。
我々はスクリプタ・プログラマだ。論理的思考を持って、論理的世界で、 論理的に間違いのないスクリプト・プログラムを作り上げる、それが仕事だ。 問題を目の前にして、自分が解決できないから「バグではない」などと言い放つのは 全く無知蒙昧であり、恥を知れ、と言いたい。ああ言いたいともさ! 現実世界で我輩を苦しめる舶来の「自称プログラマ」なヤツラにな!(涙)
一刀両断的に正直かつ明確に言えば、「追加」が必要になる最大の理由は、
そのノベルゲームに対する最初の計画が不十分だったからだ。
作るための時間が足りなかった?後から追加したいことが増えた?
何故それを最初から予定に組み込めなかったのか。
次回作のために、再発防止策をひねり出しておくことを強くお勧めする。
以上、お小言終り。
『追加』が必要と考えるなら、後述するセーブデータの共通化のためにも、 一番最初、頒布開始の「前」から追加のための布石を打っておくことをお勧めする。 具体的には、「ここには追加シナリオを入れる」という場所に、最初から 追加シナリオを入れた場合のスクリプトをコメントで書いておく。
(snip) [cm] ; Ver 1.10 からの追加シナリオ挿入予定位置 ;[if exp="f.game_version >= 1.10"] ; [call storage="追加シナリオ.ks" target="*追加シナリオ01"] ;[endif] *scenario_no2|次の日 (snip) |
シナリオを追加する際にはこのコメントを外し、"追加シナリオ.ks"を用意すればよい。 これにより、元スクリプトを殆ど修正することなく、 シナリオを追加することができる。 これは、 後述する「パッチ適用前後でのセーブデータの互換性」を保つためにも 必要なテクニックである。そうはいっても実際には最初からこういうコメントを 入れておくのは難しいので、 とりあえず「このあたりにシナリオ入るかもよ」という印と、 その規模に見合った空行を入れておくことをお勧めする。
最後に、「変更」という作業に対してもっと慎重になろう、ということも追記したい。 「変更する」ということは、「新たなミスが入りこむ可能性がある」ということだ。 安易に変更して、新しいバグを入れ込んじゃう人のなんと多いことか。 変更に対し臆病になってはいけないが、もっと慎重になることはいいことだ。 是非慎重になって欲しい。そして、ユーザの足を引っ張らないスクリプタ・ プログラマになって欲しい。
ノベルゲームでは、パッチを適用することで、 セーブデータの互換性が無くなることがしばしばある。これは 吉里吉里/KAGだけでなく、他のAVG作成システムにも多かれ少なかれ存在する アキレス腱である。
より具体的には、吉里吉里/KAGでは、 パッチ適用後にパッチ適用前のセーブデータをロードして続きを遊ぶと、 以下のようなエラーメッセージが出ることがある。
エラーが発生しました ファイル : first.ks 行 : ### タグ : 不明 ( ← エラーの発生した前後のタグを示している場合もあります ) シナリオファイルに変更があったため return の戻り先位置を特定できません |
スクリプトで例外が発生しました シナリオファイル xxxxxxx.ks 内にラベル *xxxx が見つかりません |
これが出ると、ユーザにはもう何もできない。 回避のためには、該当の(古い)セーブデータを消し、 新たに最初からゲームを始めなければならない。 何故このエラーが出るのかは製作者にしかわからないので、 ユーザは黙ってそれに従うしかない。 大作であるほど、また、ストーリーが佳境に入り、ラストに近づいていればいるほど、 セーブデータの互換性問題は、ユーザのモチベーションを著しく削ぐ重大な問題だ。 ユーザ志向を謳うなら、セーブデータの互換性は常に保つ努力をすべきだ。
セーブデータの互換性が保てない原因は二つある。
どのようにスクリプトを作成すればこれらを回避することができるか、 以下に注意点等を見ていこう。
データをセーブした際、吉里吉里/KAGは以下のような動作を行う。
一方、データをロードした場合は、吉里吉里/KAGは以下のような動作を行う。
パッチ前 | パッチ後 |
---|---|
*start|はじまり えへへへ [p][cm] *life|生きるって 生きてるって、いいね [p][cm] *death|死ぬって 死ぬって悲しいね [p][cm] |
*start|はじまり えへへへ [p][cm] *new_life|生きるって ← 過去のデータはここで再開できない 生きてるって、いいね [p][cm] *death|死ぬって 死ぬって悲しいね [p][cm] |
これは例えば、"*|"のようなラベル名が自動生成されるセーブポイントの場合でも 同じ、というかより制約が厳しい。"*|"が減ると、自動生成されていた ラベル(XXXXXX:2 や XXXXXX:3 など)が減るため、「最後のセーブポイント」で セーブされていたデータが再開できなくなる。 しかも、再開する時に、ラベル名の位置が変わってしまうため、 別の位置から再開される場合がある。
パッチ前 | パッチ後 |
---|---|
*start|はじまり えへへへ [p][cm] *|生きるって 生きてるって、いいね [p][cm] *|死ぬって 死ぬって悲しいね [p][cm] *next|次のシナリオ |
*start|はじまり えへへへ [p][cm] ; *|生きるって ← こうすると、ラベル *start:2 がなくなる 生きてるって、いいね [p][cm] *|死ぬって ← ここが新しい *start:1 になる 死ぬって悲しいね [p][cm] *next|次のシナリオ |
纏めると、『ラベルの名前や数は不用意に変更しないこと』ということに尽きる。 より具体的には、以下の条件を守ればよい。
そもそも、パッチでは関数・変数・マクロ・ラベルなどを一切追加しなければよい。
これで確実にセーブデータの互換問題の半分はクリアできる。
このとき、セーブデータは、パッチ前後で互換性を保つことができる。
しかし、シナリオ追加などで、どうしても変数などを追加する必要がある場合、
一つの手段として、セーブデータにゲームのバージョン情報を含んでセーブしておき、
それを利用してバージョンごとにシナリオの動作を変える、という方法がある。
ゲーム先頭で
[eval exp="f.game_version = 1.00"] |
と定義(sf.game_version ではダメな理由は分かる…よね?)しておき、 その後、パッチを適用するたびにバージョンを上げる。 そして、変数が追加になる場合は、シナリオ中で、この変数の値を見て、 バージョン毎に挙動を変更するようにすればよい。 例えば、「f.semute(効果音をミュートするフラグ)」が パッチバージョン1.10から 追加になった場合、効果音を演奏するマクロ[se_play]を、以下のように変更する。
Ver 1.09 まで | Ver 1.10 から |
---|---|
[macro name="se_play"] [se_opt *] [playse storage=%storage buf=%buf loop=%loop|false] [se_wait buf=%buf canskip=%canskip cond="!mp.loop"] [endmacro] |
[macro name="se_play"] [se_opt *] [if exp="f.game_version < 1.10 || !f.semute"] [playse storage=%storage buf=%buf loop=%loop|false] [se_wait buf=%buf canskip=%canskip cond="!mp.loop"] [endif] [endmacro] |
こうすることで、新しいパッチ中では、 バージョン1.10未満のセーブデータでは単純に f.semute 変数は無視され、 古いセーブデータでも最後までプレイ可能になる。 即ち、パッチ適用前後でセーブデータの混在が可能となり、互換性が保たれる。
最も考慮が難しいのがこれ。 吉里吉里では、[call]タグを使用すると、 [return]した時に戻る場所を覚えておくために、 セーブデータ中に[call]元の位置を記録する。 より具体的には、以下の三つを記録する。
従って、パッチの前後で[call]が存在する行がスクリプト中で移動したり、 その行に追記したりした場合、セーブデータの互換性は失われ、 古いセーブデータをロードして実行しようとすると、前述のエラーが表示される。 これを防ぐためには、以下の条件を守る必要がある。
厄介なのは、広く使われている「どこでもセーブプラグイン」が、 [call]を利用して任意の場所でのセーブを実現していることだ。 従って、どこでもセーブプラグインを利用すると、 基本的に[label]を含む行 (これは最終的に[label]を呼ぶマクロを含む行も該当する) の位置を変更したり、削除したりすることができなくなる。 以下の条件を守ることで、なんとかセーブデータの互換を保つことはできる。
シナリオを追加する場合、パッチバージョンによってシナリオの矛盾が出ぬように 前述のf.game_versionを活用することもお忘れなく。
具体的には、以下のように変更する。バージョン1.1へのアップデート前と後で、 シナリオファイル「今日追加.ks」を追加実行することになった場合を例示している。
アップデート前 | アップデート後 |
---|---|
; 改ページマクロ[plc]定義 [macro name="plc"] [p][label][cm] [endmacro] (snip) *start|はじまり 今日はいい天気です。 [plc] でも昨日は雨でした。 [plc] [call storage="一昨日.ks"] おしまい。 [s] |
; 改ページマクロ[plc]定義 [macro name="plc"] [p][label][cm] [endmacro] (snip) *start|はじまり 今日はいい天気です。 [plc] [call storage="今日追加.ks" cond="f.game_version >= 1.1"] でも昨日は雨でした。 [plc] [call storage="一昨日.ks"] おしまい。 [s] |
変更箇所を一行に押し込め、前後で[label]を含む行の行番号に変更はない。 このようにすれば、セーブデータの互換性を保つことは可能である。 本当は上の例では 「[call]先でセーブ可能ラベルを新たに定義しないこと」という条件が付くが、 それはもっと前に述べているので、ここでは説明を割愛する。
本職プログラマには多いのだが、 「(実際に表示されるメッセージを除き、)ソースコード中に日本語を書くなんて カッコ悪い、英語書け英語」と思っている人がいる。 データファイルは、全て記号と番号で正規的に命名されていないと 気がすまない人もいる。 まぁ、仕事のプログラムを書く場合はそうなのかもしれない。
しかし、我輩はあえて、ノベルゲームのスクリプト中では、日本語を推奨したい。 理由は至極簡単、『そのほうが早く正確に読めるから』。 英語で書かれたコメントを、 その裏に潜む真の意味まで酌んで読むことができる人など何人居るだろう。 作者が非ネイティブであれば、元の文章が本当に正しい英語なのかどうかすら怪しい。 ファイル名についても、記号で書かれたファイル名を、 対応表を元にどんな内容であるか探し当てる作業が、 どれほど作業能率を下げるだろう。そういうことを考えると、 判りやすい言語を使って判りやすく記述されていた方が、管理は格段に楽になる。
それに、万一自分がそのゲームに関われない状態になった場合、 ゲーム製作は自分の手を離れ、 アナタが作ったスクリプトは別の人の管轄下に入るかもしれない。 その時、スクリプトが英語と記号まみれだったとしたら、 引き継いだ人はそのスクリプトを完全に理解できるだろうか。絶対ムリだ。 我輩も何度か引き継いだことがあるが、死ぬような思いだった。 もうあんな無駄な苦労はしたくない。
だから、日本語。日本語でコメントを書き、日本語ファイル名を取り扱い、 日本語で命名されたマクロを使う。後から読んで判りやすいじゃないか。
比較してみよう、以下のスクリプト、やりすぎてあざといのは承知の上で、 右と左はどちらがわかりやすい?
スクリプト in 英語 | スクリプト in 日本語 |
---|---|
; Written in English [erase_message_window] ; akane & minatsu must be displayed simultaneously. [disp_char name="akane" graph="ak0002 ak0010 ak0200" position="right"] [disp_char name="minatsu" graph="mn0001 mn0020" position="left"] [disp_message_window] [speech name="akane"] 英語で書いてあると何がなんだか判りません。 [np] ; erase message_window once here [erase_message_window] ; display akihito slowly, in 2000ms [disp_char name="akihito" graph="ah0001 ah0030" position="center" time=2000] [disp_message_window] |
; 日本語で書いた場合 [メッセージ枠消去] ; あかねと美夏は同時に表示すること [キャラ表示 名前="あかね" 画像="ワンピ 笑顔 赤面" 位置="右"] [キャラ表示 名前="美夏" 画像="和服 微笑" 位置="左"] [メッセージ枠表示] [セリフ 名前=あかね] 日本語の方が判りやすい…と思うんだけど。 [np] ; 一度メッセージ枠を消すこと [メッセージ枠消去] ; アキヒトは2000msでゆっくり表示する [キャラ表示 名前="アキヒト" 画像="着流し 爆笑" 位置="中央" time=2000] [メッセージ枠表示] |
幸い、吉里吉里/KAGでは、フツーに日本語が使える。 マクロとしても使えるし、サブルーチン名としても、ラベルとしても使える。 使えるなら、便利に使おう。もちろんあざとくならない程度に、ね。 もちろん、製作者の趣味趣向の一つだと言われればそれまでだが、 「わかりやすく書く」ことの一つの有効な手段だと思うのだ。
嘲笑を込めて「日本語ベーシックみたいだー」とかノタマウ人は、 既にそれが死語になっていることに気づくべし。
この文書では、主に以下の三点について述べた。
かなり小うるさいことも書いてきたが、どうだろうか。 『そんな面倒なことやってらんねぇ』とか 『楽しく組めればそれでいいじゃん』とか思ったかもしれない。 それは半分正しく、半分間違っている。 同人であれ作品を世に出すということは、 即ち不特定多数のユーザにプレイしてもらうということだ。 このとき、ユーザに不快感を与えてはならない。 スクリプタにとって、『不快感を与えない』とは即ち、 バグの抑制が必要であることを意味する (でもなぜかレスポンス・パフォーマンスの向上が問われることはあまりない)。 早く、確実にゲームを作り上げること、 バグの発生を防止しつつ発生可能性を下げること、 万一発生した場合に再発を防止すること。 これらの指標として、上の三点を述べたと思いねぇ。
そして、スクリプタ・プログラマの究極の目的は、「ユーザにゲームを楽しんで もらうこと」であることを忘れないこと。スゴい技術は手段であって目的ではない。 それを忘れた時、アナタはまごうかたなく「ヘンなシステム」を 作ってしまうことだろう。そもそも我々は日陰者なのだ。 「あのゲームのシステムはスゴいよね」ではなく、 「あのゲーム面白かったよね」と言ってもらえることを目標にしよう。 ゲームの感想ばかりで、システムについての話題がこれっぽっちも出てこないこと、 それは実はスクリプタ・プログラマにとっての最高の褒め言葉だと思う。 それでいいじゃないか。
以上の偏向文書が、少しでもスクリプタ諸兄の役に立つことができれば幸いであるよ。