javascript初心者がどうにかプラグイン作った覚え書き

自由に雑談できるトピックです。
sirloin_ryo
記事: 3
登録日時: 2019年3月10日(日) 13:20

javascript初心者がどうにかプラグイン作った覚え書き

投稿記事by sirloin_ryo » 2019年3月27日(水) 03:55

学校で習ったC言語くらいしかプログラミングの知識がなかったので
RPGツクールMVのためにjavascript勉強しようと入門書読んで。そして挫折した。
最近は見よう見まねでなんとか簡単な処理なら作れるようになってきたので
こうやって作ればなんとか動く、みたいなのをメモしておこうと思う。

どうせ他の人が似たようなもんたくさん書いてるけど、まあ情報は多い方がいいかもしれないし…頭の整理も兼ねてるし…

見る人が見ればきっと「ここはこうした方がいい」ってのが沢山あるコードだろうから
もし見つけたらコメントしてくれると嬉しいな。

「ピンポイントでこういう処理が欲しいけど、簡単なことすぎて逆に誰もプラグイン作ってない」とか
「他の人作ったのがあるにはあるけど多機能すぎて競合しちゃう」とか
「よく使うお決まりのイベント処理群を、1個のスクリプトコマンドにまとめたい」とか
そういうときに自分でプラグイン作ると便利。
そうでもないなら他人のプラグイン探すか諦めるかした方が早い。

*参考文献*
Javascriptが苦手な私によるプラグイン作成講座 - RPGツクールMVで感動ものを作る。
http://ktnhmv.jugem.jp/?eid=12

RPGツクールMVの構造を丸裸にする
https://qiita.com/krmbn0576/items/7d13d2c2f63d7dcf9300

ツクールMVスクリプトリファレンスwiki
http://rpgmaker-script-wiki.xyz/mvscriptwiki.php

RPGツクールMV プラグインコマンド集 リファレンス
https://docs.google.com/spreadsheets/d/1rOIzDuhLC6IqJPEFciYOmXWL_O7X9-hMValMs7DpWCk/edit#gid=1611179415




準備
まずテキストエディタを探す。
OS付属のメモ帳でも書けるには書けるが、やっぱり色分け機能くらいは欲しい。
私はBracketshttp://brackets.io/というフリーソフトを使っている。

保存時、文字コードをUTF-8(BOM無し)というものにしないとバグるらしい。
よく分からないが気を付けた方がいい。




ひな形作り

まずはツクール付属のプラグインの中身を参考に、ひな形を作る。

コード: 全て選択

//=============================================================================
// PluginTest.js
//=============================================================================

/*:
 * @plugindesc ここに書いた文章がプラグイン管理の一覧のところに出る
 * @author ここに作者の名前を書く
 *
 * @help ここに詳しいプラグインの使い方を書く
 */
(function() {

   //この中に処理を書く

})();

PluginTest.jsってところは任意の分かりやすい感じの名前に書き替えておく。
上のコードをテキストエディタにコピペして、
「なんとかかんとか.js」と名前を付けてUTF-8(BOM無し)で保存すればひな形は完成。

これから、欲しい処理ごとに基本の書き方を記述していく。




ケース1:元からある処理を消す系
元からある処理を、しないようにしてしまうプラグイン。
新しいことをしなくていいので一番作りやすい。競合は起こりやすいと思う。


例として、メニュー画面のレベルやHPの表示を消してしまうプラグインを作る。
バトルのないゲームを作るときに使えるかな。


さて、この機能をまずは「プラグインを作らずに」実現してみる。

まずは、今作っているゲームのデータのフォルダを開く。
デフォルトだと C:\Users\ユーザー名\Documents\Games\ゲーム名 にある。
その中のjsというフォルダに、ゲームの本体となるjavascriptで書かれたファイルが入っている。
rpg_○○.jsというのの中身を書き換えてしまえば、ゲームの動作も変わるのだ。

