敵の行動を自在に制御する A実践編【RPGツクールMVプラグイン】

2020年01月13日

 敵の行動を自在に制御する @導入編から続きます。

 基本から上級まで、使えそうなものを全部載せてみました。
 必要なものを探してコピペなりしてください。

目次


基本編


自分の状態を参照する


対象を参照・変更する


対象を絞る(ver1.01)


まとめ

参考リンク


基本編


スキルを使う

 まずは基本形。普通にスキルを使わせる方法から。

20200112_basic.JPG

 難しいことは何もなく、『戦闘行動の強制』で行動主体とスキルと対象を選択するだけです。
 集中攻撃などの特徴を出したい場合を除き、対象は『ランダム』で構いません。

 また、この例では行動主体を固定で先頭の敵に指定しています。ボス戦など行動主体が確実に分かる場合はこれで十分です。

 しかしながら、いつも行動主体が先頭だとは限りません。
 行動主体を可変にしたい場合は、スクリプトを使用します。
 このプラグインでは以下のように呼び出せるようにしました。
this.forceAction(BattleManager._subject, 10, -1);

 10と書いてあるのがスキルIDです。
 -1とあるのが対象です。0が先頭、以降1,2,3...と増えていきます。
 -1の場合はランダムの意味になります。

 ……分かりにくいですね。

 というわけで「極力スクリプトは嫌だ!」という方のためにプラグインコマンドを用意しています。
NRP.forceSubject BattleManager._subject

 ※スクリプトではなくプラグインコマンドです。混同に注意!

 これは『戦闘行動の強制』の行動主体を書き換えてしまう機能です。エディタ上で何を選ぼうが、バトルイベントを実行中の行動主体へと強制変換します。
 あらかじめこれを一行挟んでおくと、全ての行動が終了するまでその状態が保持されます。

20200112_forceSubject.JPG

 こんな感じになります。
 この方法だとスキル名が見えるので、多少管理が楽ですね。お好きな方法をお使いください。
NRP.forceTarget [対象バトラー]

 同様に『戦闘行動の強制』の対象を書き換えるプラグインコマンドもあります。これについても後で使います。
NRP.forceSubject
NRP.forceTarget

 いずれも、クリアしたい時はパラメータなしで呼び出せばOKです。

確率でスキルを使う

 次行きましょう。
 これも特に難しくはありません。
 普通に乱数を使って確率分岐させるだけです。

20200112_if.JPG

 この例では適当な一時変数を使って、1〜4の乱数を生成しています。
 一時変数<=2の時は攻撃、3の時はファイア、4の時はスパークって感じですね。

 凝ったスキルを作った際、その処理内で同一の変数を使わないように注意です。それをやると無茶苦茶になります。
 心配なら各分岐内に『イベント処理の中断』を入れるのもよいと思います。

ターンによってスキルを使う

 この辺まではまだデフォルトで可能な機能ですね。
 通常のターン制と当サイトにあるCTB(またはCTTB)では、ターンの参照方法が変わります。

ターン制の場合

$gameTroop.turnCount()

 にて、敵グループが保有する現在ターンを取得できます。
 これは敵グループのバトルイベントと同じで1ターンから始まります。
 ※敵の戦闘行動の設定画面では0ターンから始まります。挙動が違うのでご注意!
 
20200112_turnCount.JPG

 『$gameTroop.turnCount() == 1』は見たまんま1ターン目なので、説明は不要でしょう。
 少し難しいのは『$gameTroop.turnCount() % 2 == 0』という記述です。
 これは2で割った余りが0。つまり偶数ターンを意味しています。
 もちろん『$gameTroop.turnCount() % 2 == 1』は奇数ターンになります。

 ローテーション行動を取らせたい場合は、こういう余りを使った演算が有効です。
 ちなみに、3ターンローテーションを取らせたい場合……
条件分岐:スクリプト:$gameTroop.turnCount() % 3 == 1
条件分岐:スクリプト:$gameTroop.turnCount() % 3 == 2
条件分岐:スクリプト:$gameTroop.turnCount() % 3 == 0

 という順番で回ってきます。
 直感的に0,1,2とやりたくなりますが、ご注意ください。

