神無月サスケの波瀾万丈な日常

神無月サスケのツイッター(@ktakaki00)を補完する長文を書きます。

多機能フックローププラグインを支える技術

この記事は、ツクールMVの多機能フックローププラグインの記事です。
https://forum.tkool.jp/index.php?threads/851/
https://youtu.be/PBEbrzYt3xI

本日の先の記事と合わせてお読みください。

この記事は、このプラグインを作るにあたって直面した
技術的困難を中心に扱います。
専門的な内容なので、あまり興味がない人、プラグインが読めない人などは、
適当に読み流してください。

プラグインをダウンロードして、中を見てみましょう

さて、ここからはプラグインを実際にお見せしながら
説明していきたいと思います。
プラグイン単体(動作に必要な画像素材付き)は、以下のアドレスから入手可能です。
http://www.moonwhistle.org/tkoolMV/SuperiorHookRope.zip
こちらのプラグインは、前述のサンプルプロジェクトに入っているものより、
若干バージョンアップしています。

ロープが可変長ゆえの、アニメーションの動的生成の必要性

まず最初にこのプラグインを作るにあたって一番重要だったのは、
アニメーションを、データベースに登録するのではなく、
プラグイン内で動的に生成している、ということです。
これは、プラグイン利用者にデータベースでアニメーションを作ってもらうのが
煩わしいから、という理由だけではありません。
このプラグインは、ロープの長さが可変長に延びますが、
フックロープの動作は、アニメーションによって実現しています。
もし、データベースでアニメーションを登録するとすれば、
異なる長さごとに上下左右のアニメーションを作る必要があります。
例えば長さ最大7なら、0〜7まで8通り×上下左右4種類で、
32個のアニメーションが必要になります。
この手間は、ただごとではありません。
当然、現実的ではありませんね。
このため、プラグイン内で、プログラムで直接生成する必要が
出てくるというわけです。

アニメーションの動的生成のために:データ構造の解析方法

アニメーションを動的生成するために必要なのは、
データ構造を解析することです。
アニメーションのデータはJSON形式で、テキストファイルで見ることが可能です。
しかし、データの細かい意味が、それだけでは分かりません。
ツクールMVのヘルプにもJSリファレンスがありますが、そこには簡単な説明しかなく、
データの細かい説明はほとんどないため、解析が非常に困難と言えます。
そこで僕は、奥の手を使いました。
それはRPGツクールVX Aceのヘルプを参考にすることです。
両方のツクールをお持ちの方ならお気づきでしょうが、
RPGツクールMVのデータベースのデータ構造は、RPGツクールVX AceのRGSS3の
データ構造をベースにしています。
特に、アニメーションのように、追加機能が少ないものに関しては、
ほぼ1対1対応がある、と言っても過言ではありませんでした。
この事実は、データ構造を理解する上で非常に助かりました。
実際に、ご覧ください。

ご覧のように、日本語で、なおかつデータの詳細について説明してくれており、
情報量が全く異なり豊富なのが分かるでしょう。
こうしてめでたく構造を理解できた僕は、
アニメーションの動的生成を組むことに成功しました。
よくOSやツールなどの解析で言われることですが、
「データ構造が解析できれば、半分は解析できたも同然」
ということなのです。

タッチパネル対応。移動中いつフックロープを使うか

さて。次は、RPGツクールMV特有の課題です。
ツクールMVで作る以上、マルチプラットフォームを意識する必要があるため、
タッチパネル(、マウス操作)にも対応しなければなりません。
PCの場合、マウス操作以外でも操作は出来ますが、
スマートフォン移植前提の作品で使ってもらうなら、タッチパネル対応は必須でしょう。
そこで、タッチパネル移動時は、杭やフェッチ可能なイベントをクリックすると、
「フックロープが使えるところまで歩き、使えるようになった場所で使う」という
動作が必要になってくる、と考えました。
これは、それほど難しくなく、実装出来ました。
具体的には、プラグインの一番最後、Game_Character.prototype.findDirectionTo を
再定義している部分で処理している。興味のおありの方はお確かめいただきたい。
簡単に説明すると、
「フックロープ使用可能状態で、
なおかつ目的地がフックロープ関係のイベントの場合、
目的地への移動中、
プレイヤーが目的地へフックロープ到達可能の位置にいたら、
目的地の方を向いてフックロープ使用、プレイヤー移動はキャンセル」
ということです。