rpg_core.js (基本的な処理が書いてある、あんまりいじる機会はない)
rpg_managers.js (データベース読み出しなどについて)
rpg_scenes.js (タイトル画面とかショップ画面とか、シーンごとの処理について)
rpg_sprites.js (キャラやエフェクトの画像表示について)
rpg_windows.js (メニューやテキストのウィンドウについて)
rpg_object.js (マップイベントやスイッチや変数について)

このどれかに、「メニュー画面を映す」の処理が書いてあるはずなので頑張って探す。

それぞれに何が書いてあるのかは
https://qiita.com/krmbn0576/items/7d13d2c2f63d7dcf9300
を読めばなんとなく分かるかもしれない。私はよく分からない。


メニューウィンドウをいじりたいのだから、ここではrpg_windows.jsをいじる。
念のためコピーしてバックアップを取ってから、テキストエディタで開く。
そうすると意味不明な英語が6000行出てくる。

テキストエディタには検索機能というものがあるので(ショトカはCtrl+F)
それを使ってこの中からメニュー画面の処理を探す。

愚直に「Menu」で検索したら69件もヒットしてしまった。ここから探すのは大変だ。
今度は「Level」で検索してみる。7件ヒット。
それを辿ってみると、怪しい部分を発見する。

コード: 全て選択

Window_Base.prototype.drawActorSimpleStatus = function(actor, x, y, width) {
    var lineHeight = this.lineHeight();
    var x2 = x + 180;
    var width2 = Math.min(200, width - 180 - this.textPadding());
    this.drawActorName(actor, x, y);
    this.drawActorLevel(actor, x, y + lineHeight * 1);
    this.drawActorIcons(actor, x, y + lineHeight * 2);
    this.drawActorClass(actor, x2, y);
    this.drawActorHp(actor, x2, y + lineHeight * 1, width2);
    this.drawActorMp(actor, x2, y + lineHeight * 2, width2);
};

Window_Base.prototype.drawActorSimpleStatus というやつはfunction(関数)で、その関数の中身はこんなんですよ、という記述だ。と思う。

Name(名前)、Level(レベル)、Icons(アイコン)、Class(職業)という単語が並んでいるので、
これはきっとメニュー画面のステータスを表示するものに違いない。

