RPGツクールと数学のブログ

RPGツクールと数学についてのブログです。

アクションRPGの基礎(RPGツクールMV)(2/4)

< 第1回

前回は剣を振れるようにしたので、今回は敵を設置して攻撃できるようにしてみましょう。敵がダメージを受けたり、HPを減らして倒してしまったりする処理は次回です。

敵への攻撃は次のような流れになります。

① 剣で攻撃できる位置にイベントがいるかどうか調べる
② そのイベントが攻撃の通るイベントかどうか調べる
③ 攻撃の通るイベントならその敵を攻撃受けるモードに設定
④ 攻撃を受けるモードならダメージを与える
⑤ ダメージが一定量に達したらやられる

①は剣を振ったときの処理で、指定した座標のイベントIDを調べればOKです。「指定位置の情報取得」コマンドでイベントIDを調べられます。その位置にイベントが無かったら、イベントIDは0が返ります。0以外だったらイベントがいることになりますね。

②が少し問題です。どんなイベントにも攻撃が通るようにしてしまうわけにはいかないので、攻撃が通るイベントかどうかの判定が必要になります。ツクールMVではスクリプトを使って、イベントの「名前」や「メモ」の中身を読み取ることが可能ですので、これを利用します。対象者となるイベントのメモ欄に[対象者]と入れておき、もしイベントのメモ欄に[対象者]があったら対象者と判定するのです。こうすれば、イベントをコピペするだけで敵を量産できるようになります。

ついでに、例えば人や宝箱の目の前で剣を振るのは不自然ですから、その抑制もします。人や宝箱のイベントのメモ欄には[非対象者]と入れておき、そのイベントの目の前で剣を振った場合は剣を振るエフェクトを表示しないようにします。

[対象者]
敵。攻撃の通る「対象者」であることを示す。

[非対象者]
人や宝箱。目の前で決定ボタンを押しても剣を振らない相手を示す。

③以降は次回以降に説明します。とりあえず今回は①~②を作っていきましょう。

敵を配置する

f:id:fermiumbay13:20190801182732p:plain

マップ上にランダムに動き回る敵を設置してみます。名前を「こうもり」にして、メモを「[対象者]」にします。メモにもともと何か書いていても、文字列のどこかに[対象者]があればOKです。中身はまだ何も設定する必要はありません。

f:id:fermiumbay13:20190801182659p:plain

人や宝箱の場合は、メモに[非対象者]を書いておきます。

[対象者]も[非対象者]も書いていないイベントについては、特別な処理は行いません。攻撃判定もないし、そのイベントの前で剣を振ることもできるものとします。

対象者・非対象者の取得イベントを作る

それでは「対象者」「非対象者」をそれぞれ取得しましょう。

f:id:fermiumbay13:20190801180104p:plain

まずは「対象者」取得用のイベントとして、コモンイベントに新しく「対象者取得」を追加します。

変数2番「攻撃x」
変数3番「攻撃y」
変数4番「対象者ID」
を新たに追加します。

座標({攻撃x},{攻撃y})の位置のイベントIDを変数「対象者ID」に代入します。

◆指定位置の情報取得:対象者ID,イベントID,({攻撃x},{攻撃y})
◆条件分岐:対象者ID ≠ 0
 ◆文章:なし,ウィンドウ,下
 :  :\>対象者は\V[4]番だよ!
 ◆
:分岐終了

対象者IDが0だとイベントが見つからなかったということなので、0じゃないときに限りメッセージを表示することにします。

続いて、非対象者用のイベント「非対象者取得」も同様に作ります。変数4番の「対象者ID」は使いまわしましょう。発見したことを示すスイッチとして、スイッチ5番「目の前に非対象者」を追加します。

◆指定位置の情報取得:対象者ID,イベントID,({攻撃x},{攻撃y})
◆条件分岐:対象者ID ≠ 0
 ◆スイッチの操作:#0005 目の前に非対象者 = ON
 ◆
:分岐終了

対象者・非対象者を探す