フックロープが壁を通過できなくする処理

フックロープは、壁を通過できないので、その前で止める必要があります。
これは、その座標に壁があるかどうかが判別できれば簡単です。
それでは、具体的にどうやるのでしょう。
実を言うと、このプラグインでは、A3タイル(壁の上部)とA4タイル(壁)の判定のみを
行っており、タイルA5やB〜Eで準備されたカスタムの壁は、通過します。
(ここのところは、今後のバージョンアップで設定可能にするなど、
対策が必要かもしれませんね)
A3タイルやA4タイルは、4層あるツクールMVのタイルの、最下層に位置します。
(「ちょっと待った、4層ではなく3層では?」という方がいらっしゃるかも知れませんが、
2つの上層と1つの下層の間に、タイルA2の一部を置く中層というものがあるんです)
そこで、最下層(レイヤー1)のタイルIDを確認します。
タイルIDはイベントコマンド「指定位置の情報取得」でも取得が可能な値です。
ただ、タイルIDで、それがタイルA3やA4なのかどうやって判定するのでしょう。
それは、タイルID仕様を知る必要があります。
これについては、「ツクールMV タイルID仕様」で検索すると、
調べてくれている人がいます。
https://www.f-sp.com/entry/2016/09/25/131242
この数値は一部RPGツクールVX Aceとも共通です。
これが分かれば、「目の前に壁(A3、A4タイル)があるか」はすぐできます。
自分で調べると結構骨が折れるので、
調べてくれている人に感謝、ですね。

力業で乗り切った点も

プレイヤーの移動とフックロープのタイミング合わせ、実は場当たり的

重要な点として、ツクールMVでは、プレイヤーの移動と、
アニメーションの表示は独立しています。
そして、フックロープは、アニメーションで実装されています。
フックロープを使う際、イベントをフェッチしたり、プレイヤーが一歩下がったり、
という場合、その動作にアニメーションをシンクロさせなければならないのですが、
これは、かなり場当たり的にやっています。
具体的には、フックロープの伸び方に応じて、最大の長さに達した時のウェイト数を変えたり、
逆にフェッチされるイベントの移動速度を、フックロープのアニメーションに
合わせたりしています。
本当に力業のため、フックロープの長さによっては、
若干タイミングがずれることもあるのですが、
ここはイベント移動とアニメーションのシンクロという点で、仕方ないことです。
なお、プレイヤーの移動ルートも、フェッチされるイベントの移動ルートも、
JavaScriptのオブジェクト記述形式、すなわちJSON形式で、直接リテラルで記述しています。
アニメーションのデータもそうですが、
ツクールMVはデータ構造がJSONというテキストで記述しやすい形式だからこそ、
実現できた部分が、このプラグインには多いのかもしれません。

アニメーションの関係から、一般的な(48x48サイズの)キャラにしか使えない

これもアニメーションの見た目を自然にするために、力業でのりきった点です。
フックロープを、プレイヤースプライトのどの座標から出すか……
下手をすると、上を向いているとき、頭や背中からフックロープが生えてくるように見えます。
そういったことをなくすため、プレイヤーが上下左右の向きで、
それぞれ座標を補正しています。
……ただ、これが原因で、ツクールMVの標準素材やジェネレーターで作成したような規格以外の、
特徴的なキャラクターが使うと、不自然な見え方になってしまいますが、
これはもう、現時点での仕様の限界、ということになります。

まとめ

いかがでしたでしょうか。これ以外にも、プラグインの中身を見ていただければ、
いろいろと分かりにくい部分で工夫しているのを理解してくれる人も
いらっしゃると思います。
今回、「多機能フックローププラグイン」として、ゼルダの伝説のギミックのように
「複数の機能を持たせる」「直観的にする」というものを作ったわけですが、
仕様的にも、技術的にも、いろいろ悩んだりしましたが、本当に考えていて、
苦になることはありませんでしたね。
むしろ、ゼルダの伝説がいかに偉大かが、よくわかりました。
何事も経験、ですよね。自分でやってみることで、改めて、凄さを知る。
僕にとって、このプラグイン制作の経験は、自らの身体の一部になっています。
この記事が、皆さまの何かのご参考になれば、幸いです。