CTBまたはCTTBの場合

 個々人がバラバラに動くCTBでは、グループのターンはほとんど意味を持ちません。
BattleManager._subject.turnCount()

 というわけで、上記のように行動主体が保有するターンを参照します。
 $gameTroopがBattleManager._subjectに置き換わっただけですね。

 ※NRP_CountTimeBattle.js ver1.041またはNRP_CountTimeTurnBattle.js ver1.01以降が対象です。変数名を変更していますのでご注意ください!

20200112_CTB_turnCount.JPG

複数回行動

 これはデフォルトでは難しい機能です。
 とはいっても、『戦闘行動の強制』を複数行入力するだけです。デフォルトとは違って、順番を自由に決められます。

20200112_combo.JPG

 画像の例では、奇数ターンに1回行動の全体攻撃、偶数ターンに2回攻撃するようにしてみました。
 強力な攻撃をする時だけ1回攻撃にすると、バランスを取りやすくていい感じです。

 一回ずつランダムに行動を決めたい場合は、以下のように書きます。

20200112_loop_action.JPG

 攻撃とファイアのランダム2回行動です。
 ややこしく見えるかもしれませんが、単に行動した回数をカウントしながらループさせているだけです。

 ちなみに、一撃目で対象が全滅した場合、二撃目で落ちるバグが元々ありました。このプラグインで修正済みです。

自分の状態を参照する


自分のHPが50%以下の時

 困ったことにバトルイベントの通常の条件分岐ではHPを参照できません。
 というわけで、スクリプトを使います。
条件分岐:スクリプト:BattleManager._subject.hpRate() <= 0.5

 hpRate()というのが、現在HPの割合です。100%が1.0です。

自分のMPが100以下の時

条件分岐:スクリプト:BattleManager._subject.mp <= 100

 というように、あらゆるパラメータを参照できます。
 どんなパラメータがあるかは末尾に参考リンクを置いておきますので、そちらをご確認ください。

一体になると行動が激化する

 以下を条件にして、行動を変更します。
条件分岐:スクリプト:$gameTroop.aliveMembers().length == 1


自分にステートがかかっているか

 行動主体が固定なら普通に条件分岐が使えます。
 以下はそうでない場合も判定できるスクリプトです。
条件分岐:スクリプト:BattleManager._subject.isStateAffected(4)

 上はステートID=4(初期では毒)にかかっているかどうかを判定しています。
 例えば、治療魔法を使うかどうかの判定に使えます。
条件分岐:スクリプト:!BattleManager._subject.isStateAffected(4)

 かかっていない時を知りたいなら、先頭に『!』をつけて条件を反転します。
 補助ステートの重複防止はこれで。

眠っている時に使用するスキル(CTB限定)

 CTB限定で毎ターン実行されるバトルイベントに書いてください。
 ※コモンイベントから呼び出す方法だと、先に行動異常の判定が行われるため呼び出せません。

 上で紹介済の方法を使用し、眠っている時を判定します。
 さらに以下のプラグインコマンドを指定することで、行動異常時も行動を実行できるようになります。
NRP.forceAction true

 ※ターン制でも行動実行前にコモンイベントを呼び出すようなプラグインを使えば、同様の技も可能かもしれません。今はまだ研究中です。

対象を参照・変更する


特定のアクターを狙う

 少しずつ難しいヤツいきます。もっとも、難しく感じても0から書く必要はありません。
 自分が使いたいものに似た処理を探して、コピペしてください。
target = $gameParty.aliveMembers().find(m => m.actorId() == 4);

 ※アローファンクション(=>)を使ったJavaScriptの記法はツクールMVの本体バージョンが1.6以降でないと使えないようです。ご注意ください。

 これはアクターID=4のキャラを生存者の中から探して取得するスクリプトです。
 『$gameParty.aliveMembers()』がパーティの生存者リスト。その中で『m.actorId() == 4』に一致する対象を探しているわけですね。
 でもって、取得した『target』のインデックスを取ってスクリプトから『戦闘行動の強制』を呼び出せばよいわけですが……。

 ここでさっきのプラグインコマンドを使います。これで『戦闘行動の強制』の対象を強制変換しました。『target =』の部分は省略し、一行で書いてしまいます。
