Help us understand the problem. What is going on with this article?

RPGツクールMVにおけるパッド入力、Inputクラスの理解と改造 (後編)

More than 1 year has passed since last update.

前編 に「いいね!」がまったく頂けませんでしたが、めげずにRPGツクールMVのコードから学んでいきましょう。 特別編 もあります。

今回も、対象としているのは RPGツクールMV ver1.5.2 です。

複数のパッド

前編では複数のパッドに対応しているようでしたので、実際に試してみました。いつものXBOX360用コントローラーに加え、以下のいかにもRPGに合いそうなスーファミ的なパッドを繋いでみます。

image.png

で、実際にプレイしたところ、どちらもパッドも有効で、問題なく操作できることを確認できました。ちなみに、テストコードで表示されたそれぞれの id は以下になります。

"index":0,
"id":"Xbox 360 Controller (XInput STANDARD GAMEPAD)"

"index":1,
"id":"USB,2-axis 8-button gamepad   (Vendor: 0583 Product: 2060)"

同時に操作したら?

キーボードや複数のパッドの入力が同時に処理されることはわかりました。では例えば、2つのパッドを同時に操作したら、キャラはどのように動くのでしょうか?

これは実際に試すとわかるのですが、特に問題なく動いているようにみえます。前回の Input._pollGamepads 関数のしくみ のコードをよーく眺めるとわかるのですが

    var lastState = this._gamepadStates[gamepad.index] || [];  // ココ大事 (1)
    // (中略)
    for (var j = 0; j < newState.length; j++) {
        if (newState[j] !== lastState[j]) {                    // ココ大事 (2)
            var buttonName = this.gamepadMapper[j];
            if (buttonName) {
                this._currentState[buttonName] = newState[j];  // ココ大事 (3)
            }
        }
    }

つまりパッドごとに状態を保存(1)していて、状態が変化したとき(2)だけ、_currentState に反映させている(3)のです。

二つのゲームパッドを同時に操作してみると、最後に操作したほう、最後に押したボタンのほうが反映されるのがわかります。ちょっと面白いのは、片方のパッドでキャラを上に移動しようとし、もう片方のパッドで下に移動しようとした時で、これはキャラが止まります。というのも上下方向の移動を判断する以下の関数で

Input._signY = function() {
    var y = 0;

    if (this.isPressed('up')) {
        y--;
    }
    if (this.isPressed('down')) {
        y++;
    }
    return y;
};

と、ちゃんと同時入力に対応したロジックで判断コードが書かれているから。うーん、配慮が行き届いていて、勉強になりますね!

プラグインを準備

せっかく内容を理解したので、簡単なプラグインを書いてみましょう。

以下は RPGツクールMV プラグイン作成入門 (1) で公開している、私のプラグインのスケルトンです。プロジェクトの js/plugins フォルダに RTK_Test.js という名のテキストファイルを作成し、テキストエディタで以下の内容をコピペしてください。(保存時には文字コードをUTF-8にすることをお勧めします)

//=============================================================================
// RTK_Test.js  2016/07/30
// The MIT License (MIT)
//=============================================================================

/*:
 * @plugindesc テスト用プラグイン
 * @author Toshio Yamashita (yamachan)
 *
 * @help このプラグインにはプラグインコマンドはありません。
 * テスト用に作成したものなので、実際に利用する場合には適当にリネームしてください
 */

(function(_global) {
    // ここにプラグイン処理を記載
})(this);

もしくは ダウンロード用のリンク から js/plugins フォルダにダウンロードしてください。

そしてRPGツクールMVの「プラグイン管理」画面からこのプラグインを有効化します。

image.png

このプラグインはまだ空なので、有効化しただけではゲームになんの影響もありません。試しにゲームをプレイしてみて、何の影響もないことを確認しておくと良いでしょう。

左右トリガーを有効化してみる

まずは簡単な機能追加です。xbox360コントローラーにある左右のトリガを、ゲームで認識するようにしてみましょう。

さきほどの RTK_Test.js ファイルをテキストエディタで開き、「// ここにプラグイン処理を記載」とある部分に以下のコードを記載してみてください。

    Input.gamepadMapper[6] = 'pageup';
    Input.gamepadMapper[7] = 'pagedown';

これは前編の ゲームパッドから入力値 で説明したゲームパッド用のマップ情報に、左右トリガーのキーコード(6,7)と、対応する機能コード(pageup,pagedown)を追加したものです。

ゲームを実行してみると、右トリガーが右バンパー(右上のボタン)と同様に動作することが確認できます。これら2つのボタンが紛らわしいゲームパッドもありますので、そんな場合に役に立つかもしれません。なお

    Input.gamepadMapper[7] = 'menu';

とすれば、右トリガでメニューが開くようになりますよ。

右スティックを有効化してみる

次は、もう少し高度な、そしてちょっと危険な改造に挑戦してみましょう。システムで用意した Input._updateGamepadState 関数を置き換えて、コードを追加してみます。

RTK_Test.js ファイルをテキストエディタで開き、さきほど「// ここにプラグイン処理を記載」とあった部分に以下のコードを記載してみてください。

