神無月サスケの波瀾万丈な日常・はてなブログ編

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

ムンホイXPの地味な技術:その3.フィールドマップのあれこれ

普通のRPGだと、ウィンドウのレイアウトとか戦闘のシステムやレイアウトなどに凝るものらしいですが、本作品ではそういうのは極力据え置きにして、マップ画面の仕様とかそういうものばかりいじっていました。

このため、町を移動するのが結構意味も無く楽しかったりするでしょう。それは、システム的に地味なことをたくさんしているからかもしれません。

プライオリティの導入

RGSSゲームライブラリ、Tilemapクラスにはプライオリティという概念が導入されています(RPGツクールXPのみ。VX以降は廃止)。タイルごとにプライオリティを、なし(0)から5までの間で設定することで、そのタイルの位置する「高さ」を設定しているのです。

ムンホイXPのシステムでは、この考え方を Game_Character オブジェクト(イベントやプレイヤーなど)にも導入し、タイルとの親和性を高めました。

Game_Character#priority の仕様

具体的には、Game_Character に @priority というインスタンス変数を追加しています。priority の取ることの出来る値は、タイルと同様0〜5で、これにより、同じプライオリティにあるタイルと同じ高さに表示されることになります。

これによって、様々な仕様を変更しています。例えば、Character#screen_z は、priority 導入により、それを用いた計算式に拡張しています。

プライオリティを使った多層処理

通常はプレイヤーやイベントのプライオリティは1ですが、このプライオリティを操作することで、多層処理を行っています。具体的には、以下の例が挙げられるでしょう。金網の下をくぐりぬけたり、上を通ったりすることです。


ここでプレイヤーが金網の下を通っている時のプライオリティは1、金網の上に乗っている時のプライオリティは3です。プライオリティ1の時を「下層」、プライオリティ3の時を「上層」と呼んでいます。

そして、タイルのプライオリティは次の方針に基づいて決められています。

  • 0=プレイヤーの下にあるもの(床や地面など)
  • 1=プレイヤーと同じ高さにあるもの(民家の壁など)
  • 2=プレイヤーの上にあるが上層になると下になるもの(屋根など)
  • 3=プレイヤーが上層に出たとき同じ高さにあるもの(屋根の上にある障害物)
  • 4以上=プレイヤーが上層に出ても上にあるもの(アドバルーンなど)
マップエディタでの設定方法

タイルにあったプライオリティをイベントに拡張するにあたって、イベント名に「@2」や「@4」などの「@+数字」が付いていた場合、その数字を、そのイベントのプライオリティとして設定することにしています。イベントを上層に置くためには、名前に「@3」という文字を入れると良いわけです。下層に置く場合は、デフォルトのプライオリティが1のため、わざわざ「@1」と書く必要はありません。

なお、下層と上層では、タイルの通行判定が違います。このため、上層の通行判定だけ、別のタイルセットのものを使っています。ムンホイXPでは、タイルセットはひとつにまとめており、ID=1番のものを使用していますが、上層の場合はID=2番の通行判定を使っています。

プレイヤーの上層と下層の切り替え

イベントから「スクリプトの呼び出し」で以下のようにすると変更できるようにしています。
下層に変更する場合:

$game_player.set_priority(1)

上層に変更する場合:

$game_player.set_priority(3)

これは、コモンイベントの1番(上層→通常)と2番(通常→上層)から呼び出されいます。イベントから、これらのコモンイベントを呼び出して切り替えます。ただし、実際にはもう少し複雑な処理を追加しているため、興味がある人は実際にコモンイベントおよび、そこから呼び出されているスクリプトを確認してみてください。

結論:多層処理だけなら、他のより簡単な実装方法がある

以上、ムンホイXPでの多層処理のメカニズムでした。実際には多層処理を行いたいだけなら、わざわざこんなことをしなくても、より簡単な方法はいくつかあります。

例えば、RPGツクール2000の方法として、同じタイルセット(2000ではチップセットという)グラフィックを使って、通行判定だけを変更したものを準備します。通常と上層を切り替えるタイミングで、イベントコマンド「チップセットの切り替え」を行えば、通行判定やプライオリティを変更させることが出来ます。XPには「タイルマップの切り替え」はイベントコマンドにはありませんが、同様のことはスクリプトで出来ると思います。

また、RPGツクール95では、オリジナルのムンホイでは、屋上など、上層の地形は「海」になっています。上層に出る時は、RPGツクール95特有の機能「主人公タイプの変更」でタイプを「通常」から「船」に変更することによって、海は通れるが普通の地形は通れない、つまり屋上のタイルは動けるが、別のところには行けない、というようにして実現しています。

