ガード関連の仕様について

本ページではMUGENのガード関連の仕様について解説する。



ガード方向

MUGENでは相手キャラの位置に関係無く、「キャラクターが(内部的に)向いている方向の逆」で固定されている。
つまり見た目とガード方向が常に一致するため、一般的な格ゲーでいうめくりと完全に同じ状況というのは有り得ない。

が、いくら見た目通りだとは言っても人間の反射神経では限界があるわけで、
ガード方向が切り替わる瞬間を狙った飛び越えつつの攻撃というのは、
やはりMUGENにおいてもプレイヤーにとってある程度の脅威ではあり続けている。
微妙な位置だなと感じた時は相手キャラの軸位置よりも自キャラが振り向くかどうかに注意を置くと吉。


Guard.Distについて

HitDefおよびProjectile内の設定であるGuard.Dist。
HitDefはキャラクター本体や飛び道具、Projectileであれば飛び道具の位置を基準とした相手がガードモーションを取り得る最大距離を示す。

キャラクターが攻撃を出していても、そのHitDefのGuard.Dist値以上に距離が離れていると、
相手はガードモーションを取らない(取れない)。
これはあくまでガードモーションに移行しないだけで、キー入力によるガードは問題なく出来る。
だが、AIはinguarddistトリガーでガードを行うため実質的にガード不能技になる。
遠距離から連発するだけでハメ殺せてしまう。対処法は下記の製作者向け記事を参照のこと。
省略した場合はcnsで指定する[Size]のattack.distが代入される。

別に全てのHitDefに設定する必要のあるものではないが、細かな調整をしたい時には知っておくと便利である。
例えば瞬獄殺のようにガード不能な突進技ではGuard.Dist=0にしておくと、
相手はバックジャンプやダッシュをしなくても歩いて後ろに下がれる。
ちなみに、一般的な格ゲーの投げ技はほとんどの場合ガードモーションが取れないようになっている。

なお、この方法ではHitDefを発生させる瞬間にしか設定は出来ず、
現在は当たり判定の発生と同時にHitDefを実行するのが一般的になっているため、
攻撃の予備動作中は通常通りの距離でガードすることになりGuard.distだけでは無意味なことも多い。
特に理由がなければ該当ステートに入った時点でAttackdistを実行し、
HitDefの実行前に変更しておいた方がいいだろう。


人操作時とAI操作時とのガードの違いについて

CMDやCNSファイルに記述するステートコントローラーで、CPU操作時の特徴を検出してフラグを立て、
入力が無くとも自動的に行動するようにしたもの。詰まる所AIというのはそれだけである。
敵との間合いや敵のStateType・MoveTypeを監視し自動的に状況に即した技を出すという程度のことなら、
元々CMD・CNSで管理する領域なので全く問題は無い。
しかし本来「ガード」という行動はCMD・CNSの記述で管理されているものではない*1ため、
AIに的確にガードをさせようとしてもそれには限界がある。

人操作時のガードは、フレームの開始時点で「自分のctrlが有効」、
かつ「敵側のプレイヤーもしくはヘルパーのmovetype=Aになっているか、敵側のプレイヤーがProjectileを管理」していて、
「自分側のCommand="Holdback"&&Command!="Holdup"が成立している」と内部的なガード状態に入る。
この仕様のため、キー後ろ要素が入っていても、キー上要素が入っているとガード出来ない。
また、キー後ろ要素が入ってさえいれば、キー前要素が入っていてもガードが出来る。
さらにこの時、自分が敵側のGuard.Dist圏内に入っているとChangeStateが起こり、外見的にもガードモーションに入る。
ただし一般的なダッシュステートなど、一部のステートではこのChangeStateが起こらない。
そのためダッシュ中のctrlが有効になっていると、ダッシュ中にキー後ろ要素を入れておくことでガードを仕込みつつ相手に接近出来る。
ちなみにWin版ではGuard.Distの値をInGuardDistというトリガーで参照出来るので、
Win版のAIではDOS版の時のAIよりも大分人操作時に近い自然さでガードステートに移行させることが出来る。

なお、一度内部的なガード状態に入ると、そのフレームの間では、ガード用のステート以外でもその効果が持続する。
そのため、攻撃動作などの1F目でもガードが成立することがある
ctrlが有効な状態からchangestateで移れるステートの1F目でexplodやplaysndなどを実行している場合、
攻撃用のボイスを叫びながらガードするなんてことも有りうる。
1F目に相手の攻撃が重なる必要があるのであまり起こらないと思いきや、
実際にプレイヤー操作でキャラクターを動かしていると意外と出くわすことが多いので、
特に事情がなければ、エフェクトは2F目以降に出した方がよい。

