2016年10月21日金曜日

ツクールMVでプラグインを作るための現実と作法

ツクールMVでプラグインを作るための現実と作法

はじめに

 本稿は株式会社ドワンゴ様から依頼を請けてニコニコ自作ゲームフェスMVの企画の一部として執筆しています。ニコニコ自作ゲームフェスMVでは、みなさんのツクールMV作品を随時募集しています。私が作成したノベルゲーム総合プラグインによる「企画」なんかもありますので、ふるってご参加ください!

ニコニコ自作ゲームフェスMV

 早いものでRPGツクールMVの発売からもうすぐ一年が経過しようとしています。私は、去年の十月末に海外版がSteamで先行販売されたときに衝動買いをして以来、プラグイン制作に的を絞って活動してきました。その過程で私なりにプラグイン制作と公開に関していくつかの知見を得ることができたと思っています。

 そこで本稿では、これからプラグイン作成(自作品用のプラグイン制作含む)を始めようという方を主な対象に、プラグインの作成から一般公開までの流れの中で重要なポイントを簡潔に説明しようと思います。JavaScript(以下JS)に関する知識としては、変数や関数、オブジェクト指向を把握している程度の方を想定していますが、専門的なことには一切触れないので、それらは後回しでもOKです。逆に言うと、本稿はJSやプラグインそのものの講座ではありませんのでご注意ください。

 繰り返しますが専門的な記述は一切ありません。プラグインは使うだけ、という方でも多少は得るものがあるように頑張って書いたのでお付き合いくださいませ~。

準備編

優秀なお手本を参考にする

 さあプラグイン制作を始めよう、と意気込む方がよく行うのが本屋に駆け込んで教本を買うことです。ですが、個人的にはあまりオススメできません。プラグイン制作は一からアプリケーションを作成するのとは勝手が違います。すでにコアスクリプトという優秀なお手本が存在するので、そのレールに従えばいいのです!
 もちろん、これを機にJSを本格的に勉強してみたいという方はその限りではありませんよ! 書籍に関しては以下の記事が参考になるかと思います。

参考:初心者ツクラーの為のJavaScript入門

 とはいえ個人的には、よほどガッツリと学習するのでなければ以下のサイトで事足りると思います。基本的なことはすべてここに載っているはずです。

参考:Mozilla Developer Network JavaScript

 お手本は二つあります。ひとつは前述したコアスクリプト。プロジェクトのjsフォルダに入っているファイル群ですね。ツクールMVを動かしているすべての記述がここにあり、JSの基本文法に関してはここを読んでいれば嫌でも身につきます。どうせ何度も読み返すことになるでしょう。

 そして、もう一つのお手本は公式プラグインです。新規プロジェクトの「js\plugins」以下に最初から入っています。作者が「Yoji Ojima」(尾島陽児氏)となっていて、かつ構造がシンプルなもの……となるとTitleCommandPosition.jsがベストでしょう。基本的なプラグインの作法はこのファイルに詰まっています。

 参考にするうえで重要なのは次の二つです。

  1. 即時関数
  2. 再定義