以上を参考にすれば、より簡単な方法はあるのですが、ここではデータの一貫性があった方が拡張がしやすいと思い、今回のような方法を採用しました。

補足:この方式の採用を検討する人への注意

もうひとつ重要な注意があります。ムンホイではプレイヤーなど、主要なキャラクターの大きさが32までになっています。これはVXやVX Aceのキャラチップに近い仕様です。このため、これらのプライオリティの設定で問題ないのですが、より大きなキャラチップを使用している人が多いでしょう(32x64など)。この場合、この設定だけでは不十分な場合があります(キャラクタがプライオリティ2の屋根を突き破る、といったことがある)。このため、この考えを導入したい人は、タイルのプライオリティの値を吟味する必要があるでしょう。

斜め移動

はじめに:なぜ斜め移動はRGSSに標準搭載されないのか

斜め移動は、結構スクリプト素材も出回っており、単に斜めに移動するというだけなら、大して難しくはありません。そもそも、RGSSレベルでも、イベントコマンドでは斜め移動が標準搭載されており、これなら、プレイヤーの移動にも斜め移動が採用されてもおかしくないように思えます。(更に言えば、イベントコマンドでの斜め移動はRPGツクール2000の時代からありましたよね)

しかし、実際はRPGツクールVX Aceで、多用な機能が標準搭載されたRGSS3でさえ、斜め移動を採用しませんでした。これはなぜでしょうか。

僕に考えられる大きな理由の一つは、「ユーザー側が考慮しないと、斜め移動の見た目が不自然に見える場面が多くなるから」だと考えられます。

斜め移動が不自然に見える3つの例