CMD・CNSの記述で強引に作ったAIのガードはこれと全く違い、上で述べたInGuardDistなどをトリガーに用いて、
ChangeStateで強引に120番台にステートを飛ばす*2ことで作られている。
しかし、InGuardDist=1を使う都合上、Guard.Distの値以上の遠距離から届く攻撃を出された時反応のしようが無い。
こればかりはキャラがたまたまCommand="Holdback"の状態で、つまりMUGEN本来のAIの部分でガードしてくれることを祈るしかないのである。
ちなみにもしもInGuardDistを使用しないと、DOS版の時のようなGuard.Distと無関係に敵のStatetypeや、
NumProjのみを監視してガードステートに飛ばすAIになってしまう。

なお、トレーニングモードにもオートガードの設定が存在するが、
これはフレームの開始時点でInguarddistが反応したらCommand="Holdback"を実行するというものであり、
どちらかと言えば人操作のガードに近い。
そのため一般的なAIでもガード出来ることを確認したければ、
stupa氏が作成したいっしょにとれーにんぐ(adi氏のパッチを適用していないもの)のガードモードをAutoにして確認する必要がある。

*1
ガード行動のステートは他の行動と違い勝手に好きなステートNoに振り分けるなどのことは出来ない。
120~150番台の最初から決定されている特定のステートNoしかガードは出来ないし、
このステートNo群をガードではなくさせることも出来ない。

*2
120~150番台のガード用のステートNoに入ると、CtrlやCommand="Holdback"に関係なく内部的にもガードの状態に入る。


InGuardDist=1になるタイミングと距離について(製作者向け)

