プラグインの基礎をまとめてみた
今だにプラグインの作り方よくわかんなくなるので、復習がてらまとめを書くことにしました。
まずは参考資料など
このコーナーではおなじみ、むーてぃさんのRPGツクールMVのプラグインを作る方法 | 趣味に生きる。
それから、こちらもおなじみ yamachanさんの RPGツクールMV プラグイン作成入門 (1) 簡単なプラグインを作成してみる - Qiita
ついでに、NPlasmaさんのRPGツクールMV やさしいプラグインの書き方 基礎編 | ぷらずま式改さらには RPGツクールMV 良いプラグインとは | ぷらずま式改もいい記事です。
どちらかというと、使う人に「優しい」プラグインの作り方ですね。僕も、さほど優しいプラグインは作れてません。
これらの記事を基本にして、ざっとまとめておきたいと思います。
ここにプラグインの作り方知りたくて来た人は、全部読めばいいと思います。
すでに記事あるなら、この記事いらないだろって話もありますが、このコーナーは基本的に自分のためのメモなので! 自分が忘れた時に見るもんなのでー!!
まず自分でプラグインを作る前に、公式プラグインの把握から始めるのが良いと思います。
まず、ヘルプに一通り説明が書いてあります。
そして、公式プラグイン - RPGツクールMV Wikiにもまとまっているので、参考になります。
とか言ってますが、僕自身は全然把握できてません!! 把握しろよ!! だから、すでにある機能を開発しまくるんだろ!!
追記
_F さんの【RPGツクールMV】イマドキのプラグイン記述術 - エフアンダーバーが書かれていたので追加します。
これは素晴らしいです。以降僕の解説で _F さんと違ってること書いてたりしますが、そこは臨機応変に取捨選択プリーズ!
ただ、_F さんの記事は入門記事ではないので、プラグインの仕組みをざっと理解してから読まないと、意味わかんないと思います。
プラグインとは
RPGツクールMVのプロジェクトに追加することで様々な機能が実現できるJavaScriptファイルがプラグインです。
一応の基本的な説明はヘルプにも書いてあるんですが、それで作れるようになるかというと、かなり厳しいものがあります。
まずは、どのような拡張手法があるか、ひとつずつ見ていきましょう。
メソッドの再定義
プラグインはそもそものRPGツクールMVの挙動を上書きして、作り変えることができます。
各種ウィンドウのレイアウトを変えたりなど、なんでもできちゃいます。
この手法は、プラグインを登録した時点で機能するので、これが基本ですね。
できれば、導入時点で見た目や挙動が変わるような作りになってると嬉しい。
僕もプラグイン作ってるのに、人のを導入すると「あれー、プラグイン入れたのに何も起こらないツマンネ、削除、削除」みたいなノリになりがちです。
パラメータ
つぎは、[プラグインパラメータ]ですね。
これはプラグインに渡される初期設定で、エディタのプラグイン管理ウィンドウで設定できます。
どのような設定が必要かプラグイン側で細かく設定できます。
[プラグインパラメータ]の詳細は説明すると結構な量になるので、今回は解説しません。
このウィンドウは開発の最後に作られたっぽく、比較的ちゃんとUIが作られています。
項目はドラッグで入れ替えできますし、プラグインのON/OFFは個別のウィンドウを開かなくてもコンテクストメニューから行えますし、複数選択しておけば一度にON/OFFを変更できます。
プラグインを入れ替えた後にエディタそのものを再起動しなくても、コンテクストメニューで[更新]を選べば入れ替えが完了します。
ただ、たぶんRPGツクールMV作った方も想定してなかったと思うんですが、なんかいろいろやっているうちにプラグインを3桁使ってた、なんてことも珍しくないようです。
フォルダによる分類や、区切り線、注釈といった機能も欲しかったところです。
なぜか同じプラグインを重複して登録できてしまうといった、そこはチェックしてくれよ、という不満はあります。
おかげで空プラグインのファイル名を、区切り線がわりに使えるという裏技もできるわけですが。
とはいえ検索(メインメニューがグレーアウトしていますが、コンテクストメニューや Cmd+Fで呼び出せる)できるので、ある程度の量のプラグインも想定してはいるようです。
メモ・メタデータ
メモ欄にタグを書き込むことでプラグインに値を渡す方法もあります。
ざっくり言えば[プラグインパラメータ]の個別項目版です。
メモはnote、meta プロパティを持っているデータについています。
具体的には、クラスツリー : メモつきデータ(MetaData)の所に並んでいるデータがそうです。
結構ありますね。
各種ブラグインが活用しているため、エディタに用意されている表示領域では狭すぎる感じです。
しかしこれは設計ミスを責めるよりプラグインを作りやすくしたことを褒めたほうがいいかもしれません。
RPGツクールの次回作があるなら、ここは大きく拡張されるとおもいます。
プラグインコマンド
それから[プラグインコマンド]で、JavaScript で作った機能を呼び出すことができます。
詳しくは、これまたおなじみトリアコンタンさんのプラグインコマンド集を作って、ツクラーフレンドリーについて考える - Qiitaに詳しいことが書いてあります。
これはプラグインを作る方としては若干面倒くさいですが、日本語のコマンドも作れるし、実行も速いし、書く量も[スクリプト]に比べると短くできます。
僕は日本語コマンド用意してませんけどねっ! 英語と日本語ふたつ作るの面倒くさいんで!!
ちゃんとやってるトリアコンタンさんはとても偉いのです。キノコと杏ちゃんを讃えましょう。
スクリプト
JavaScript で作ってるんで、基本的には[プラグインコマンド]を使わずに[スクリプト]で直接呼び出せば良いわけなんですが、eval()
を使って文字列をその場でコンパイルして実行しているため遅いのです(一回の呼び出しなら、そんなに影響ありませんが)
あと、参照先オブジェクトの記述が必要だったりして、記述がどうしても長くなりがち。大抵は this.
が必要になります。
しかし、[移動ルートの設定]の中には[プラグインコマンド]が存在しないので、[スクリプト]を使わざるをえない。
そういうしょうがなく使うだけでなく、[スクリプト]からプラグインの機能を呼び出す場合、複数行書けるので前後にJavaScriptの処理が書け、非常に応用力が高いというのは大きなメリットです。
以上がプラグインでできることです。
なんでもできますね。
JavaScript な訳ですから、データを外部ファイルから読み込む形式なども、スクリプトさえ書いてしまえばできます。
本来は動作に何の影響も与えない[注釈]に書いた文字をデータとして利用するような「えっ、そんなことしちゃうんだ」ってプラグインもあります。
できることが多いので、今回はとりあえずだれでもほぼ同じ形になるプラグインのテンプレートを用意するところまで行くのを目標とします。
メソッドの再定義を試してみる
値が気にいらないけどデータベースに設定項目もない、というやつ結構あると思います。
RPGツクールMVには値を固定値で返すメソッドが結構あって、そこ書き換えればいいんです。
コアスクリプトを直接書き換えてもいいんですが(良くない(笑))、プラグインにしておくと設定戻すのも簡単ですし、コアスクリプトのバージョンアップもしやすいですし、何かと便利です。
まずは適当なテキストエディタを用意しましょう。
多くのサイトでVisual Studio Codeが推奨されていると思います、僕からもオススメです。
Mac版の他にLinux版、さらにWindows版もありますし、公開された2015年からいい感じに時間も経って使いやすくなっているし情報もある、そして、いい感じに古びてないので過去の負の遺産もほぼないという、実に旬なエディタとなっております。
個人的には AppleScript に対応してないのが「チッ」って感じですが、マルチプラットフォームを考えるとしょうがないですね。
一時期はMSのソフトが一番 AppleScript の対応度が高い(もちろん Apple よりも!)ってこともあったんですが。
閑話休題。
文字コードはUTF-8(BOMはあってもなくてもいいけど、僕は無しにしてます)、改行文字はLFを選んどきましょう。この辺コアスクリプトと合わせておかないと、意外な文字化けなど発生するので選択の余地はないです。
VSCode の場合ウィンドウの右下の表示から変更できますが、コアスクリプトをひとつ適当にコピーして名前を変え、中身を削除した方が間違いない気もします。
ファイル名には全角文字は使わない方がいいです。なんかしらんのですが、RPGツクールMVでは読み込めなかったりエラーが出たりしがち。
myPlugin.js とでも名前をつけましょう。
んで、以下の文字を入力します。コピペで結構ですがプログラマ気分を味わうために、手入力してエラーを発生させ「いやー、バグだよバグ、デバッグ大変でさー」とか言っちゃったりするのもいいでしょう。
僕はコアスクリプトからほぼコピーしてますけどね、以下のスクリプト(笑)
Window_Options.prototype.volumeOffset = () => 5;
ファイルを保存したら、普通のプラグインと同様にRPGツクールMVのエディタで登録します。
プロジェクトのテストプレイをして、音量設定を動かしてみると、雑な10刻みが5刻みになってます。
なんということでしょう、一行だけで実用として十分使えるプラグインが作れてしまいました。
標準的な枠を作る
世に出回っているプラグインの構造を、ひとまず、ざっと説明します。
だいたい次のような作りになっています。
( function() {
'use strict';
// スクリプトを書く箇所
} )();
まず、外側のカッコを取り除くと次のようになって、普通の関数定義だと言うことがわかります。
この場合は function の後に識別子が書いてないので「無名関数( anonymous function 又は nameless function )」というやつです。
function() {
'use strict';
// スクリプトを書く箇所
}
無名関数の中身は外からアクセスする手段がないので、他のプラグイン(やコアスクリプト)を気にせずに新たな識別子を作れて、非常に楽に安全なスクリプトが作れるというわけです。
逆にこの無名関数の中からはグローバルな領域にアクセスしほうだいなので、コアスクリプトの変更を行うのに問題ありません。
あと 'use strict';
が何かというと、関数の頭に書くことでJavaScript の解釈を厳密( strict )にやりますよ、という宣言になります。
例えば、変数は let
などで宣言しないとエラーとなる、などの厳密さがあります。
ちょっと聞いた感じでは「えー、厳密にやんなきゃいけないの、めんどくさーい」って感じがしますが、現実は逆です。
厳密な解釈をしていない場合、エラーがなぜ発生したのかわからず、延々コードの上を彷徨い続ける悪夢が待っています。
オススメしたエディタ VSCode なら、厳密な書き方してないと知らせてくれるので、実質特に深く考えることなく厳密なコードが書けてしまいます。
故に 'use strict';
は必須の記述と言えます。
( function( _global ) {
'use strict';
// スクリプトを書く箇所
} )( this );
みたいな書き方をしてある場合もありますが、まず _global
が必要になることないと思います。
目的としては、グローバル領域に無名関数の中から、新たに変数や関数・クラスを作る場合に必要になるわけですが、個人的には使ったことありません。
グローバル領域を汚染しないように無名関数を使っているのですから、当初の目的に反しますからね。
どーしても必要な時もあると思いますが、必要になってから書いていいと思います。
this を _global に渡さなくても、RPGツクールMV は window がグローバル領域として設定されているので、window を使えば同様のことが可能です。
JavaScript が使われている環境によってはグローバル領域が必ずしも window であるわけではないので、this を _global に渡す方が適用範囲が広い書き方ということにはなります。
なお、どーしても必要な時の記事をSigureyaさんが書いているので、気になる方は参考にどうぞ。RPGツクールMVでclass記法によって書いたクラスをセーブデータに含める方法 - Qiita
無名関数・即時関数の細かいところ
さて、ここからは別に知らなくてもいいことですが、僕と同様に気になる人もいると思うので、どうしてこのような形でスクリプトが書かれるのか説明します。
実は JavaScript の仕様として、行頭(; の直後も含む)で function
を始めると、識別子のある関数と判断されます。
いきなり無名関数を書こうとしても、JavaScript は識別子があると思っていますから「識別子ないですよエラー(Function statements require a function name)」が発生してしまうのです。
なので、行頭と function
の間に何か挟めばいいのじゃないか、という話になります。
とっても裏技っぽい雰囲気になってきました!
挟むのは console.log(
みたいな関数でもいいのですが、当然ログ出力が行われるので、それは無駄な処理です。
+ や - あるいは ! などの単項演算子を頭に置いて !function(){}
みたいにも書けます。
しかし console.log(
程ではないですが、型変換などの処理が働いて無駄ですし、意外な副作用でバグが発生するかもしれません。
そこで一番副作用がないカッコが使われている、というわけです。
さて、無名関数は通常それを変数に代入するなり、関数の引数として指定するなりして、処理が必要なところへ渡します。
そうしないと「無名」なので関数が呼び出せなくなってしまいます。
そこで出てくる考え方が「即時関数(IIFE: Immediately Invoked Function Expression)」です。
では、即時関数とはなんなのか見ていきましょう。
まずは先ほどの説明したように、無名関数全体をカッコでくくり ( 無名関数 )
の形にします。
前述のように、このままでは「無名関数を受け取って即捨てる」ことになってしまいます。
そこで次に受け取った無名関数の後ろに、別のカッコをつけ ( 無名関数 )()
の形にします。
JavaScript はざっくりいうと「値としての関数の後ろにカッコをつけると、関数が実行される」という仕組みを持っています。
つまりここでは関数を定義して即実行していることになります。このような関数を「即時関数」と言うのです。
ちなみに、ここまでの理屈が分かると (function(){})()
の代わりに (function(){}())
(最後のカッコの位置が違う)と書いても動作に違いがないということも分かると思います。
関数の中で定義した変数は外から覗けないので、関数の中に外に出したくない(衝突させたくない)スクリプトは関数内に書くのが安全です。
とはいえ関数に名前があると関数そのものが、他から見える(アクセス可能)になってしまい衝突の危険が出てきます。
そこで無名関数を使うことで、関数へのアクセスも防ぎます。
これを即実行しているのは、このタイミングが無名のアクセス不能な関数にアクセスできる唯一のチャンスだからです。
即実行しているので (function(){})()
の外に書いたのと同じ実行タイミングで、関数の中に書いた変数・関数・クラス定義は行われます。
でも、(function(){})()
の外からは見えなくなっているので、他のプラグイン(やコアスクリプト)を気にせずに新たな識別子を作れて、非常に楽に安全なスクリプトが作れるというわけです。
素晴らしい!! 裏技だけどすばらしい!!
というかもう、みんな使ってて裏技でもなんでもなくなってますが。
そこで結論。
プラグイン作るの、結構簡単!