アクションRPGの基礎(RPGツクールMV)(応用編 敵の思考)
RPGツクールMVでアクションRPGを作る基礎の応用記事です。ベースになっているのはこちらです。
今回は敵の思考を充実させて、色々な行動をとるためのサンプルを作成します。以下の流れで作成します。
1. 敵に「経過時間」のパラメータを持たせて、それをもとに行動を決めさせる
2. 「剣を振る」の、敵が主人公を攻撃する版を作成する
敵に経過時間のパラメータを持たせる
敵の行動パターンを作るためには、敵自身が、自分は行動開始してどれぐらい時間が経ったのか、というのを把握する必要があります。
これまでは敵のダメージ量を、enemyDamageというスクリプトの変数で扱っていました。これと同じような感じで、enemyTimeという、敵の経過時間を表す変数を新しく作りましょう。
コモンイベント「初期化」に、以下の◇の行を追加します。
◆スクリプト:enemyDamage = new Array(999);
: :for(var i = 0; i < 999; i++){
: : enemyDamage[i] = 0;
: :}
◇スクリプト:enemyTime = new Array(999);
: :for(var i = 0; i < 999; i++){
: : enemyTime[i] = 0;
: :}
◆スクリプト:for(var eventID = 1; eventID <= 999; eventID++){
: : var mapID = this._mapId;
: : $gameSelfSwitches.setValue([mapID, eventID, "A"], false);
: : $gameSelfSwitches.setValue([mapID, eventID, "B"], false);
: :}
◆変数の操作:#0006 ため量 = 0
◆スイッチの操作:#0001 キー入力受付 = ON
◆スイッチの操作:#0003 主人公被ダメージ無敵 = OFF
これで、敵の経過時間を表すenemyTime変数が追加されました。初期化の度に0に戻すようにしています。
次に、行動パターンを作りたい敵の1ページ目を変更します。今まで敵の1ページ目は、触れたらダメージを受けるというものにしていましたが、そうではなくて、敵が思考して行動パターンを決めるページに変更してしまいます。
(今回の作成方法では、「敵に触れたらダメージ」と両立させることは出来ません。うまく作ってあげれば両立できるとは思うのですが、複雑化しそうなので、今回は割愛させてください)
敵の1ページ目を、次のようなものにします。
トリガーを、「並列処理」にしておきます。実行内容は、仮に以下のようにしてみてください。
◆条件分岐:スクリプト:enemyTime[this.character(0)._eventId - 1] == 60
◆文章:なし, ウィンドウ, 下
: :\>敵が行動するぞ
◆
:分岐終了
◆条件分岐:スクリプト:enemyTime[this.character(0)._eventId - 1] >= 60
◆スクリプト:enemyTime[this.character(0)._eventId - 1] = 0;
◆
:分岐終了
◆スクリプト:enemyTime[this.character(0)._eventId - 1]++;
◆
enemyTime[this.character(0)._eventId - 1]は、自分自身の経過時間という意味です。enemyTime[this.character(0)._eventId - 1]++とすると、自分自身の経過時間が1上がります(+= 1と書いても同じ意味です)。これは、60になるとちょうど1秒を表わすものですので、ここでは試しに60になったとき(=1秒経ったとき)文章を表示するというサンプルにしています。さらにその後の条件分岐は、経過時間が60以上になったときに、経過時間を0に戻すというものになります(enemyTime[this.character(0)._eventId - 1] = 0;は、経過時間を0に戻すという意味です)。こうするとまた1秒後に文章が表示される、というのがループするようになります。
スクリプトを書くときは、イコールの数に注意してください。=が1個は、右辺のものを左辺に代入するという意味になり、=が2個のもの(==)は、左辺と右辺が等しいかどうか判定するという意味になります。
こんな感じですね。例として文章の表示をさせるようにしてみましたが、この部分を敵の行動処理に差し替えてやれば、敵が1秒おきに行動をするよう作ることができます。
「剣を振る」の敵版を作る
では、試しに「剣を振る」の敵側バージョンを作成して、1秒おきに剣を振らせてみましょう。そのためにはまず、コモンイベント「対象者取得」の、主人公判定版を作成します。
コモンイベント「対象者取得(敵→主人公)」を、以下の内容で新規作成します。
◆変数の操作:#0011 主人公x = プレイヤーのマップX
◆変数の操作:#0012 主人公y = プレイヤーのマップY
◆条件分岐:攻撃x = 主人公x
◆条件分岐:攻撃y = 主人公y
◆コモンイベント:主人公がダメージ
◆
:分岐終了
◆
:分岐終了
◆
11番,12番として、主人公x、主人公y、という変数を新しく追加しました。(番号はなんでも構いません)
主人公を取得する処理は、スクリプトが無くても実装できます。単純に、変数「攻撃x」「攻撃y」が、主人公の座標に一致するかどうか判定して、主人公なら、「主人公がダメージ」を呼び出すだけです。
そして、上記を使ってコモンイベント「剣を振る(敵)」を、以下の内容で新規作成します。このイベントは、主人公版の「剣を振る」とは異なり、敵からコモンイベントの呼び出しによって呼び出されるだけですので、トリガーは「なし」でOKです。
◆変数の操作:#0002 攻撃x = このイベントのマップX
◆変数の操作:#0003 攻撃y = このイベントのマップY
◆条件分岐:このイベントが下を向いている
◆アニメーションの表示:このイベント, 剣↓
◆変数の操作:#0002 攻撃x -= 1
◆コモンイベント:対象者取得(敵→主人公)
◆変数の操作:#0003 攻撃y += 1
◆コモンイベント:対象者取得(敵→主人公)
◆変数の操作:#0002 攻撃x += 1
◆コモンイベント:対象者取得(敵→主人公)
◆変数の操作:#0002 攻撃x += 1
◆コモンイベント:対象者取得(敵→主人公)
◆変数の操作:#0003 攻撃y -= 1
◆コモンイベント:対象者取得(敵→主人公)
◆
:分岐終了
◆条件分岐:このイベントが左を向いている
◆アニメーションの表示:このイベント, 剣←
◆変数の操作:#0003 攻撃y -= 1
◆コモンイベント:対象者取得(敵→主人公)
◆変数の操作:#0002 攻撃x -= 1
◆コモンイベント:対象者取得(敵→主人公)
◆変数の操作:#0003 攻撃y += 1
◆コモンイベント:対象者取得(敵→主人公)
◆変数の操作:#0003 攻撃y += 1
◆コモンイベント:対象者取得(敵→主人公)
◆変数の操作:#0002 攻撃x += 1
◆コモンイベント:対象者取得(敵→主人公)
◆
:分岐終了
◆条件分岐:このイベントが右を向いている
◆アニメーションの表示:このイベント, 剣→
◆変数の操作:#0003 攻撃y -= 1
◆コモンイベント:対象者取得(敵→主人公)
◆変数の操作:#0002 攻撃x += 1
◆コモンイベント:対象者取得(敵→主人公)
◆変数の操作:#0003 攻撃y += 1
◆コモンイベント:対象者取得(敵→主人公)
◆変数の操作:#0003 攻撃y += 1
◆コモンイベント:対象者取得(敵→主人公)
◆変数の操作:#0002 攻撃x -= 1
◆コモンイベント:対象者取得(敵→主人公)
◆
:分岐終了
◆条件分岐:このイベントが上を向いている
◆アニメーションの表示:このイベント, 剣↑
◆変数の操作:#0002 攻撃x -= 1
◆コモンイベント:対象者取得(敵→主人公)
◆変数の操作:#0003 攻撃y -= 1
◆コモンイベント:対象者取得(敵→主人公)
◆変数の操作:#0002 攻撃x += 1
◆コモンイベント:対象者取得(敵→主人公)
◆変数の操作:#0002 攻撃x += 1
◆コモンイベント:対象者取得(敵→主人公)
◆変数の操作:#0003 攻撃y += 1
◆コモンイベント:対象者取得(敵→主人公)
◆
:分岐終了
◆ウェイト:15フレーム
◆
コモンイベント「剣を振る」とほとんど同じですが、プレイヤーではなく「このイベント」主体になっており、呼び出す「対象者取得」が、さっき作った「対象者取得(敵→主人公)」に置き換わっています。基本的にこれだけでOKです。剣を振る以外の攻撃も、同様な置き換えで、敵版に差しかわるはずです。
そして、敵の1ページ目で上記のコモンイベントを呼び出すよう、修正します。以下の◇の行が変更部分です。
◆条件分岐:スクリプト:enemyTime[this.character(0)._eventId - 1] == 60
◇コモンイベント:剣を振る(敵)
◆
:分岐終了
◆条件分岐:スクリプト:enemyTime[this.character(0)._eventId - 1] >= 60
◆スクリプト:enemyTime[this.character(0)._eventId - 1] = 0;
◆
:分岐終了
◆スクリプト:enemyTime[this.character(0)._eventId - 1]++;
◆
これで敵が1秒おきに剣を振るようになりました。
当たったら痛いことも確認してください。
このようにしてやれば、敵の行動パターンと、敵側の攻撃処理を自由に作っていくことができます。行動パターンでは今回は経過時間しか条件に採用しませんでしたが、例えば以下のようにすると、敵のダメージ量が大きくなったきたとき(=敵のHPが少なくなってきたとき)に、行動パターンが変わる、ということも実装できます。
↓行動パターンをHPによっても変更するサンプル
◆条件分岐:スクリプト:enemyDamage[this.character(0)._eventId - 1] >= 3
◆注釈:ダメージ量が3以上になったとき(=HPが少ないとき)
◆条件分岐:スクリプト:enemyTime[this.character(0)._eventId - 1] == 15
◆コモンイベント:剣を振る(敵)
◆
:分岐終了
◆条件分岐:スクリプト:enemyTime[this.character(0)._eventId - 1] >= 15
◆スクリプト:enemyTime[this.character(0)._eventId - 1] = 0;
◆
:分岐終了
◆
:それ以外のとき
◆注釈:ダメージ量が3未満のとき(=HPが多いとき)
◆条件分岐:スクリプト:enemyTime[this.character(0)._eventId - 1] == 60
◆コモンイベント:剣を振る(敵)
◆
:分岐終了
◆条件分岐:スクリプト:enemyTime[this.character(0)._eventId - 1] >= 60
◆スクリプト:enemyTime[this.character(0)._eventId - 1] = 0;
◆
:分岐終了
◆
:分岐終了
◆スクリプト:enemyTime[this.character(0)._eventId - 1]++;
◆
enemyDamageがダメージ量ですから、それを条件に追加することで、ダメージ量によって行動パターンが変わる、ということを実装できます。上記はダメージ量が3以上になると、経過時間が60ではなく15で剣を振るような実装になっているので、4倍速く振ってくるようになる、というものです。