NRP.forceTarget $gameParty.aliveMembers().find(m => m.actorId() == 4)

 ※しつこいようですが『スクリプト』ではなく『プラグインコマンド』です。
  自分もたまに間違えます。


20200112_target_actor.JPG

 対象がいなかったり戦闘不能になった場合は、他の相手を狙ってくれます。

 なお、ここで使用している『find』という関数は、リストの中から最初に見つけた要素を返します。
 条件を満たす対象が複数いても、対象になるのは最初の一人だけです。

最も弱っているアクターを狙う

NRP.forceTarget $gameParty.aliveMembers().reduce((a, b) => a.hpRate() < b.hpRate() ? a : b)

 前回と同じ要領で可能です。
 今回は『reduce』という関数を使用しています。
 これは生存者リストの中から、HP%(hpRate())を繰り返し比較しあって一番小さな対象を得ているわけです。

 ……が、一つ落とし穴。
 この『reduce』という関数、比較する対象がないとエラーで落ちます。
 $gameParty.aliveMembers()が空の時、つまり全アクターが死んでいると落ちます。

 1回目の行動ならそんな状況にはなりません。対象の取得は1回目の行動時しかやらないというなら、問題はありません。
 ただ2回目以降の行動では注意が必要です。
条件分岐:スクリプト:!$gameParty.isAllDead()

 そこで上の条件(全滅時でない)を満たす時のみ処理するようにします。

20200112_target_hprate.JPG

 こんな感じになります。
 なお、よく使う場合は分かりやすい名前でコモンイベント化することをオススメします。
 ていうか、こんなパッと見で分かりにくい処理を毎回打ち込むのは耐えられません。

20200112_target_hprate_common.JPG

 分かりやすいですね。これなら我慢できそうです。

 今回はHP%でやりましたが、比較する値を変えれば色んな相手を対象にできます。
NRP.forceTarget $gameParty.aliveMembers().reduce((a, b) => a.hp > b.hp ? a : b)

 これは現在HPの一番多いアクターです。多いほうを取るため、不等号を大なりにしています。
NRP.forceTarget $gameParty.aliveMembers().reduce((a, b) => a.hp + a.mp > b.hp + a.mp ? a : b)

 HP+MPの合計で比較してみました。複数の要素を合わせた比較も可能です。

【追記】
NRP.forceTarget $gameParty.aliveMembers().sort((a, b) => a.hpRate() - b.hpRate())[0]

 ならば、落ちることなく同じ効果(最小の対象)が得られます。
 『b.hpRate() - a.hpRate()』にすれば、最大の対象も得られます。どっちがどっちか分かりにくいのが難点ですが……。

最もHPが減っている仲間を選択して回復

 実用的っぽいヤツをいきましょう。
NRP.forceTarget $gameTroop.aliveMembers().reduce((a, b) => a.hpRate() < b.hpRate() ? a : b)

 上とほぼ同じ考えですが、プラグインコマンドの一行で可能です。

20200112_target_heal.JPG

 対象が味方から敵。$gamePartyが$gameTroopに変わっただけですね。
 範囲が味方のスキルを使えば、勝手に自軍が対象となります。
 ちなみに全滅判定は不要です。全滅してたらそもそも回復できませんので。

 ……というかこの処理、バトルイベントじゃなくて最初から全体に組み込んだほうがいい気がしないでもない。他にプラグインがないなら検討しておきます。
 →作りました。
 http://newrpg.seesaa.net/article/473218336.html


HPが50%以下の仲間がいる時のみ回復を行う

 上と併せて役立ちそうなものも置いておきます。
 以下を条件にして、回復行動を実行すれば可能です。
条件分岐:スクリプト:$gameTroop.aliveMembers().find(m => m.hpRate() <= 0.5)

20200112_target_hprate50.JPG


戦闘不能の仲間がいる時のみ蘇生を行う

 以下を条件にします。
条件分岐:スクリプト:$gameTroop.members().find(m => m.isDead())

 対象はランダムでも問題ありません。戦闘不能者がいれば、勝手に優先してくれるようです。

ステートにかかった相手を対象とする