では、このように要らないものをそぎ落としていく。
(javascriptでは//を付けると、行の終わりまでが「無いもの」として扱われる。コメントアウトという)

コード: 全て選択

Window_Base.prototype.drawActorSimpleStatus = function(actor, x, y, width) {
    var lineHeight = this.lineHeight();
    var x2 = x + 180;
    var width2 = Math.min(200, width - 180 - this.textPadding());
    this.drawActorName(actor, x, y);
    //this.drawActorLevel(actor, x, y + lineHeight * 1);
    this.drawActorIcons(actor, x, y + lineHeight * 2);
    this.drawActorClass(actor, x2, y);
    //this.drawActorHp(actor, x2, y + lineHeight * 1, width2);
    //this.drawActorMp(actor, x2, y + lineHeight * 2, width2);
};

コメントアウトしたら上書き保存し、テストプレイをしてみる。
メニューを開けば、レベルもHPバーも消えて随分と殺風景になっているはず。

ついでに、名前と職業の表示をもう少し下側にしてみる。
this.drawActorLevel(actor, x, y + lineHeight * 1); や
this.drawActorMp(actor, x2, y + lineHeight * 2, width2); を見るに、
x や x2 というのが表示位置のx座標(横位置)、y や y+lineHeight*1 というのがy座標(縦位置)を表しているらしい。

つまり名前と職業をもう少し下側に、例えばHPバーと同じ高さに表示するには

コード: 全て選択

    this.drawActorName(actor, x, y + lineHeight * 1);
    this.drawActorClass(actor, x2, y + lineHeight * 1);

こんな風にyをy + lineHeight * 1に置き換えてしまえばよい。
書き換えたらまたテストプレイしてメニューを開いてみると、いい感じの位置に名前と職業名が来る。


さて、これでもう「メニュー画面のレベルやHPの表示を消してしまう」という目的は達成した。
プラグインなんて作んなくてもゲーム本体のjsファイルを書き換えればなんだってできる。

でも、それはなんか怖い感じがする。
やっぱりやめて元に戻したいと思ったときのために、書き換えた場所を覚えておくのも大変だし
うっかり大事な部分を書き換えてしまって、バグってどうしようもなくなったりしそうだし。
そうならないためにプラグインというものがある。


では本題に入って、プラグインを作っていく。

書き換えてしまったrpg_windows.jsは元に戻しておき、
さっき作ったひな形の//この中に処理を書く のところにこんな風に書く。

コード: 全て選択

//前略
(function() {
   //この中に処理を書く
   Window_Base.prototype.drawActorSimpleStatus = function(actor, x, y, width) {
       var lineHeight = this.lineHeight();
       var x2 = x + 180;
       var width2 = Math.min(200, width - 180 - this.textPadding());
       this.drawActorName(actor, x, y + lineHeight * 1);
       //this.drawActorLevel(actor, x, y + lineHeight * 1);
       this.drawActorIcons(actor, x, y + lineHeight * 2);
       this.drawActorClass(actor, x2, y + lineHeight * 1);
       //this.drawActorHp(actor, x2, y + lineHeight * 1, width2);
       //this.drawActorMp(actor, x2, y + lineHeight * 2, width2);
   };

})();


(function() { と })(); で囲うようにして、さっき書き換えた部分をコピペするだけ。
こう書くことは、さっきたrpg_windows.jsを書き換えて上書き保存したのと同じ効果を持つらしいのだ。

出来上がったら○○.jsと名前を付けて保存し、
それをさっきのjsフォルダにあるpluginsフォルダに入れて、プラグイン管理を開いてそれを追加する。

テストプレイすれば、さっきrpg_windows.jsを書き換えたときと同じようにメニュー画面が変わっているのが分かるはずだ。
プラグイン管理からオフにしたり、削除したりすればもちろん元通りになる。

これで「メニュー画面からレベルやHPバーを消すプラグイン」が完成!!!やったね!!!

(同じくメニュー画面のステータス表示をいじるプラグイン(例えばTPバー追加機能のあるYEP_CoreEngineなど)と一緒に使うと、表示が消えなくなってしまうことがある。
そのときはプラグイン管理の表にて、このプラグインをYEP_CoreEngineなどより下に置くようにするといい。
表の上から順に処理されるからなんだとか。)




ケース2:元からある処理に付け足す系
元からある処理に、新しく処理を付け足す系。
競合は起こりにくいと思う。


今回は、「ニューゲームが選択されたときにあるスイッチをオンにする」プラグインを作る。
以前投稿したコレだ。
最初からONになってるスイッチを作れるプラグインhttps://tm.lucky-duet.com/viewtopic.php?f=5&t=7555

最初からオンになってるスイッチが欲しいなープラグインないかなーとGoogleで探していると、
(解決済み)コモンイベントを最初からスイッチなしで並列処理したい https://tm.lucky-duet.com/viewtopic.php?f=23&t=1436
このような記事をツクマテに見つけた。

この記事のTrbさんのコメントによれば、DataManager.setupNewGameというものがニューゲーム時の初期設定を行っていて、
そこにスイッチをオンにする処理を付け足してしまえば良いのだとか。

rpg_managers.jsの中を探してみると、こんな記述が出てくる。

コード: 全て選択

DataManager.setupNewGame = function() {
    this.createGameObjects();
    this.selectSavefileForNewGame();
    $gameParty.setupStartingMembers();
    $gamePlayer.reserveTransfer($dataSystem.startMapId,
        $dataSystem.startX, $dataSystem.startY);
    Graphics.frameCount = 0;
};

なにが書いてあるのかは、分かる必要はないので読み飛ばしていい。


javascriptで記述してスイッチをオンにするにはどうしたらいいのか。それはここを見ると調べられる。
ツクールMVスクリプトリファレンスwiki
http://rpgmaker-script-wiki.xyz/mvscriptwiki.php
ここにはイベントコマンドをスクリプトやプラグインから実行する方法が書いてある。

スイッチを操作するには、
$gameSwitches.setValue(スイッチID,true or false)
と書けばいいらしい。例えば101番のスイッチをオンにするには
$gameSwitches.setValue(101,true);
と書けばいい。(wikiには書いてないが、お作法的に最後に;を付けた方が良い)


そんなわけで、rpg_managers.jsの問題の個所にそれを書き足して

コード: 全て選択

DataManager.setupNewGame = function() {
    this.createGameObjects();
    this.selectSavefileForNewGame();
    $gameParty.setupStartingMembers();
    $gamePlayer.reserveTransfer($dataSystem.startMapId,
        $dataSystem.startX, $dataSystem.startY);
    Graphics.frameCount = 0;
   $gameSwitches.setValue(101,true);
};

こうして上書き保存すればニューゲーム時にスイッチ101番がオンになるようになる。
が、もちろん手っ取り早いからってこんなことしちゃいけないのはさっき言った通り。
動くことを確かめたら、ちゃんと元通りにして保存しなおしておく。

ケース1と同じように、この部分をプラグインのひな形へぶち込む。

コード: 全て選択

//前略
(function() {
   //この中に処理を書く
   DataManager.setupNewGame = function() {
       this.createGameObjects();
       this.selectSavefileForNewGame();
       $gameParty.setupStartingMembers();
       $gamePlayer.reserveTransfer($dataSystem.startMapId,
           $dataSystem.startX, $dataSystem.startY);
       Graphics.frameCount = 0;
      $gameSwitches.setValue(101,true);
   };
})();

んで同じように保存してjs\pluginsの中に入れてプラグイン管理で追加してしまえば
「ニューゲーム時にスイッチ101番がオンになるプラグイン」の完成である。


完成ではある…が、まだ改良すべき点がある。
ケース1でも最後に述べたように、別のプラグインがDataManager.setupNewGameを書き換えていた場合、競合を起こしてしまう。
せっかく別のプラグインが書き換えたのを、このプラグインが「rpg_managers.jsに書いてある元通りの処理 + スイッチオン処理」に上書きしてしまうのだ。

実は、ある方法を使うとその競合をどうにかすることができる。
この手法はケース1の処理を消す系プラグインでは使えない(と思う)。

こういう書き方をすると、「いったん元からある処理を行ってから、次に書き足した分の処理をする」みたいなことができる。

コード: 全て選択

//前略
(function() {
   //この中に処理を書く
   var hennsuu = DataManager.setupNewGame;
   DataManager.setupNewGame = function() {
       hennsuu.call(this);
      $gameSwitches.setValue(101,true);
   };
})();

またいきなり訳わからないのが増えた。

javascriptにも、ツクールと同じように変数というものがある。
ツクールみたいに最初から番号が振られたものが存在するとかではなく、使いたけりゃ自分で名前を付けて自分で作る必要がある。
var aiueo; と書くと aiueo という名前の変数が作れるし、
var nantoka = 3; と書くと nantoka という名前の変数を作って、ついでに3という数値を代入することができる。

ツクールの変数には数字と文字くらいしか入らないが、javascriptの変数はクソヤバくてなんでも入るらしい。関数まで入る。
さっき書いたコードでは、hennsuuという変数にDataManager.setupNewGameの内容をそのまま突っ込んでいる。
(本当はポインタだのなんだの難しいことしてるのかもしれないが、よくわからないのでそう思っておく)

そして、hennsuu.call(this);と書くと、それはさっき突っ込んだDataManager.setupNewGameの内容と同じことを行うらしい。
(多分。色々な説明を読んだがcallとthisの意味は未だによく分からない。javascriptは難しい。)

とまあこんな風に書くと、「DataManager.setupNewGameを『今あるDataManager.setupNewGameの内容をまず実行してから、スイッチ101番をオンにする』に書き換える」
のようなプラグインにできる。
もしこのプラグインが実行される前にDataManager.setupNewGameの中身が書き換えられていても、うまいこと元に戻さずに動いてくれるのだ。

hennsuuなんて名前だとダサいのでこう書き変える。

コード: 全て選択

//前略
(function() {
   //この中に処理を書く
   var _DataManager.setupNewGame = DataManager.setupNewGame;
   DataManager.setupNewGame = function() {
       _DataManager.setupNewGame.call(this);
      $gameSwitches.setValue(101,true);
   };
})();

元の関数名の最初にアンダーバーを付けた名前にするのがイカしているらしい。
他の人のプラグイン見てもみんなそうしてるから、そういう慣習なんだと思う。

これで「ニューゲーム時にスイッチ101番をオンにするプラグイン」が完成!!!やったね!!!
101番以外をオンにしたくなったらその都度コードの中の数字を書き換えればOK!


…なんだけど、一々コードを開いて書き換えて…とかしているとうっかり別なところも書き換えてバグらせそうでよくない。
それをしなくて済む機能がツクールMVにある。プラグインパラメータという。

他の人のプラグインには、プラグイン管理から「パラメータ」というのをいじることで、プラグインの動作を変えられるものがある。
パラメータを使って、オンにするスイッチの番号を設定できるようにしよう。

そのためにはこんな風に書く。(先ほど紹介した自作プラグインの中身である)

コード: 全て選択

//=============================================================================
// switchONatNewGame.js
//=============================================================================

/*:
 * @plugindesc ゲーム起動時、特定のスイッチをオンにします。自動実行コモンのトリガーにどうぞ。
 * @author @sirloin_ryo
 *
 * @param switchNo
 * @desc オンにしたいスイッチの番号 (0以上)
 * @default 0
 *
 * @help このプラグインには、プラグインコマンドはありません。
 */

(function() {
    var parameters = PluginManager.parameters('switchONatNewGame');
    var switchNo = Number(parameters['switchNo'] || 0);

    var _DataManager_setupNewGame = DataManager.setupNewGame;
   DataManager.setupNewGame = function() {
        _DataManager_setupNewGame.call(this);
       $gameSwitches.setValue(switchNo,true);
    };
})();

いろいろ増えた。

まず最初の部分に、@param (パラメータ名) のように書く。後に続いて@desc (説明) @default (デフォルトの値) と書く。

次に(function(){の後。
var parameters = PluginManager.parameters('switchONatNewGame'); と書く。
'switchONatNewGame'の部分は、そのプラグインのファイル名と同じになるようにその都度書き換えないといけない。

その後、
var switchNo = Number(parameters['switchNo'] || 0);
のようにすると、switchNoという変数にパラメータで設定された数字が入る。
パラメータに数字でないおかしなものが入っていたら、0が代入されるようになっている。この辺は「javascript Number」「javascript ||」でググるといい。

そうして最後に、
$gameSwitches.setValue(switchNo,true);
と、さっきまで101だった部分をswitchNoに置き換える。

これで「ニューゲーム時にパラメータで設定した番号のスイッチをオンにするプラグイン」が完成!!!

(パラメータ取得処理の書き方にはいろいろあって、もっと安全で良いやり方もあるらしい。今後また調べてみよう…)




ケース3:新しく処理を作る系
新しい処理をプラグインの中に書いて、それをプラグインコマンドで呼び出せるようにする系。


…を書こうと思ったけど力尽きたので、プラグインコマンドの使い方について参考になるサイトを載せておしまいとする。

プラグインコマンドの実装に最低限必要なコード | RPGツクールMV | LQDB
https://db.liberty-quest.com/rpgmakermv/minimum-code-to-add-plugin-command/

args[n]に入ってるのはなんでも文字列なので数値として扱いたいときはNumber()を使わないといけないという罠があるので覚えておく。

“雑談” へ戻る