// これが即時関数です。JS(ES5の場合)ではこの方法でしか変数のスコープを規定することができません。
(function() {
 
    // 上書きする前の関数を変数に入れます。(JSでは関数への参照を変数に代入することができます)
    var _DataManager_setupNewGame = DataManager.setupNewGame;
    DataManager.setupNewGame = function() {
        // 関数の最初で保持しておいた上書き前の関数を呼び出します。(applyは変数に入れた関数を実行するメソッド)
        var result = _DataManager_setupNewGame.apply(this, arguments);
        // 自分が入れたい処理を実行します。
        $gameParty.gainItem($dataItems[4], 1);
        // 上書き前の関数が戻り値を返している場合は、それを返します。         return result;     };
})();

 即時関数とは、定義したその場で実行される関数です。なぜそんなものが必要なのか? それは関数内で定義したローカル変数の有効範囲をプラグイン内に限定するためです。簡単に言うと、変数名が他のプラグインと競合することを防ぐためです。即時関数内で定義するローカル変数は、競合の心配は一切無用です

 次に再定義です。これは既存のコアスクリプトの関数の定義を保持したまま、独自の処理を追加することを可能にします。

 海外のプラグインの中には、お手本とはかけ離れた独特なプラグインが多数あります。内容を把握したうえで記述方を取り入れるぶんには全く問題ないですが、もっともシンプルかつ実害の少ないやり方が公式プラグインの記法であることは間違いないと思います。

エディタを用意する

 さて、これからプラグインの作成を……といきたいところですが、その前にやることがあります。エディタ(IDEを含む)の準備です。

 JSはテキストファイルなのでテキストエディタであればなんでも編集できます。しかし、プログラミングに適したエディタを選択することで、コードの静的解析や補完、デバッグ実行などプログラミングをするのに役立つ恩恵を受けることができます。前作でRGSSを扱っていた方にはピンとこないかもしれませんが、ツクールMVでは自分で自由に制作環境を選択できるのです。JSはRGSS(Ruby)と比べて扱いにくいと言われていますが、前述の各種アシスト機能に頼ることで大幅に負担を軽減できます。

  • エディタの表示例(画像はWebStorm) Web Strom

 JSに対応したプログラミング向きのエディタはたくさんあり、すべてを比較検討していてはそれだけで一つの記事になってしまうのでここでは割愛してエディタの代表的な機能を見ていきましょう。

  • 静的コード解析
     静的コード解析とはコードを直接実行せずに内容を解析して、文法エラーや不適切な記述を事前に見つけ出してくれる機能です。エラーや危険な記述を未然に防ぐことはもちろん、独自の検査ルールでコードの品質を全体的に高めてくれます。
  • コード補完
     オートコンプリートとも呼ばれる機能で、入力しようとしている処理(変数やメソッド等)を予測して候補としてポップアップで提示してくれます。単なる前方一致のものや、あいまい検索で柔軟に候補を提示してくれるものもあります。
  • 定義先にジャンプ
     正式な名前が分からなかった(笑)。関数や変数を定義している場所に瞬時に移動できる機能です。コアスクリプトは無数の関数に分割されていますが、この機能があれば迷うことなく処理の流れを追うことができます。もちろん元の場所に戻ることもできます。エディタによって同一ファイル内に限定されるものと、別ファイルまでジャンプできるものとがあります。
  • アウトライン解析
     エディタに表示しているファイル内に定義されている変数や関数を一覧で表示してくれる機能です。クリックするともちろんエディタ上の実際の場所にジャンプします。
  • デバッグ実行
     少し難しい話になってしまいますが、デバッグ実行では、ブレークポイントというものを実行前に張っておけば、実行時に処理がそこで停止し、その時点での変数やオブジェクトの中身を確認したり、任意のスクリプトを自由に実行したりできます。さらにステップ実行といって止まった箇所から一行ずつ実行することも可能です。
  • Webサーバ機能
     これは一部のIDEに限定された機能ですが、ローカル環境上で仮想のWebサーバとして動作し各種ブラウザ(Chrome, Firefox, Edge)での動作確認を行うことができます。Firefoxなどは直接実行しても一応動作しますが、より実際のブラウザ版に近いかたちで動作確認できるメリットは大きいです。

 肝心のエディタですが、私が軽く確認したところ比較的よく使われているのが「Sublime Text3」「Brackets」「Visual Stadio Code」「WebStorm」あたりのようです。(後ろにいくほど高機能な代わりに起動が遅いです)機会があれば、それぞれの使い勝手も検証したいところですね。

作成編

プラグインをStrictモードにする

 お手本にエディタ、材料と道具の準備が完了したところで、早速プラグインを作成……といきたいところですが、お手本にひとつ追加して欲しいコードがあります。

'use strict'という構文です。

(function() {
    // 必ず即時関数の先頭に定義します。
    'use strict';
 
})();

 これはJSをstrictモードで実行するために必要な一文です。必ず即時関数の「直後」に入れてください。strictモードに関する解説はこちらの記事が参考になるでしょう。要はそのままだと自由すぎるJSに対して、制限を掛けてくれるモードです。リスクのある書き方や紛らわしい書き方を未然に防ぐことができます。

参考:Mozilla Developer Network Strict モード

発生したエラーの対処をする

 プラグインを作成して試しに実行したら、あるいはプラグイン素材を適用したらエラーが発生した……としても落胆することはありません。

 エラーが発生したときの一番の手掛かりは「スタックトレース」です。スタックトレースとは、処理がどのような経路で最終的にエラーに至ったのかを示してくれるものです。ツクールで実行している場合はF8キー押下で、エディタから実行している場合はコンソールを見れば、スタックトレースを確認することができます。

  • スタックトレースの表示例 スタックトレースの表示例

 スタックトレースを確認すると、多少慣れた人ならエラーのおおよその見当を付けることができます。もしあなたがプラグイン素材の利用者なら、ぜひこのスタックトレースの情報を提供してあげてください。ただし、スタックトレースにはご自身のローカルファイルパスが含まれている場合があります。必要に応じてマスキングするなどの対処をしてください。

 次に発生したエラーごとの対処法……といってもJSはゆるい言語なので、エラーの種類もさほど多くありません。そして、エラーの原因はほとんどひとつに絞られます。それは「存在しないものを」参照しようとした場合です。

  • ReferenceError: aaaa is not defined
var aaa = {};
console.log(aaaa); // ReferenceError: aaaa is not defined

 定義されていない識別子を使用した場合に発生します。ほとんどの場合、ただのタイプミスです。スタックトレースから発生した行数を特定すればすんなりと解決できます。そもそもエディタの静的解析を使いこなしていれば事前に教えてくれることがほとんどなのであまりお目にかかることはないです。

  • TypeError: undefined is not a function
var aaa = {};
aaa.bbb(); // TypeError: undefined is not a function

 なんとも不親切なエラーメッセージですね。関数以外のプロパティを実行「()」しようとすると発生します。いや存在するはずだ! という場合は、処理をさかのぼって、メソッドの実行主体(この場合は「aaa」)に想定する値が入っているかどうかを確かめましょう。ここでスタックトレースが役に立ちます。

  • TypeError: Cannot read property 'ccc' of undefined
var aaa = {};
aaa.bbb.ccc; // TypeError: Cannot read property 'ccc' of undefined

 存在しない値に対して、さらにプロパティを参照すると発生します。ここでundefinedなのはbbbです。対処方法は、前のヤツとほとんど同じです。

競合を解決する、あるいは未然に防ぐ

 多数のプラグインを同時に動かすときの脅威が競合です。まずは競合が発生する主な要因と対処法をまとめてみました。

  • 同一処理に対する複数の再定義
     複数のプラグインが同じメソッドを再定義して、かついずれか一つが元のメソッドを呼び出していない場合、単独では呼ばれたはずの処理が呼ばれないことがあります。
     運が良ければプラグイン管理画面からプラグインの順番を入れ替えることで解決できますが、そうでない場合は、どうにかして元の処理を呼び出すように変更するしかありません。
     効率は悪くなりますが、元の処理を呼び出すことでオブジェクトの状態が不都合に変えられてしまう場合も、再定義で変えられた処理を元に戻すことができる場合があります。実行時間は当然伸びてしまいますが、競合するよりはマシです。たとえ無駄な処理だとしても極力、元の処理を呼び出すようにしましょう。
(function() {
    var _DataManager_setupNewGame = DataManager.setupNewGame;
    DataManager.setupNewGame = function() {
        _DataManager_setupNewGame.apply(this, arguments);
        // 後に定義した処理が、元の処理を呼び出していなければ先に定義した処理は呼ばれません。
        console.log('呼ばれない');
    };
})();
 
(function() {
    DataManager.setupNewGame = function() {
        console.log('呼ばれる');
    };
})();
  • 追加した識別子の名前が衝突
     追加したメソッドや変数の名前が衝突してしまうケースです。命名には一定の規則があるので意外と起こります。これは即時関数や名前空間などを用いても防ぐことはできません。
     ただし対処法は簡単です。名称が衝突しただけなら、どちらかの名称を変えればいいだけです。
(function() {
    DataManager.newMethod = function() {
        // 追加したメソッド名称がたまたま衝突してしまった場合、先に定義した処理は呼ばれません。
        console.log('呼ばれない');
    };
})();
 
(function() {
    DataManager.newMethod = function() {
        console.log('呼ばれる');
    };
})();
  • 既存変数の状態を変更
     厄介なケースです。たとえば、あるプラグインが既存の変数の値をnullに変えてしまい、直後に別のプラグインがその変数のプロパティを参照するとエラーになってしまいます。
     変数の型を変える場合、特にリスクが高いです。とある海外のプラグインでは、boolean型の既存プロパティを配列に変えたりしていました。自由なJSならではの荒技ですが、そのぶん影響も大きくなります。
     対処するには、事前にチェックを入念に行うことです。特に配列に対して繰り返し処理をする場合は、想定外のものが入っていた場合に弾けるように、特定のプロパティや関数を保持しているかなどの分岐を作っておきましょう。  もっともこのケースは実際に競合を確認してから対処する場合が多いですが……
(function() {
    var _DataManager_setupNewGame = DataManager.setupNewGame;
    DataManager.setupNewGame = function() {
        _DataManager_setupNewGame.apply(this, arguments);
        // 先の処理でnullが入れられているのでエラーになる
        var length = this._databaseFiles.length;
    };
})();
 
(function() {
    var _DataManager_setupNewGame = DataManager.setupNewGame;
    DataManager.setupNewGame = function() {
        this._databaseFiles = null;
        _DataManager_setupNewGame.apply(this, arguments);
    };
})();

命名に関する約束ごと

 プラグインを作るうえで、数多くの命名が必要になります。ファイル名はもちろん、関数名やメソッド、変数名。さらにプラグインパラメータやプラグインコマンドの命名も含めて、命名は可読性はもちろん、使い勝手にも大きく関わってきます。

  • プライベートなプロパティ・メソッド
     JSでは定義したプロパティは外部から自由に参照できます。コアスクリプトでは先頭にアンダースコア(_ ) が含まれているプロパティやメソッドは外部から参照してはならない、という意味のようです。(とはいえ、そのコアスクリプト自身が一部でその約束を破っているので微妙ですが、意図としては間違いないと思います)
     なので参照したい場合は、取得および設定するためのメソッドを別途、定義してやり取りするのがお行儀の良い書き方になります。
  • プロパティとメソッドの区別
     オブジェクト指向において、プロパティとは主体の持つ属性であり、値が入っているだけです。一方、メソッドは主体の動作であり、処理を実行して必要に応じて結果を返すものです。アクセサプロパティなどの例外もありますが割愛します。
     よってこれらの命名の際は、プロパティには「名詞」、メソッドは「動詞」を最初に付与すると分かりやすく区別できます。続けて「目的語」などを付与すると一層、分かりやすくなるでしょう。実際の値や動作を十分に説明しているかが肝要です。  何故そんなことに拘るのかというと、オブジェクト指向のソースコードは、「実行主体」+「プロパティ(メソッド」で一つの英文になるからです。その英文が処理を正しく説明しているのならコメントはほとんど不要になります。実際コアスクリプトは、この要件を十分に満たしているのでコメントなしでも成り立っているのです。 (一部誇張あり)

公開編

ヘルプを作成する

 プラグインの使い方はプラグイン管理画面のヘルプに表示されるようにします。具体的なやり方は最初に示した公式プラグインのお手本が参考になるでしょう。意外と横に狭いので横スクロールバーを出さないためには工夫が必要です。

 では、具体的な必須事項を挙げていきます。

  • プラグインを適用しただけで必ず変化すること
     この説明がないとゲームの挙動をユーザが判断する際、正常に動いているのか、バグなのか、プラグインによる追加仕様か、デフォルトの仕様かが区別できなくなってしまいます。
  • プラグインコマンドの使用例
     パラメータの説明は別途記述欄がありますが、プラグインコマンドについてはヘルプの自由記入欄に書くことになるので、最低限、コマンドと引数に関する説明が必須で、できれば記述例があるといいでしょう。
  • バージョン
     バージョン表記の方法は色々ありますが、私は「メジャーバージョン」「マイナーバージョン」「リビジョン」の三つの数字(1.2.0等)で構成しています。ツクール本体と同じ表記法ですね。
     メジャーとマイナーで事足りるようにも思えますが、個人的には、「1.11」と「1.2」のどちらがより新しいバージョンなのか区別がつきにくいので苦手です。(ドットを小数点と解釈するか、しないかで異なる)
  • 作者連絡先
     ブログやSNSのアカウントなど、連絡先が記載されていればフィードバックを得やすくなりますし、安心して使ってもらうことができます。
  • 利用規約
     必須事項です。MITライセンスなど、既存のライセンスを使用するのが望ましいです。(理由は後述)

ライセンスを決める

 RGSSの頃は、素材提供者がそれぞれ規約を作成してWebサイトに掲載するのが一般的でしたが、ツクールMVでは公式がMITライセンスを推奨しています。

参考:ツクール開発部公式ツイッター@tkool_dev

 MITライセンスとはOSSライセンスの一種でコピーレフトの考え方を持たない寛容なライセンスのひとつです。利用者は原作者の著作権表記とライセンスの全文(もしくは全文に繋がるハイパーリンク)を明確にする義務のみを負い、改変しての二次配布や、商用利用などすべて自由にできます。

参考:自作ソースコードに、MITライセンスを適用する3つのやり方

  • どうしてMITなのか?
     端的に言うと、原作者を尊重しつつ、作者と利用者、双方の負担を軽くすることができるからです。作者は一切のサポート義務を負う必要はなく、利用者もソフトウェアの説明書やクレジットに表記する必要はありません。
  • 独自規約の問題点
     規約を独自に作成すると、どうしても定義が不明確な箇所が出てきてしまいます。元来、自然言語とは曖昧さを宿命として孕むものです。不明確な点について言葉を尽くして説明しようとすると、かえって曖昧さが増す結果にもなりかねません。  そうなると規約を誤解する人や守らない人が必ず出てきます。そういう人を見付けてイライラするくらいなら、最初から寛容にしておいた方がマシです。
  • グローバルスタンダードなライセンスのメリット
     MITライセンスの定義はOSD(オープンソースの定義)を満たしており、解釈について議論の余地はありません。加えて、日本語が分からない海外のユーザにも、MITの三文字だけで安心して使ってもらえるメリットもあります。
     同じく寛容なOSSライセンスとしてApacheライセンスなどがありますが、事実上のスタンダードしてMITを定着させるべくあえて公式が明言するかたちで推奨したであろうことを考慮すれば、無理に逆らうこともないかと思います。
  • MITライセンスの注意点
     MITライセンスと明記すると自動的にいくつかの権利を利用者に与えることになります。利用者は改変および商用、非商用の有無にかかわらず単独での再配布が可能です。また作者は、利用者がプラグインをツクールMV以外の目的に利用することを禁止できません。さらに、特定の個人や集団に対してプラグインを使用禁止にすることができません。(たとえば、ネット上でトラブルになった相手に対して使用禁止を宣告する等)これらを許容できない場合、MITライセンス以外を選択する必要があります。
  • MITライセンスの適用方法
     詳細は先に挙げたURLをご参照ください。基本的には、著作権表記をしっかり行うこととMITライセンスの全文をソースコードと公開するWebサイトに掲載したうえで、MITライセンスであると宣言すれば問題ありません。

プラグインを配布する場所

 公開方法は色々あって、自身の運営するWebサイトや各種オンラインストレージなどがあります。ですが、OSSのソースコードを公開するという意味でならGitに特化したサービスであるGitHubがオススメです。

参考:GitHub トップページ

  • コードをコミットする際に差分が確認できる
     コードの差分を比較して、コミット前の最終確認ができます。デグレードを防ぐ意味でも予期しない箇所が変更されていないかどうかのチェックは重要です。ローカルコミット、リポジトリコミットという二段階を経ているので安心です。
  • 以前のバージョンが履歴からログ付きでいつでも復元できる
     バージョン管理システムの恩恵です。これにより求められればいつでも過去のバージョンを復元して渡すことができます。
  • プルリクエストがもらえる
     ツクールの文化上、あまり頻繁ではありませんが、誰かがバグを見付けて修正したものを送ってくれるかもしれません。もし送られた場合は、内心キョドっていたとしても平静を装い、中身を確認して問題がなければ承認しましょう。私は以前に、二回送られたことがあります。
     自分が作ったものを勝手に修正されることに最初は抵抗があるかもしれませんが、そういうものなので慣れましょう。
  • GitHub Pagesでそのままツクール作品が公開できる
     リポジトリにあがっている内容をWebサイトを公開できるサービスです。これを使えばツクールMVのブラウザ版を直接公開できます。MVのプロジェクトをそのままアップロードすればいいだけなので煩雑な手順も不要です。

 参考:Qiita:RPGツクールMVで作ったゲームをGitHubPagesで公開してみる

  • 英語なので使う側にとって不便
     デメリットです。一般ユーザにはJSファイルを直接参照するURLのみを自身のWebサイトやフォーラム等で提示するのがいいかと思います。私の場合は、別途スプレッドシートを用意して、そこでプラグインの一覧を紹介しています。スプレッドシートは、表形式の一覧を作りやすく、またFTP等の不要で更新が楽なのでオススメです。

おわりに

 いかがでしょうか。今回は外堀を埋めたかたちで、本丸であるプラグインそのものには切り込んでいないので物足りなかったかもしれません。しかし、こういった周辺知識を固めていくことで後顧の憂いなくプラグイン開発に没頭することができます。

 ツクールのコアスクリプトは残念ながらOSSではありませんが、プラグインを作って自由に公開できることは事実上コアスクリプトをOSS化しているのと同じことだと思っています。プラグイン制作には、いちユーザがツクールというツール開発そのものに参画し、自身の裁量で想像力を駆使して自由に使い勝手を向上していけるという楽しみがあります。

 より実践的、具体的なプラグインの作成方法については、また機会があればやろうと思っています。何かご要望などありましたらお気軽にコメントください。

2 件のコメント:

  1. 以前にもこちらで名無しでコメントを残しましたが、改めてドバン!と言います

    プラグイン制作にはいつか手を出してみたいなと思っているので
    このような講座を書いていただけると大変助かります
    まだまだ理解が追いついていませんが・・・^^;

    それと少し話は逸れますが
    ツクマテでは制作中のゲームで使用した海外の公式プラグインの問題に解決案を出してくださったおかげもあって
    無事にゲームを完成させることが出来ました!

    誠に勝手ながら
    MVでスペシャルサンクル等にスクリプトの素材利用などを目的として
    名前を記載してゲームを作らせていただきました!

    ttp://game.nicovideo.jp/atsumaru/games/gm466

    こちらの素敵なスクリプトをいくつかお借りさせて頂いたこともあって無事に完成しましたのでご報告します!
    本当にありがとうございました!!
    これからもプラグイン制作頑張ってください!!

    返信削除
    返信
    1. ドバンさん、コメントありがとうございます!
      そして、完成おめでとうございます。

      スペシャルサンクルの件、了解しました。
      微力ながらお手伝いができたこと、嬉しく思います!

      応援ありがとうございます。私もゲーム制作、陰ながら応援しております~!

      削除

注: コメントを投稿できるのは、このブログのメンバーだけです。