次に、「剣を振る」を次のように書き換えます。◇から始まる行が新たに追加した行です。長いけど、何してるかは後述するのでさらっと飛ばしてください。

◇変数の操作:#0002 攻撃x = プレイヤーのマップX
◇変数の操作:#0003 攻撃y = プレイヤーのマップY
◇スイッチの操作:#0005 目の前に非対象者 = OFF
◆条件分岐:プレイヤーが下を向いている
 ◇変数の操作:#0002 攻撃x -= 1
 ◇コモンイベント:対象者取得
 ◇変数の操作:#0003 攻撃y += 1
 ◇コモンイベント:対象者取得
 ◇変数の操作:#0002 攻撃x += 1
 ◇コモンイベント:対象者取得
 ◇コモンイベント:非対象者取得
 ◇変数の操作:#0002 攻撃x += 1
 ◇コモンイベント:対象者取得
 ◇変数の操作:#0003 攻撃y -= 1
 ◇コモンイベント:対象者取得
 ◇条件分岐:目の前に非対象者がOFF
  ◇アニメーションの表示:プレイヤー,剣↓
  ◇
 :分岐終了
 ◆
:分岐終了
◆条件分岐:プレイヤーが左を向いている
 ◇変数の操作:#0003 攻撃y -= 1
 ◇コモンイベント:対象者取得
 ◇変数の操作:#0002 攻撃x -= 1
 ◇コモンイベント:対象者取得
 ◇変数の操作:#0003 攻撃y += 1
 ◇コモンイベント:対象者取得
 ◇コモンイベント:非対象者取得
 ◇変数の操作:#0003 攻撃y += 1
 ◇コモンイベント:対象者取得
 ◇変数の操作:#0002 攻撃x += 1
 ◇コモンイベント:対象者取得
 ◇条件分岐:目の前に非対象者がOFF
  ◇アニメーションの表示:プレイヤー,剣←
  ◇
 :分岐終了
 ◆
:分岐終了
◆条件分岐:プレイヤーが右を向いている
 ◇変数の操作:#0003 攻撃y -= 1
 ◇コモンイベント:対象者取得
 ◇変数の操作:#0002 攻撃x += 1
 ◇コモンイベント:対象者取得
 ◇変数の操作:#0003 攻撃y += 1
 ◇コモンイベント:対象者取得
 ◇コモンイベント:非対象者取得
 ◇変数の操作:#0003 攻撃y += 1
 ◇コモンイベント:対象者取得
 ◇変数の操作:#0002 攻撃x -= 1
 ◇コモンイベント:対象者取得
 ◇条件分岐:目の前に非対象者がOFF
  ◇アニメーションの表示:プレイヤー,剣→
  ◇
 :分岐終了
 ◆
:分岐終了
◆条件分岐:プレイヤーが上を向いている
 ◇変数の操作:#0002 攻撃x -= 1
 ◇コモンイベント:対象者取得
 ◇変数の操作:#0003 攻撃y -= 1
 ◇コモンイベント:対象者取得
 ◇変数の操作:#0002 攻撃x += 1
 ◇コモンイベント:対象者取得
 ◇コモンイベント:非対象者取得
 ◇変数の操作:#0002 攻撃x += 1
 ◇コモンイベント:対象者取得
 ◇変数の操作:#0003 攻撃y += 1
 ◇コモンイベント:対象者取得
 ◇条件分岐:目の前に非対象者がOFF
  ◇アニメーションの表示:プレイヤー,剣↑
  ◇
 :分岐終了
 ◆
:分岐終了
◆ウェイト:15フレーム
◆スイッチの操作:#0002 剣を振る = OFF

まず、攻撃x, 攻撃yに主人公の座標を代入しておきます。その後、例えば下を向いていたら次のように座標を変えながら、その座標における「対象者取得」「非対象者取得」コマンドを実行します。

f:id:fermiumbay13:20190801184855p:plain

