RPGツクールMV
UCHU_MobileOperation

RPGツクールMVの仮想パッドプラグインの改造例

【おことわり】
筆者はRGSS3はある程度読みましたが、JGSSは「RGSS3の実装がこうだからこうだろう」程度の理解しかしておりません。またJGSS/JavaScriptについてもRGSS3/Rubyの知識から推測して書いているだけですので、その点はご承知おきください。

はじめに

RPGツクールMVの仮想パッドプラグインとしてよく知られたものにuchuzine氏によるUCHU_MobileOperation.jsがあります(Qiita内関連記事)。非常に使い勝手がよいのですが、Ver.1.1.4の既知の問題として、HideButton OnMessageをtrueに設定するとメモリリークを起こしてしまうことが知られています。
(ちなみにトリアコンタン氏のノベルゲーム総合プラグイン(GitHub)のノベルウィンドウだとスタックエラーが発生、100%落ちます)

上記で指摘されている通り、原因は変数に隔離したメソッドを上書きして呼び出す所にあるので、それらを改修するついでに、RPGツクールMVコアスクリプトVer.1.5で追加されたプラグインパラメータのタイプ指定や、新たな機能の追加を行ってみました。

ソースコード

UCHU_MobileOperation_Modified.js(Gistにあります)
別途、仮想パッド画像が必要になります。 http://uchuzine.x0.com/demo/ のものがそのまま利用できます。
(ヘッダを変更していないことから分かるかと思いますが、この修正版もMITライセンスのままです)

修正点

  • プラグインパラメータのタイプを設定
  • ゲーム内のスイッチで表示を切り替える機能の追加
  • HideButton OnMessageのメモリリークを修正
  • その他、微細なバグの修正

追加した機能

特定の番号のスイッチをONあるいはOFFにした時のみ、仮想パッドを表示する機能を追加しました。
これはHideButton OnMessageより設定が優先されます。
具体的な動作はHideButton OnMessageの修正にも関わるので次項をどうぞ。

HideButton OnMessage修正方針

updateメソッド(フレーム更新)で見ています。
マップ画面(Scene_Map)および戦闘画面(Scene_Battle)で判定が行われます。

UCHU_MobileOperation_Modified.js
        //UCHU_MobileOperationの同名メソッドとほぼ同じ
        Scene_Base.prototype.hideUserInterface = function() {
            if (Utils.isMobileDevice() || PRM.pcBtn) {
                Btn_hide = true;
                if(PRM.visible[0]){document.getElementById("Dirpad").style.zIndex = '0';}
                if(PRM.visible[1]){document.getElementById("okBtn").style.zIndex = '0';}
                if(PRM.visible[2]){document.getElementById("escapeBtn").style.zIndex = '0';}
            }
        };

        //UCHU_MobileOperationの同名メソッドとほぼ同じ
        Scene_Base.prototype.showUserInterface = function() {
            if (Utils.isMobileDevice() || PRM.pcBtn) {
                Btn_hide = false;
                if(PRM.visible[0]){document.getElementById("Dirpad").style.zIndex = '11';}
                if(PRM.visible[1]){document.getElementById("okBtn").style.zIndex = '11';}
                if(PRM.visible[2]){document.getElementById("escapeBtn").style.zIndex = '11';}
            }
        };

        //updateMainで表示状態をチェックする
        var dice2000_Scene_Map_updatemain = Scene_Map.prototype.updateMain;
        Scene_Map.prototype.updateMain = function() {
            dice2000_Scene_Map_updatemain.apply(this, arguments);
            //スイッチ番号が設定されている時
            if(PRM.hideBtnSwitch != 0){
                //どの値で表示するかはPRM.hideBtnSwitchValue(真理値)による
                //非表示状態にする
                if($gameSwitches.value(PRM.hideBtnSwitch) != PRM.hideBtnSwitchValue){
                    //表示状態(Btn_hideがfalse)にメソッドを呼び、行き先でBtn_hideをtrueにする
                    if(!Btn_hide) this.hideUserInterface();
                //表示状態にする
                }else{
                    //非表示状態(Btn_hideがtrue)にメソッドを呼び、行き先でBtn_hideをfalseにする
                    if(Btn_hide) this.showUserInterface();
                }
            //スイッチ番号が設定されておらず、Hide OnMessageがtrueに設定されている時
            }else if(PRM.hideBtn){
                //消去条件:メッセージウィンドウにテキストが存在する時&スクロールモードでない時&ウィンドウ位置が下の時
                //ここの条件式を変えれば消すタイミングは変えられます
                if($gameMessage.hasText() && !$gameMessage.scrollMode() && $gameMessage.positionType() == 2){
                    if(!Btn_hide) this.hideUserInterface();
                }else{
                    if(Btn_hide) this.showUserInterface();
                }
            }
        };

おわりに

日曜プログラマには、MITライセンスのプラグインを修正した場合にファイルネームやバージョン管理をどうすべきなのか、よく分かりませんでした。あと、競合をチェックする方法も分からなかったので、とりあえずリネーム+バージョンを別立てにすることでお茶を濁します。
ノベルゲーム総合プラグインで100%落ちる症状が改善しており、またVXAce(RGSS3)の経験からこの手の処理はupdateメソッドでチェックを掛ければほぼ間違いがなかったので、まず大丈夫かとは思いますが、修正の方針などを見た上でのご利用をお願いします。