NRP.forceTarget $gameParty.aliveMembers().find(m => m.isStateAffected(10))

 ステートID=10(初期では睡眠)にかかった相手を対象にします。デフォの睡眠は回避率の減少効果があるので、命中の低い大振り攻撃で狙ってくる敵など嫌らしいかもしれません。

ステートにかかっていない相手を対象とする

NRP.forceTarget $gameParty.aliveMembers().find(m => !m.isStateAffected(10))

 『!』を頭につけることで反転。眠っていない相手を対象とします。まだ眠っていない相手を一人ずつ眠らせてくる敵なども作れます。

 せっかくなので、もう一段階行きましょう。
NRP.forceTarget $gameParty.aliveMembers().find(m => !m.isStateAffected(10) && !m.isStateResist(10))

 『!m.isStateResist(10)』という条件を追加しました。『&&』は『かつ』の意味です。
 『isStateResist(10)』とはステート無効化を持っているかの判定です。
 !でその反対ということは、「眠っておらず、かつ無効化を持たない相手」を対象とするという意味になります。

 賢い敵を作りたい時はどうぞ。

対象を絞る(ver1.01)


女を優先して狙う

 女ばかりを狙うむっつりモンスターを作ってみましょう。
 といっても、ツクールMVのアクターデータベースには性別欄なんてありません。そこで女性アクターのメモ欄に<lady>と記入します。

 これにて『m.actor().meta.lady』で女性かどうかを判定できるようになります。
 ちなみに対象が敵の場合は『m.enemy().meta.lady』になるので注意です。

 ※別にwomanでもfemaleでも何でもいいですが、参考先のこちらに習ってます。

 さて、上と同じようにfindを使ってもいいのですが問題があります。findはあくまで、条件に合う先頭の者を取得するだけです。メンバーに複数の女性がいる場合、その中の先頭ばかりが狙われてしまいます。
NRP.forceTarget $gameParty.aliveMembers().filter(m => m.actor().meta.lady)

 というわけで、今回はfilter関数を使いましょう。これで条件に合う全ての対象を取得できます。
 これによって、女性という条件を満たす範囲で、かつランダム(狙われ率も考慮)に狙ってくれるようになります。

 この場合、既に全ての女性キャラが戦闘不能状態だと、男性キャラ(および性別不詳)も狙うようになります。

対象を限定して狙う

 では、女しか狙わない敵を作りたい場合はどうするか?
 そんな時のために『NRP.forceTargetLimit』というプラグインコマンドを用意しました。
NRP.forceTargetLimit $gameParty.aliveMembers().filter(m => m.actor().meta.lady)

 これで女しか狙わなくなります。条件を満たす相手が一人もいなければ、行動自体をスキップします。

まとめ


 敵の行動の制御については以上です。
 これでバトルイベントの強力さが伝わったならば幸いです。
 基本的にあらゆるものを参照できるため、大抵のことができてしまいます。

 ここでは紹介していませんが『戦闘行動の強制』以外のコマンドも使えるため、演出なども自由自在です。
 例えば、音楽を止めるなどの演出と組み合わせて複数回行動をさせれば、時間停止っぽい技も作れてしまいます。

 今後はスキルなどの作成にも活用できないか研究しようと思います。

参考リンク


 有志がまとめて下さった各クラスの情報です。どんなパラメータを参照できるかはこちらから確認できます。

 Game_Enemy(敵のみの項目)
 Game_Actor(味方のみの項目)
 Game_Battler(敵味方の共通項目)
 Game_BattlerBase(敵味方の基本共通項目)

 Game_BattlerBase(敵味方の基本共通項目)
 Game_Troop(敵集団の共通項目)
 Game_Unit(敵味方集団の共通項目)

 末尾に()を付ける必要があるもの(関数)と()のいらないもの(変数)が混在しているので注意です。間違えると機能しません。

 その他、参考にさせていただいた記事など。
 https://punipunion.hatenablog.com/entry/2018/12/01/154554
 http://rpgmaker-script-wiki.xyz/battleaction_mv.php


 >RPGツクールMV目次に戻る
posted by 砂川赳 at 19:08 | RPGツクールMZ&MV | このブログの読者になる | 更新情報をチェックする