白枠の位置に主人公がいて、黄色い枠が敵への当たり判定になるわけですね。剣を振った瞬間に黄色い枠の座標にいた敵に攻撃が通じるはずです。一方、人や宝箱を示す非対象者は目の前にいるかどうかだけを調べたいので、青い③のタイミングでのみ取得します。③に非対象者がいなければ、剣を振るエフェクトを表示します。

同様にして他の3方向も作ります。

f:id:fermiumbay13:20190801181148p:plain

試しに敵をコピペして増やし、剣を振ってみると、剣の当たった位置のイベントIDが画面に表示されるはずです。上の写真では剣のエフェクトが消えた後ですが……

対象者・非対象者を判定する

そのイベントが実際に「対象者」であるか、「非対象者」であるか、それぞれ判定する処理を入れます。対象となるイベントの「メモ」に[対象者]、または[非対象者]の文字列が入っているかどうか調べます。

対象者も非対象者も、文字列が違うだけでスクリプトの内容は同じなので、「対象者」の例で説明します。

「メモ」に[対象者]の文字列が入っているかを調べたいのですが、これは標準機能ではできないので、スクリプトを使います。条件分岐のスクリプトの欄に次のスクリプトを入力してください。

~$dataMap.events[$gameVariables.value(4)].note.indexOf("[対象者]")

おまじないみたいにして使っていいのですが、これはイベントIDが変数4番の値になってるイベントのメモに[対象者]の文字列が含まれているか?という意味のスクリプトです。

$gameVariables.value(4)
=値「変数4番」

$dataMap.events[n].note
=文字列「n番のイベントのメモ」

str.indexOf("[対象者]")
=値「文字列strの中に[対象者]が含まれている位置(無かったら-1)」

条件の判定結果は、真(しん)、または偽(ぎ)といいます。判定結果が正しい場合は真といって条件分岐の中を通り、正しくない場合は偽といって条件分岐の中を通りません。

このスクリプトの先頭に付けた~はビット反転といって、答えが-1になるものだけを0(偽の意味)にする効果があります。[対象者]が無かったら-1になるので、このとき偽になり、どこかに含まれていれば0以外(真の意味)となります。

要するに[対象者]の文字列があったら条件分岐を通る、という意味になります。

↓変数に関して、これらはよく使うスクリプトなので、知っておくと便利です。

$gameVariables.value(n)
=値「変数n番」

$gameVariables.setValue(id, n)
=命令「変数id番に値nを代入する」

これを利用すると、例えば変数番目の変数に値を代入、ということもできます。

$gameVariables.setValue(3, $gameVariables.value($gameVariables.value(10)))
=命令「変数3番に変数「変数10番」番の値を代入する」

MVでは標準機能でこういうことが出来ないので、スクリプトで書くしかありません。実際、変数を使って規模の大きなシステムを作るときには必要不可欠な機能です。

「対象者取得」は次のように変わります。

◆指定位置の情報取得:対象者ID,イベントID,({攻撃x},{攻撃y})
◆条件分岐:対象者ID ≠ 0
 ◇条件分岐:スクリプト:~$dataMap.events[$gameVariables.value(4)].note.indexOf("[対象者]")
  ◆文章:なし,ウィンドウ,下
  :  :\>対象者は\V[4]番だよ!
  ◆
 :分岐終了
 ◆
:分岐終了

f:id:fermiumbay13:20190801185952p:plain

こうすれば、[対象者]がメモに入っていないイベントは斬っても反応しません。

同様に「非対象者取得」を次のようにすれば、人や宝箱の前で剣を振らなくなります。

◆指定位置の情報取得:対象者ID,イベントID,({攻撃x},{攻撃y})
◆条件分岐:対象者ID ≠ 0
 ◇条件分岐:スクリプト:~$dataMap.events[$gameVariables.value(4)].note.indexOf("[非対象者]")
  ◆スイッチの操作:#0005 目の前に非対象者 = ON
  ◆
 :分岐終了
 ◆
:分岐終了

それでは次回は実際に、敵にダメージを与えてみます。

> 第3回