Input._updateGamepadState = function(gamepad) {
    var lastState = this._gamepadStates[gamepad.index] || [];
    var newState = [];
    var buttons = gamepad.buttons;
    var axes = gamepad.axes;
    var threshold = 0.5;
    newState[12] = false;
    newState[13] = false;
    newState[14] = false;
    newState[15] = false;
    for (var i = 0; i < buttons.length; i++) {
        newState[i] = buttons[i].pressed;
    }
    if (axes[1] < -threshold) {
        newState[12] = true;    // up
    } else if (axes[1] > threshold) {
        newState[13] = true;    // down
    }
    if (axes[0] < -threshold) {
        newState[14] = true;    // left
    } else if (axes[0] > threshold) {
        newState[15] = true;    // right
    }
    for (var j = 0; j < newState.length; j++) {
        if (newState[j] !== lastState[j]) {
            var buttonName = this.gamepadMapper[j];
            if (buttonName) {
                this._currentState[buttonName] = newState[j];
            }
        }
    }
    this._gamepadStates[gamepad.index] = newState;
};

これは rpg_core.js ファイルにある該当部分をコピー&ペーストで張り付けただけです。コードの変更はまだ実施していません。この段階でゲームをテストプレイし、何の影響もないことを確認しておきましょう。

そして for 文の前にある if () ... else ... 文を2つコピーして、axes[3] を axes[3] に、axes[2] を axes[2] に書き換えます。

    if (axes[3] < -threshold) {
        newState[12] = true;    // up
    } else if (axes[3] > threshold) {
        newState[13] = true;    // down
    }
    if (axes[2] < -threshold) {
        newState[14] = true;    // left
    } else if (axes[2] > threshold) {
        newState[15] = true;    // right
    }

これでokです。実際にゲームをプレイして、右スティックが左ステックと同様に利用できることを確認してください。

このプラグインを使用すると右手だけでプレイが可能ですので、お菓子などを食べながらプレイすることが可能ですね。少しだけ実用性があるかもしれません?

干渉に関する注意

なお、今回実施したシステム内の関数置き換えは、仕方なくとった手法で、あまりお勧めできるプラグインの実装方法ではありません。同じ関数を利用した他のプラグインとの干渉をおこす可能性があります。

今回のものは関数を置き換える方法で、機能を追加はするものの本来の動作は維持するので、もし他のプラグインと干渉した場合は、なるべく実行順序を先に(プラグインの順番を上に)することで対応できるかもしれません。

今回のプラグインのソース

ふたつの改造を含んだ、今回のプラグインのソースを全部掲載しておきます。自身で改造していろいろ楽しんでみてください。

//=============================================================================
// RTK_Test.js  2016/07/30
// The MIT License (MIT)
//=============================================================================

/*:
 * @plugindesc テスト用プラグイン
 * @author Toshio Yamashita (yamachan)
 *
 * @help このプラグインにはプラグインコマンドはありません。
 * テスト用に作成したものなので、実際に利用する場合には適当にリネームしてください
 */

(function(_global) {
    // ここにプラグイン処理を記載
    Input.gamepadMapper[6] = 'pageup';
    Input.gamepadMapper[7] = 'pagedown';

Input._updateGamepadState = function(gamepad) {
    var lastState = this._gamepadStates[gamepad.index] || [];
    var newState = [];
    var buttons = gamepad.buttons;
    var axes = gamepad.axes;
    var threshold = 0.5;
    newState[12] = false;
    newState[13] = false;
    newState[14] = false;
    newState[15] = false;
    for (var i = 0; i < buttons.length; i++) {
        newState[i] = buttons[i].pressed;
    }
    if (axes[1] < -threshold) {
        newState[12] = true;    // up
    } else if (axes[1] > threshold) {
        newState[13] = true;    // down
    }
    if (axes[0] < -threshold) {
        newState[14] = true;    // left
    } else if (axes[0] > threshold) {
        newState[15] = true;    // right
    }
    if (axes[3] < -threshold) {
        newState[12] = true;    // up
    } else if (axes[3] > threshold) {
        newState[13] = true;    // down
    }
    if (axes[2] < -threshold) {
        newState[14] = true;    // left
    } else if (axes[2] > threshold) {
        newState[15] = true;    // right
    }
    for (var j = 0; j < newState.length; j++) {
        if (newState[j] !== lastState[j]) {
            var buttonName = this.gamepadMapper[j];
            if (buttonName == 'shift') {console.log(JSON.stringify(gamepad))}  // テスト用
            if (buttonName) {
                this._currentState[buttonName] = newState[j];
            }
        }
    }
    this._gamepadStates[gamepad.index] = newState;
};

})(this);

おわりに

以上、RPGツクールMVでキーボード、そしてゲームパッドからの入力を処理しているコードを順に見てきました。またそれを改造する簡単なプラグインを作成してみました。

楽しんでいただけましたでしょうか?

RPGツクールMVという楽しいツールと、学ぶ価値のあるすてきなライブラリを制作した開発者の皆さんに感謝します。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away