まず最初に。斜め移動の通行判定は、RGSSではどのように組まれているのか、見てみましょう。左下に移動する場合(Game_Character#move_down_left)を引用します:


# 下→左、左→下 のどちらかのコースが通行可能な場合
if (passable?(@x, @y, 2) and passable?(@x, @y + 1, 4)) or
(passable?(@x, @y, 4) and passable?(@x - 1, @y, 2))

コメントにあるように、左下に行く場合「下→左、左→下 のどちらかのコースが通行可能な場合」は通行可能で、通行の処理を行うのです。

確かにこれなら、通行できないはずの地形に迷い込むようなことはありません。しかし、見た目としては、非常に不自然になることがあります。僕がテストプレイしていて見つけた(そして対処した)大きな問題点を3つにまとめ、それぞれ次の名前で呼ぶことにしました。

  • 梯子
  • 吹き抜け
  • プレート(壁)

これらを、ひとつずつ説明して行きます。

梯子

次のような移動を考えます。すなわち、階段や梯子のような地形に、斜め移動で入る(あるいは出る)場合です。

この時、「壁の中を斜めに横切って、階段(梯子)の途中の部分に飛び移っている」というように見えてしまいます。

吹き抜け

次のような移動を考えます。

この時、「何もない吹き抜けを斜めに横切って、空中移動している」ように見えてしまいます。

プレート(壁)

次のような移動を考えます。移動先は「下への移動のみが不可」という、平らな壁(プレート)のような地形です。プレートに斜めに入る(または出る)場合です。


この時、「身体半分を壁にめり込ませながら移動している」ように見えてしまいます。

斜め移動禁止地形の導入

そこで、ムンホイXPでは、タイルに「斜め移動禁止」属性を追加しました。上記の3つのうちどれであるかは、自動判定されます。すなわち……

  • 「斜め移動禁止」で、通行不可であれば、吹き抜けタイル
  • 「斜め移動禁止」で、通行可能で、プライオリティがプレイヤーより低ければ梯子タイル
  • 「斜め移動禁止」で、通行可能で、プライオリティがプレイヤーより高ければプレートタイル

ということです。

なお、この「斜め移動禁止」属性は、地形タグで実装するのが一般的でしょうが、本作では茂み(0x40)を使用していないため、茂み属性を「斜め移動禁止」として使用しています。

スクリプトでの斜め移動禁止の実装

Game_Map#ladder? で梯子判定を、 Game_Map#wellhole? で吹き抜け判定をしています。プレート判定は、梯子判定と処理が共通する部分が多いため、Game_Map#ladder? の引数を変えることで、まとめて判定します。

これらのメソッドを、斜め移動の際に呼び出し、斜め移動禁止でないか判定します。Game_Character#move_lower_left に追加された処理を引用します:


# ★斜め移動禁止地形の場合
if $game_map.ladder?(@x, @y, @priority, true) or
$game_map.ladder?(@x - 1, @y + 1, @priority, false) or
$game_map.wellhole?(@x, @y + 1, @priority) or
$game_map.wellhole?(@x - 1, @y, @priority) then
return false unless @through
end

こうすることによって、斜め移動禁止の地形で、斜め移動を行わせないことが可能です。

斜め移動が行えない場合通常移動を行うことが大事

さて。斜め移動を制限したわけですが、ここで移動の快適さのために重要なことがあります。それは、例えば「右上に動こうとして動けなかった場合、右か上に動ける場合、その方向に移動を行う」ということです。

すなわち、斜め移動が行えなくても、通常移動が可能なら、それをするということです。この考え方は、斜め移動禁止を導入しなくても重要ですが、斜め移動禁止を入れて制限を多くするなら、なおさら必要です。

なお、右上に動こうとして動けなかった場合で、右と上の両方に動ける場合はどちらに動けばいいのでしょう。どちらでもいいのでしょうが、僕は経験則から、上下の動きの方を優先しています。このあたりは、議論の余地があると思いますので皆さんも調整しながら考察するとよろしいでしょう。

これらの実装は、Game_Player#update の中に書かれていますので、興味のある方は解析してみてください。

結論:斜め移動で一番厄介なのは見た目の問題

斜め移動は常に見た目との戦いなのです。つまり、斜め移動を無くすか制限を強くすれば解決するのでしょうが、それではプレー時の爽快感が失われてしまいます。よって若干面倒でも、こだわっていきたい、そんな僕のこだわりをどうか皆さんも理解して欲しいのです。

なお、今回、斜め移動の見た目問題については、一番端的な部分を押さえたつもりですが、まだまだ、他にもあるように思えます。こういうのは、理屈ではなく見た目の問題なので、探すだけ見つかるでしょう。ぜひ、皆さんも、斜め移動を導入するときは、このような見た目の問題を意識してみてください。

移動速度(ダッシュの速度)

もう一つ小さなことですが、指摘しておきたいのは、移動速度の問題です。

RPGツクールXPの移動速度は、1〜6まで指定でき、数が大きいほど速いのです。プレイヤーのデフォルトの移動速度は4なのですが、これは少し遅く感じます。一方で5にすると、少し速く感じてしまいます。何とか、この中間が取れないものでしょうか。

本作では、ここをいじって、通常の移動速度を4と5の中間、低速ダッシュを5と6の中間、高速ダッシュを6の移動速度にしています。

実装

プレイヤーやイベントの移動速度については、Game_Character#update_move で、以下のように定義されています。


# 移動速度からマップ座標系での移動距離に変換
distance = 2 ** @move_speed

ここで @move_speed が1〜6の値を取るのです。1タイルは32ピクセルですが、これが論理座標で128の大きさになります。よって、例えば @move_speed が 6 なら、distance は2の6乗、すなわち64になり、2フレームで1タイルを移動する計算になります。@move_speed が5なら4フレーム、4なら8フレームです。

そこで、中間の速度を取るためには、3フレームや、6フレームで1タイル移動することを考えてやればいいのです。そこで、先程のコードの後に、以下を追加しています。


# ★若干移動速度アップ
if @move_speed == 4
distance = 22
elsif @move_speed == 5
distance = 43
end

これで、@move_speed が4の時、6フレームで、@move_speed が5の時、3フレームで1マス進むようになります。実際に計算すると進む座標の数は128より大きくなるように見えますが、多くなった部分は後の処理で丸められるので、問題ありません。

フレームレートをいじるよりも簡単な解決方法

ここで紹介した方法は、驚くほどシンプルに移動速度を変える方法です。

ツクールXPが出た当時は、内部フレームレートを通常の40fps から 60fps に変更することによって、移動速度を1.5倍にするという人が結構いました。CPUの性能が上がった今なら、それでも問題ないかもしれませんが、フレームレートを増やすということは、負荷を増やすということです。カクカクと処理落ちする人も多くなったのではないでしょうか。

移動速度のために処理落ちを増やすなんてナンセンスです。それよりは、こういうシンプルな方法がありますよ、ということです。

なお、この手法は、RGSS2(RPGツクールVX)以降でも比較的簡単に実装できます。

結論

以上、マップ関連のあれこれを見てきました。自分で読み返していて、つくづく地味なことやっているなあ、と痛感したのでありました。でも、僕は確信しています。本当に重要な技術は、レイアウトとか演出とかを派手にすることではなく、こういう縁の下の力持ち的な地味なものなんだ、ということを。

今回の紹介が皆さんの参考になれば幸いです。