攻撃側のキャラクターがmovetype=Aになると、Attackdistを個別に設定しない限り、
攻撃のHitdefに関わらず、キャラクターの軸の前方にcns内のSizeの項目で設定したAttack.Distの値に応じたInGuardDist=1が成立する範囲が発生し、
このトリガーを利用してAIがガードモーションを取ることが可能になる。
なおmovetypeをA以外にすると、本体依存のInGuradDist=1が成立する範囲は存在しなくなる。
(この仕様を利用したのが、Mouser氏作成BLACK氏アレンジのK'に搭載されている、AIがガード出来ないアイントリガーである)。

飛び道具以外(キャラクター本体のHitdefで定義されたもの、attrは問わない)の場合

Hitdefで個別にGuard.Distが定義されていない場合はもちろん、Hitdefが実行されるまでのフレームでは、
InGuradDist=1が成立する距離は(Size内の定数、ステートコントローラを問わず)AttackDistの値がそのまま適用される。
逆に言えば、Hitdef内に明記したGuard.Distの値は、Hitdefが実行されてからしか適用されない
したがって、発生の遅い投げ技の場合、技の射程範囲内でガードモーションを取り続け、
Guard.Dist=0が有効になったフレームで掴まれる、ということも有り得る
(一応技を受ける側がHitdefattr=SCA,NT,STなどをトリガーにして、
 1フレーム目から投げに対して無敵になるステートに移ればなんとか間に合うが、
 ほとんどのAIではrandomなどを使ってChangestateが確実に作動することを防止しているため、
 人操作では見てからジャンプ余裕の投げ技でも、AIではあっさり投げられてしまう。
 なお、AIがこの手の技に無敵技で切り返す際には、Hitdefattrではなく大抵movetype=Aをトリガーにしている)。
意図的にガードモーションを取らせたい場合はこのままでいいが、
それでは困るという場合は、ステートコントローラのAttackDistを併用するか、
airファイルのCLSN1をわざと設定せず(あるいは攻撃判定を画面外遠方に設定するか)にHitdefだけを先行して実行すればよい。
前者の方法で設定したAttackDistはHitdefでguard.distを定義するまで有効で、
gurad.distを明記しないとそのステートを抜けるまでずっと有効になる。
一方後者の方法は、任意のタイミングで相手AIに技の属性まで認識させることが出来る
(例えば投げモーションに入った瞬間にHitdefを実行すれば、見てからジャンプ余裕でした、という行動をAIに再現させられる。
 もっともこのあたりが未調整であることを前提にして、見てからどころか超反応でジャンプやバクステを繰り出すAIも少なくないのだが)。

なお、AttackDistもGuard.Distも起点はキャラクター本体の軸位置になるため、
当たり判定が大きく前方に張り出すキャラクターだけではなく、元々左右に長いキャラクターもしっかりと値を設定しておく必要がある。

飛び道具(キャラクターのHitdef以外で定義されたもの)の場合

  • Projectileを単独で用いる場合
Projectileコントローラが実行されProjectileが発生するまでは、飛び道具以外の攻撃と同様の範囲でInGuradDist=1が成立する。
しかしProjectileが発生した次のフレーム以降では、キャラクター本体から生じるInGuradDist=1の範囲は消失し、
今度はProjectileの軸の前方のcns内のSizeの項目で設定したProj.Attack.Distの値に準じた範囲でInGuradDist=1が成立する。
airファイルで設定された軸位置からProj.Attack.Distよりも前に攻撃判定がある飛び道具は、
飛び道具の先端部分ではInGuradDist=1が成立せず、AIはこのトリガーを用いてガード出来なくなる。
特にビーム状の横方向に長い飛び道具でこの問題が起こりやすい。

一般的なキャラクターではcns内のAttack.Distは160、Proj.Attack.Distは90に設定されており、
Attack.Dist依存ではInGuradDist=1は成立するが、Proj.Attack.Dist依存ではInGuradDist=1が成立しないこともある。
その結果、飛び道具の発生まではガードしているのに、飛び道具が発生した瞬間ガードを解いてダメージを受けるという、
一見不可解な現象が起きる。MUGENユーザーならば何度となく目にしたことがある光景だろう。
対処法を簡単に説明する。
まず、飛び道具が発生するまでに相手にガードモーションを取って欲しい距離を、ステートコントローラのAttackDistで設定する。
画面端から画面端まで一瞬で届くビームのような飛び道具の場合、AttackDistのトリガーはtime=0などとするのが無難。
次にairファイル上での飛び道具の軸位置を後方にずらす。具体的には発生の根本付近の少し後ろあたり。
Projectileコントローラ内のOffsetの値(つまり、飛び道具を発生させる座標)は、airファイルの軸位置が決まった後で設定する必要がある。

また、逆に飛び道具の軸位置よりも後ろに当たり判定がある場合にも、AIがガードを解いてしまうことがある。
本体から離れた所に当たり判定が発生する場合は、いかにも飛び道具が刺さっているように見えるが、
実際にはただ単に軸位置の設定のせいでガー不になっているだけということもある。
具体的にどうすりゃいいの、という人は、出雲氏のジェダ・ドーマのセーガの軸位置を参考にするといいだろう。
意外に思われるかもしれないが、これでも氏のジェダほどの横幅でぎりぎりだったりする。
なお、飛び道具に幅があって軸位置が画面外に出てしまう場合、ProjEdgeBoundやProjStageBoundの設定が必要になることもある。

ちなみにProjectileを管理していると、キャラクター本体のmovetypeがAになっていてもInguarddistがProjectileにしか反応しなくなる。
そのため飛び道具発射後の硬直が短かったり、画面内外を問わず長く残る飛び道具を持つキャラクターはガー不攻撃を繰り出すことになってしまいやすい
(例えば、Projectileで定義された弱ソニックブームを前転で抜けてきたAIに通常技を振ると、AIはガード出来ない)。
Projectileを管理していてもHelperならInguarddistを反応させられるので、
Hitdefで定義された攻撃を含むステートに入った時点でmovetype=AのHelperを設置してIngurddistを作動させ、
!root,numprojをトリガーにしてdestroyselfで消えてもらえばこの事態は避けられる。
相手のAIが飛び道具監視を行っていると誤作動を起こす可能性があるので、
movetype=Aのヘルパーの座標は、x座標は本体と同じ値、y座標を数千を超える巨大な値にするとよい。
いっそのこと飛び道具をProjectileではなくHelper形式に切り替えるという手もあるが、
これはこれで相手側のnumprojトリガーが反応しなくなるという問題(詳細は後述)を含むので推奨しない。

  • Helperを単独で用いる場合
飛び道具に複雑な挙動をさせたい場合、HelperにHitdefを設定して飛び道具とすることでかなり自由度が増えるが、
見た目には同じ飛び道具でも内部での振る舞いはProjectileとは大きく異なる。
まずProjectileとは異なり、キャラクター本体のmovetypeがAならば、
Helperを発生させても本体依存のInGuradDist=1の範囲は消失しない。
そのため攻撃を受ける側が、飛び道具を飛び越えるなどしてスカした後でもガードしっぱなしになることがある。
Helperの位置を特定するトリガーがあれば飛び道具を後方にやりすごしたことをAIが確認出来るのだが、
生憎そのようなトリガーは存在しない
(手段が全くないわけではないのだが、それなりの準備を必要とする。
興味がある人は簡易AIテンプレ等のページにリンクされている厨忍氏のAI製作に関するQ&A集を読んでみよう)。

このように、攻撃を受ける側が認識するのは難しいが、
攻撃する側がHelperを発生させた次のフレームでステートコントローラを使ってAttakdist=0とすれば、
Projectileと同様に本体依存のInguardDist=1の範囲を消すことが簡単に出来る。こだわりがある人は、設定しておいて損はないだろう。
なお、ヘルパーを発生させたフレームでattackdistを0にしてしまうと、相手のinguarddistトリガーが反応しなくなるフレームが1F発生してしまう。
1FであってもAIにとっては致命的なので、必ず1F遅らせてattackdistを0にすること。
また、デフォルトでInGuradDist=1となる範囲もProjectileと異なる。
ProjectileではProj.Attack.Distの値が参照されるが、HelperはHitdef内の設定attr = S,SPなどとして飛び道具属性にしても、
cnsのAttack.Distの値が参照される。いずれにせよステートコントローラでAttackDistを長めに設定しておけば、
飛び道具の発生後もその範囲でInGuradDist=1は成立し続けるので、あまり問題にはならない。

ただし、Helperは特殊な挙動を設定出来る分、Projectileとは違った原理でガー不になることがある。
その最たる例が画面上を左右に往復するタイプの飛び道具で、
前述したようにInGuradDist=1になるのは飛び道具の前方だけに限られるので、
飛び道具が敵の背後から飛んでくるタイミングでは、見た目だけではなく内部的にも飛び道具の向きを変えてやる必要がある。
方法は単純で、見た目の向きが変わった所で、Helper側でステートコントローラのTurnを使ってやればよい
(Vel Xの値はプレイヤーでもHelperでも向いている方向を正とするので、
 いったん減速させた後反転させ、再度加速させればブーメランのような挙動になる)。
なおIngurddistと直接関係はないのだが、Helper形式の飛び道具はNumProjトリガーに反応しないことも頭に入れておきたい。
当たり前のような話ではあるが、攻撃を受ける側のAIにしてみれば、
Projectileならば発生直後からNumProjで認識出来るのに対し、HelperはInGuradDist=1が成立するまで、
特殊な方法を取らなければその存在が全く掴めないのである。
Numhelperトリガーを使えばいいと思われるかもしれないが、今やゲージやエフェクトに多量のHelperが使われ、
しかもHelperのmovetypeを認識するトリガーが存在しない(一応認識する手段はある。前述した厨忍氏のQ&A参照)ので、
現実的にはNumhelperトリガーは単独では防御、警戒には使えない。
特に速度の速い飛び道具を使う場合は、そのことを念頭に置いた上でGuard.distを設定したい。

  • キャラクターの軸を中心に当たり判定が発生するHitdefで定義された攻撃について
ProjectileやHelperなら軸位置で対応出来るが、キャラクターの軸位置を動かすことは出来ないので、
本体とは逆方向を向いたmovetype=AのHelperを設置し、キャラクターの後方でもInguarddistが成立するようにしてやればよい。
このHelperの座標は、x座標は本体と同じ値とし、y座標は大きな値にした方がよい。
ちなみに全画面攻撃もHitdefで定義されていればこの部類に入るが、
Helperを設置すると同時に本体およびHelperのattackdistを延長しておかないと、
相手との距離が離れたときにガー不になってしまう。

かなり長々と書いてきたのでうんざりした人も少なからずいると思われるが、
実際にAIがきちんとガード出来るかどうかを確かめるには、stupa氏が製作したいっしょにとれーにんぐのガードモードをAutoにした上で、
少しずつ互いの位置をずらしながら技を振ってみるだけでいい。
意図した通りにガードしてくれなければ、cnsかairか、どこかに問題があるはずである。

+ 動画を楽しく見るために
動画で「ガードしろw」「なぜつっこんだw」というコメントをしばしば見かけるが、
ガードしなかったのはAIではなく攻撃している側のcnsの方に原因がある場合も少なくない。
ただし、原因の特定は動画だけではまず不可能で、双方のAI、cns、airを照らし合わせながら、
デバッグを起動して最低限フレーム単位、場合によっては同一フレーム内での複数回のchangestateまで確認する必要がある。
また、ガードはMUGENの内部処理にも関わってくるため、下手をすると神キャラ製作者レベルの知識を要求されることも。
それぐらいならまだ対処の手段もあるが、MUGENの仕様上どうしようもないこともある。
Y軸方向の当たり判定、guardflag、持続、当たり判定の形状の変化などをAIは参照出来ない。
こうした背景があるので、動画内で軽々しくcnsの不備を疑うようなコメントをしてはならない。
もししっかりと調べた上で原因が特定出来たら、キャラクターの製作者にメールなどで連絡してあげよう。


暗転中に攻撃判定が発生する技とガード

一般的な格闘ゲームにおいて暗転中に攻撃判定が発生する技に関しては、
暗転中相手は動けないので暗転前からガードモーションを取っていないとガード出来ない。
一方MUGENでは、単にsuperpauseやpauseを実行するだけでは暗転してからキーを入力してもガードが間に合う。
これは暗転中も「ctrlが有効か、ガードステートにいて、かつcommand="holdback"が成立している」という、
ガード成立条件が機能していることが原因。
そのため暗転後ガード不能な技を作るためには暗転時に相手がガードステートにいるかどうかを参照して、
ガードしていればガード可能なhitdefを実行、そうでなければガード出来ないhitdefを実行する必要がある。
もちろんassertspecialのflagに空きがあればunguardableを実行してもいい。
なお、hitdefによる指定を行う場合、暗転が解除された時点でhitdefをガード可能なものに上書きしておかないと、
暗転解除後も攻撃がガード不能になってしまうことに注意。
また、暗転時にガード姿勢にいることをトリガーにする以上、
inguraddistが成立した状態で、1回以上相手側にステート処理順序が回っていなければならない。
早い話が1P2Pを問わずattackdistの足りない攻撃や、2P側から0F暗転技をぶっぱなすとどこをどうやってもガード不能になってしまう。
このため、MUGENで暗転前ガード可能かつ暗転後ガード不能の0F暗転技を完璧に実装するのは事実上不可能になっている。

なお、AIは暗転中に攻撃判定が発生する技は基本的にガード出来ない。
通常commandが実行されていなくても単にガードステートにいるだけでガードは可能で、
AIはこの仕様を利用してガードしているのだが、暗転中はcommand="holdback"が成立していないとガードが出来ないのである。
そのため、一見するとガードモーションを取っているように見えても、
AIは暗転中に攻撃判定が出る攻撃は無防備に受けてしまう(ただしhitoverrideを作動させていた場合は作動する)。
いずれのケースでもガー不技(投げ技も含む)であれば問題ないのだが、そうでない技を作る時は注意しよう。


DOS版MUGENのガード硬直半減仕様

DOS版MUGENはcommonの仕様がWIN版MUGENや1.0以降のMUGENとは異なるため、
ガード硬直がhittimeで設定したフレームの半分(実際には半分+小数点部分切り上げ)になる。
一見WIN版などを使っていれば関係ない話に聞こえるが、当時製作されたキャラやDOS版からコンバートしたキャラの中には、
このバグを回避するためにガード硬直を本来の2倍の値に設定したキャラが多数存在する(sander71113氏製作のキャラなど)。
古いキャラを使っていて固めが異様に強かったりした際には一度チェックしてみよう。
また逆に、DOS版からコンバートされたキャラで、ガード用のステートがキャラクターのcns内に記載されている場合、
本来のガード硬直の半分のフレームでガード硬直が解除されることがある。
この場合、他のキャラクターでは連続ガードになるはずの連携に割り込むなどの現象が発生する。
こちらの問題の修正方法は以下の通り。
cnsファイルをテキストエディタやメモ帖で開き、statedef 151で検索する。
キャラクターのcnsファイルが複数あるなら、全てのcnsファイルから探す。
Statedef 151が見つかったら、その少し下にある
[State 151, 4]
type = ChangeState
trigger1 = Time >= GetHitVar(hittime)
value = 130
ctrl = 1
この記述を
[State 151, 4]
type = ChangeState
trigger1 = Hitover
value = 130
ctrl = 1
と書き換える。(Time >= GetHitVar(hittime)をHitoverと書き換えればよい)
また、statedef 153で検索して、同じようにTime >= GetHitVar(hittime)をHitoverと書き換える。
cnsの書き換えの前には、必ずバックアップを取っておくこと。


最終更新:2021年12月14日 12:55