「ガードステート 補足説明」の編集履歴(バックアップ)一覧はこちら
ガードステート 補足説明 - (2007/12/12 (水) 18:09:39) の1つ前との変更点
追加された行は緑色になります。
削除された行は赤色になります。
・ガードステートについて 最終更新12/12
&italic(){&u(){EnemyNear,HitDefAttr中心のステート}}
㍻㌢氏や⑨氏のAI講座においてガードステートのトリガーにP2StateTypeがよく使われています。
このままでも良いのですが、これだけだと立ち下段などの一部攻撃に対応できません。
そこでP2StateTypeだけではなくHitDefAttrも用います。
勿論自分のではなく相手のを参照するのでEnemy,もしくはEnemyNear,をつけて下さい。
ここではEnemyNearを用います。
なぜP2StateTypeだけではなくHitDefAttrも用いるかというと、
相手の攻撃の中にはStateTypeとAttr、そしてGuardFlagが一致していない場合があるからです。
簡易的に表してみると
StateType = S
HitDefAttr = S,AA(NAやSAの可能性もあるが立ち打撃という意味でAAで統一)
GuardFlag = MA(あるいはA)
これは立ち打撃で立ち、屈み、空中を問わずにガードできるというものです。
いわゆる上段というものです。(多分)
StateType = S
HitDefAttr = S,AA
GuardFlag = HA(あるいはH)
これは立ち打撃で立ち、空中状態のみガードできるというものです。
つまり屈み状態ではガード不可、中段という意味です。
これらの場合はP2StateTypeでもHitDefAttrでも結果は変わりません。
ですが中にはこういったものもあります。
StateType = S
HitDefAttr = S,AA
GuardFlag = L
これが所謂「立ち下段」と呼ばれる形です。
StateType=S、つまりキャラが立ち状態で
HitDefAttr=S,AA、つまり立ち打撃であることが分かります。
この場合立ちガードの記述にP2StateTypeを使っているとほぼ確実に立ってしまいます。
しかしGuardFlagがL、つまり屈みガードのみ可なので攻撃を喰らってしまいます。
またStateType=A(空中状態)なのにGuardFlagがLという場合も有ります。
そのためP2StateTypeではなくHitDefAttrを用います。
HitDefAttrは相手のHitDefに影響されます。
つまりHitDefAttrを用いると相手がSCAのどの状態であろうとどのような攻撃かを正確に読み取ってくれます。
それにHitDefはStateTypeとは別に設定できますからね。
とりあえず基本形を書いてみると
[State 120, Hi to Lo]
Type = StateTypeSet
TriggerAll = AIフラグON
TriggerAll = StateType != A(念の為)
相手の攻撃が屈み打撃の場合 or 相手の攻撃が飛び道具の場合
Trigger1 = EnemyNear,HitDefAttr = C,AA || EnemyNear,HitDefAttr = SCA,AP
相手の攻撃が立ち打撃の場合
Trigger2 = EnemyNear,HitDefAttr = S,AA
Trigger2 = EnemyNear,Time < * 相手の動作が*フレーム未満の時
StateType = C
Physics = C
IgnoreHitPause = 1(必要かどうかは不明)
[State 120, Lo to Hi]
Type = StateTypeSet
TriggerAll = AIフラグON
TriggerAll = StateType != A(念の為)
相手の攻撃が空中打撃の場合
Trigger1 = EnemyNear,HitDefAttr = A,AA
相手の攻撃が立ち打撃の場合
Trigger2 = EnemyNear,HitDefAttr = S,AA
Trigger2 = EnemyNear,Time >= * 相手の動作が*フレーム以上の時
StateType = S
Physics = S
IgnoreHitPause = 1(必要かどうかは不明)
となります。
ただしEnemyNear,HitDefAttr = SCA,APは保険用ですので注意して下さい。
EnemyNear,HitDefAttrではProjectileどころかHelperすら読み込んでくれません。
そこで飛び道具に対してはEnemy,NumProj > 0を使用することを薦めます。
まず上の記述ですが、屈み打撃の場合ほとんどの攻撃が屈んでいればガードできます。
つぎに下の記述ですがこれは言うまでも無く空中打撃に対しては立つようにしてあります。
そして掲示板の方にも質問がありましたが、Trigger2のEnemyNear,Timeについて。
上の記述も下の記述もTrigger2に立ち打撃が条件となっていますが、EnemyNear,Timeの部分が違います。
これは&u(){「相手の立ち打撃が*フレーム未満の場合は屈み、*フレーム以上だと立つ」}という仕組みです。
通常中段は他の攻撃に比べて発生が遅くなっています。
そこでEnemyNear,Timeを用いて擬似的に中段かどうかを判断させています。
補足ですが*には任意の数字を入れて下さい。
目安とはして16~18ぐらいを入れるとベストかもしれません。
これで立ち下段に対するガードがほぼ完璧ですが、注意点があります。
AIにガードさせる記述、つまりChangeStateです。
この時にステート130や131などに直接飛ばすとガード不可能な攻撃もガードしようとするようです。
それを防ぐためにステート120や121に飛ばすことをおすすめします。
更に精密なAIを作ろうと思うのならばさらにトリガーを増やして条件を厳しくすることを薦めます。
例えば変数(Var)を用いて、相手の数フレーム前のStateTypeを判断したり、擬似的な学習システムを作成しそれによって確率を変化させたりなど。
簡単な例としてはTrigger2は中段対策なのですが、これを数種類に分けて判断させることもできます。
例えばEnemyNear,StateType!=Sを付け加えることによって「立ち状態以外での立ち打撃」という珍しい攻撃を判断することもできます。
この場合は相手が屈んでいるか空中にいるかなのですが、屈み状態ならば中段であることは滅多にありませんし、
空中状態での立ち打撃なんてものも滅多に有りません。
しかし念には念をということで一応それに対するためのトリガーも追加します。
それは&u(){EnemyNear,Vel Y < 0} と &u(){EnemyNear,Vel Y >= 0}です。
これらは&u(){「相手が降下攻撃してきているかどうか」}を判断します。
気晴らしに遊んでいた時に空刃脚を思い出しまして。
しかしこれでもまだメタじみている気がします。
もう少し記述を少なく出来ればそうは感じ無いのですが・・・。
例)
[屈み移行ステート]
Trigger1 = EnemyNear,HitDefAttr = C,AA || EnemyNear,HitDefAttr = SCA,AP
Trigger2 = EnemyNear,HitDefAttr = S,AA
Trigger2 = EnemyNear,Time < *
Trigger2 = EnemyNear,Vel Y <= 0
Trigger3 = EnemyNear,StateType != S
Trigger3 = EnemyNear,HitDefAttr = S,AA
Trigger3 = EnemyNear,Time >= *
Trigger3 = EnemyNear,Vel Y <= 0
[立ち移行ステート]
Trigger1 = EnemyNear,HitDefAttr = A,AA
Trigger2 = EnemyNear,HitDefAttr = S,AA
Trigger2 = EnemyNear,Time >= *
Trigger2 = EnemyNear,StateType = S
Trigger3 = EnemyNear,HitDefAttr = S,AA
Trigger3 = EnemyNear,Time <= *
Trigger3 = EnemyNear,Vel Y > 0
Trigger4 = EnemyNear,StateType != S
Trigger4 = EnemyNear,HitDefAttr = S,AA
Trigger4 = EnemyNear,Time > *
Trigger4 = EnemyNear,Vel Y > 0
屈み移行のTrigger2は立ち下段対策ですが、一応Velが入っています。
これの詳細は後述を参照してください。
立ち移行のTrigger2は中段対策です。
これは&u(){「相手の立ち打撃が*フレーム以上で立ち状態である」}ということで中段と判断させております。
次に屈み移行のTrigger3は&u(){「相手の立ち打撃が*フレーム以上で立ち状態じゃなく下降していない」}というものです。
これは後述するP2StateType中心のトリガーにおけるVel Y = 0に対する屈みと同じようなものです。
もし相手が屈み状態ならばVel Y = 0に当てはまって屈んでくれます。
相手が空中状態であっても下降攻撃以外は屈んで避けてしまえというものです。
といっても対応できる攻撃には限界がありますが・・・。
まさか昇竜に中段があるとは思えませんけどね。
そして立ち移行のTrigger3,4。
この2つは屈み移行のTrigger2,3に対応させています。
まずTrigger3の意味は&u(){「相手の立ち打撃が一定フレーム未満or下降中」}です。}
下降中という場合ほとんどが空中状態になっているはずです。
空中状態で攻撃した場合は普通空中属性が付いた攻撃になります。
その場合は立ち移行ステートのTrigger1が反応して立ちます。
もし相手の攻撃が立ち属性の場合はまず屈み移行のTrigger2か3が反応します。
しかしそれは&u(){「相手が下降していない状態」}が条件となりますのでそれに対して&u(){「相手が下降している状態」}という条件のトリガーが立ち移行に必要です。
そのため屈み移行のTrigger2に対して立ち移行のTrigger3が、屈み移行のTrigger3に対して立ち移行のTrigger4があります。
以前は(EnemyNear,Time < *) || (EnemyNear,Vel Y > 0)という記述を使いこれ一つで両方に対応させようとしていましたが、
これだとまだ反応してくれない攻撃があるのでTrigger3と4の2つに分けました。
こちらの方が丁寧と言えば丁寧なんですけどね。
そして最後に飛び道具対策ですが、現段階では完全には出来ません。
ただし無いよりはマシなのでそれを加えた暫定完成形は
[屈み移行ステート]
TriggerAll = AIフラグON
TriggerAll = StateType != A
Trigger1 = Enemy,NumProj > 0 || Enemy,NumHelper > 0 飛び道具が存在する時
Trigger2 = EnemyNear,HitDefAttr = C,AA,AP || EnemyNear,HitDefAttr = SA,AP
Trigger3 = EnemyNear,HitDefAttr = S,AA
Trigger3 = EnemyNear,Time < *
Trigger3 = EnemyNear,Vel Y <= 0
Trigger4 = EnemyNear,StateType != S
Trigger4 = EnemyNear,HitDefAttr = S,AA
Trigger4 = EnemyNear,Time >= *
Trigger4 = EnemyNear,Vel Y <= 0
[立ち移行ステート]
TriggerAll = AIフラグON
TriggerAll = StateType != A
Trigger1 = EnemyNear,HitDefAttr = A,AA
Trigger2 = EnemyNear,HitDefAttr = S,AA
Trigger2 = EnemyNear,Time >= *
Trigger2 = EnemyNear,StateType = S
Trigger3 = EnemyNear,HitDefAttr = S,AA
Trigger3 = EnemyNear,Time <= *
Trigger3 = EnemyNear,Vel Y > 0
Trigger4 = EnemyNear,StateType != S
Trigger4 = EnemyNear,HitDefAttr = S,AA
Trigger4 = EnemyNear,Time > *
Trigger4 = EnemyNear,Vel Y > 0
となります。
ヘルパーにHitDefを載せた形に対してはInGuardDistが有効みたいです。
というわけで屈み移行ステートにEnemy,NumHelperも追加しました。
しかし途中で気付いたので修正したのですが、&u(){ガード移行ならともかく立ち屈み移行にInGuardDistって必要ないですよね?}というわけで修正しました。
これでもしっかりと動いてくれます。
もしInGuardDistが無効になってもそのときはガードを止めてくれますからね。
そして立ち移行からEnemy,NumProj = 0が無くなりました。
これは&u(){「飛び道具がある時確実に屈むから中段で崩される」}という弱点を無くすためです。
もしこれがあった場合、例えば波動拳キャンセル禊なんかくると確実に屈んでしまうため屈みガード不可である禊を受けてしまいます。
そういったものを防ぐために消しました。
&italic(){&u(){P2StateType中心のステート}}
皆さんが良く使うP2StateType(あるいはEnemy,~、EnemyNear,~)についてやってみます。
実はこれ&bold(){だけ}だと一部攻撃には対応できませんが、Timeなどの他のトリガーと組み合わせると対応可能です。
まずは&u(){「相手が空中状態の時のみ立ち他は屈む」}という風にすると
[屈み移行ステート]
Trigger1 = P2StateType != A
[立ち移行ステート]
Trigger1 = P2StateType = A
となります。
ただしこの状態だと立ち中段で余裕で崩されるのでそれに対する対策もします。
[屈み移行ステート]
Trigger1 = P2StateType != A
Trigger2 = P2StateType = S
Trigger2 = EnemyNear,Time < *
[立ち移行ステート]
Trigger1 = P2StateType = A
Trigger2 = P2StateType = S
Trigger2 = EnemyNear,Time >= *
ここまではEnemyNear,HitDefAttr中心のステートとほぼ同じです。
本来ならこれだけでも上等なのですが更にガチガチにしたいという人は
[屈み移行ステート]
Trigger1 = P2StateType = A
Trigger1 = EnemyNear,Vel Y = 0
Trigger2 = P2StateType = C
Trigger3 = P2StateType = S
Trigger3 = EnemyNear,Time < *
[立ち移行ステート]
Trigger1 = P2StateType = A
Trigger1 = EnemyNear,Vel Y != 0
Trigger2 = P2StateType = S
Trigger2 = EnemyNear,Time >= *
とすればOKです。
上との違いはP2StateTypeがAでも場合によっては屈むという条件が追加されている事です。
この場合は&u(){「相手が空中状態で地面と平行に移動している時は屈みそれ以外は立つ」}という条件が追加されています。
これに当てはまる攻撃は限られている気がしますが例としてはサイコクラッシャーとかですね。
まあこれは立っていてもガードできますが。
どっちかというと&u(){「空中突進とか屈んでスルーしようぜ」}というコンセプトでやりました。
役に立つかどうかは不明ですが・・・。
ちなみに普通に空中攻撃をしてもその技独自の動きか重力によってVel Y != 0になるので立ち移行は可能です。
あとこのステートは下段飛び道具とかには完全には対応していないので注意して下さい。
その対応度はEnemyNear,HitDefAttr中心より低いですがまあ気にするほどのものでもありません。
最後に途中までガードするけど途中からガードしなくなるなどの現象はガードに移る条件や
[State X]
Type = ChangeState
Trigger1 = (略)
Value = 140
となっている記述のトリガーをいじってみてください。
自分もこの辺はまだ完璧ではないのでこれ以上は何とも言えません。
・各トリガーの欠点 最終更新12/8
AIを作成する際にはトリガーは非常に重要です。
ですがトリガーにも色々な落とし穴があります。
それについて気付いたものを適当に書き連ねようかと思います。
&italic(){&u(){InGuardDist}}
ガードや回避の際にお世話になるトリガーです。
しかしこれにもいくつかの欠点があります。
&s(){一つ目は&u(){自分の中心軸よりX軸方向に-にいけば無効になる。}}
&s(){簡単に言えば背中側のものは認識しないと言う事です。}
&s(){レミーの上ソニックで調べましたが、まだ前に存在する状態では有効になってました。}
&s(){しかし屈んでいる状態で通っていった時、無効になりました。 }
&s(){いくら相手の飛び道具を屈んで避けれても背後に回った部分に当たってしまっては元も子も有りません。}
&s(){多分めくりに対しても同じことが言えると思います。}
&s(){さらに詳しく実験したところ-方向にいてもしっかりと有効になるようです。}
&s(){しかしProjectileに対しては無反応でした。(レミーの件の他にも斬空など)}
&s(){このことから&u(){同一ステート内においてP2Dist Xの正負が逆になった場合無効になる。}}
&s(){ということが言えるかもしれません}
&s(){ただ現在も実験中なのでハッキリとは言えませんが・・・。}
&s(){ちなみにInGuardDistだけでガードステートに飛ばした場合めくりに対して対応しきれていませんでした。}
更に少しだけ捻って実験してみたところ&u(){「自分と対象のFacingが負の関係にあり自分の中心軸よりX軸方向に-にいけば無効になる。」}
ということが分かりました。
これならめくり攻撃の件も飛び道具の裏周りの件も説明が可能です。
しかしこの対象というのが曖昧なんですよね。
この部分は説明しにくいのでまあ何となくとでも理解して下さい。
二つ目は&u(){GuardDist=0を使用しているものには反応しない。}
これは主に突進系の攻撃によく見られます。
GuardDistとはガードステートに移行する距離のことですが、それが0の場合密着状態じゃないと有効になりません。
突進系の攻撃に対してほとんど対応できていない場合はこれが原因かもしれません。
他にGuardDist=0が用いられるとしたら投げぐらいでしょう。
&italic(){&u(){EnemyNear,~}}
これは自分が主に使っているものです。
勿論他にも使っている人は大勢居るでしょう。
この効果は&u(){自分に最も近い相手の~}です。
やはりこれにも欠点はあります。
それは&u(){ヘルパーに対応していない}ということです。
これについての実用例は後で詳しく説明します。
もしこれがヘルパー対応でしたらそれはそれですごいことになるでしょうが。
EnemyNear,IsHelperとかできたら良かったのになあ。
&italic(){&u(){EnemyNear,HitDefAttr}}
いうまでもなく相手のHitDefAttrを認識するトリガーです。
当身などには何かと便利なのですが地味にいやらしい欠点があります。
一つ目は&u(){攻撃判定が無いと無効になる。}
まあ実際はあまり関係無いのですが、これ中心の記述だと移行が遅れるみたいです。
当然ですよね。相手のHitDefが有効にならないと作動しないのですから。
が、逆を言えば&u(){HitDefが有効にならない限りという条件}がつけられる・・・かもしれません。
編集中に思いついただけなので期待しないで下さい。
それに実用方法が思いつきません。
移行が遅れるのを防ぐにはP2StateTypeだけにするとよいみたいです。
二つ目は&u(){Projectileには反応しない。}
これは実にいやらしいです。
これのせいでEnemyNear,HitDefAttrだけでガードを組むことができませんから。
&s(){またEnemyNear,という記述上&u(){ヘルパーのHitDefAttrを認識できない}という欠点も持ち合わせています。}
&s(){なんか間違いだらけだったのですがEnemyNearでもヘルパーは認識できるようです。}
&s(){これならEnemyNear,IsHelperと組み合わせて何か出来そうですが・・・。}
やっぱりヘルパーの認識は無理みたいです。
というわけで&u(){ヘルパーのHitDefAttrを認識できない}という欠点はやはりあったようです。
・おまけ 最終更新12/1
ここでは愚痴みたいなものを書いていきます。
というよりは現状AIに認識不可能なものを少し。
&italic(){&u(){HelperにHitDefを載せた飛び道具の裏回り状態}}
これは本当に認識不可能です。
いや一応可能と言えば可能なのですが、それをやると今度は必要以上に固まってしまいます。
もしこれがProjectileならばEnemy,NumProj > 0と!InGuardDistによって認識することが可能です。
ProjectileならできてHitDefでは出来ない理由はHelperであることが最大の原因です。
トリガーの欠点について書いてある通りにヘルパーの存在を認識できても詳細は一切認識できません。
ここでProjectileならNumProjとInGuardDistの2つのトリガーによって認識できますが、HitDefだとInGuardDistでしか認識できません。
更にそのInGuardDistも裏回りが認識できません。
無論ヘルパーの存在はNumHelperで認識できますが、それが何かの処理を行うためのものなのか攻撃用のものなのかは認識できません。
そのためInGuardDistなどの相手が攻撃している状態を認識できるトリガーを一緒に組まない限り必要以上にガードするのです。
が、InGuardDistを組ませると裏回りが・・・というジレンマが発生します。
ですのでこれは現状諦めたほうが良いです。
情報提供:B9MW85qx氏
:EQbnUkn9氏
・ガードステートについて 最終更新12/12
&italic(){&u(){EnemyNear,HitDefAttr中心のステート}}
㍻㌢氏や⑨氏のAI講座においてガードステートのトリガーにP2StateTypeがよく使われています。
このままでも良いのですが、これだけだと立ち下段などの一部攻撃に対応できません。
そこでP2StateTypeだけではなくHitDefAttrも用います。
勿論自分のではなく相手のを参照するのでEnemy,もしくはEnemyNear,をつけて下さい。
ここではEnemyNearを用います。
なぜP2StateTypeだけではなくHitDefAttrも用いるかというと、
相手の攻撃の中にはStateTypeとAttr、そしてGuardFlagが一致していない場合があるからです。
簡易的に表してみると
StateType = S
HitDefAttr = S,AA(NAやSAの可能性もあるが立ち打撃という意味でAAで統一)
GuardFlag = MA(あるいはA)
これは立ち打撃で立ち、屈み、空中を問わずにガードできるというものです。
いわゆる上段というものです。(多分)
StateType = S
HitDefAttr = S,AA
GuardFlag = HA(あるいはH)
これは立ち打撃で立ち、空中状態のみガードできるというものです。
つまり屈み状態ではガード不可、中段という意味です。
これらの場合はP2StateTypeでもHitDefAttrでも結果は変わりません。
ですが中にはこういったものもあります。
StateType = S
HitDefAttr = S,AA
GuardFlag = L
これが所謂「立ち下段」と呼ばれる形です。
StateType=S、つまりキャラが立ち状態で
HitDefAttr=S,AA、つまり立ち打撃であることが分かります。
この場合立ちガードの記述にP2StateTypeを使っているとほぼ確実に立ってしまいます。
しかしGuardFlagがL、つまり屈みガードのみ可なので攻撃を喰らってしまいます。
またStateType=A(空中状態)なのにGuardFlagがLという場合も有ります。
そのためP2StateTypeではなくHitDefAttrを用います。
HitDefAttrは相手のHitDefに影響されます。
つまりHitDefAttrを用いると相手がSCAのどの状態であろうとどのような攻撃かを正確に読み取ってくれます。
それにHitDefはStateTypeとは別に設定できますからね。
とりあえず基本形を書いてみると
[State 120, Hi to Lo]
Type = StateTypeSet
TriggerAll = AIフラグON
TriggerAll = StateType != A(念の為)
相手の攻撃が屈み打撃の場合 or 相手の攻撃が飛び道具の場合
Trigger1 = EnemyNear,HitDefAttr = C,AA || EnemyNear,HitDefAttr = SCA,AP
相手の攻撃が立ち打撃の場合
Trigger2 = EnemyNear,HitDefAttr = S,AA
Trigger2 = EnemyNear,Time < * 相手の動作が*フレーム未満の時
StateType = C
Physics = C
IgnoreHitPause = 1(必要かどうかは不明)
[State 120, Lo to Hi]
Type = StateTypeSet
TriggerAll = AIフラグON
TriggerAll = StateType != A(念の為)
相手の攻撃が空中打撃の場合
Trigger1 = EnemyNear,HitDefAttr = A,AA
相手の攻撃が立ち打撃の場合
Trigger2 = EnemyNear,HitDefAttr = S,AA
Trigger2 = EnemyNear,Time >= * 相手の動作が*フレーム以上の時
StateType = S
Physics = S
IgnoreHitPause = 1(必要かどうかは不明)
となります。
ただしEnemyNear,HitDefAttr = SCA,APは保険用ですので注意して下さい。
EnemyNear,HitDefAttrではProjectileどころかHelperすら読み込んでくれません。
そこで飛び道具に対してはEnemy,NumProj > 0を使用することを薦めます。
まず上の記述ですが、屈み打撃の場合ほとんどの攻撃が屈んでいればガードできます。
つぎに下の記述ですがこれは言うまでも無く空中打撃に対しては立つようにしてあります。
そして掲示板の方にも質問がありましたが、Trigger2のEnemyNear,Timeについて。
上の記述も下の記述もTrigger2に立ち打撃が条件となっていますが、EnemyNear,Timeの部分が違います。
これは&u(){「相手の立ち打撃が*フレーム未満の場合は屈み、*フレーム以上だと立つ」}という仕組みです。
通常中段は他の攻撃に比べて発生が遅くなっています。
そこでEnemyNear,Timeを用いて擬似的に中段かどうかを判断させています。
補足ですが*には任意の数字を入れて下さい。
目安とはして16~18ぐらいを入れるとベストかもしれません。
これで立ち下段に対するガードがほぼ完璧ですが、注意点があります。
AIにガードさせる記述、つまりChangeStateです。
この時にステート130や131などに直接飛ばすとガード不可能な攻撃もガードしようとするようです。
それを防ぐためにステート120や121に飛ばすことをおすすめします。
更に精密なAIを作ろうと思うのならばさらにトリガーを増やして条件を厳しくすることを薦めます。
例えば変数(Var)を用いて、相手の数フレーム前のStateTypeを判断したり、擬似的な学習システムを作成しそれによって確率を変化させたりなど。
簡単な例としてはTrigger2は中段対策なのですが、これを数種類に分けて判断させることもできます。
例えばEnemyNear,StateType!=Sを付け加えることによって「立ち状態以外での立ち打撃」という珍しい攻撃を判断することもできます。
この場合は相手が屈んでいるか空中にいるかなのですが、屈み状態ならば中段であることは滅多にありませんし、
空中状態での立ち打撃なんてものも滅多に有りません。
しかし念には念をということで一応それに対するためのトリガーも追加します。
それは&u(){EnemyNear,Vel Y < 0} と &u(){EnemyNear,Vel Y >= 0}です。
これらは&u(){「相手が降下攻撃してきているかどうか」}を判断します。
気晴らしに遊んでいた時に空刃脚を思い出しまして。
しかしこれでもまだメタじみている気がします。
もう少し記述を少なく出来ればそうは感じ無いのですが・・・。
例)
[屈み移行ステート]
Trigger1 = EnemyNear,HitDefAttr = C,AA || EnemyNear,HitDefAttr = SCA,AP
Trigger2 = EnemyNear,HitDefAttr = S,AA
Trigger2 = EnemyNear,Time < *
Trigger2 = EnemyNear,Vel Y <= 0
Trigger3 = EnemyNear,StateType != S
Trigger3 = EnemyNear,HitDefAttr = S,AA
Trigger3 = EnemyNear,Time >= *
Trigger3 = EnemyNear,Vel Y <= 0
[立ち移行ステート]
Trigger1 = EnemyNear,HitDefAttr = A,AA
Trigger2 = EnemyNear,HitDefAttr = S,AA
Trigger2 = EnemyNear,Time >= *
Trigger2 = EnemyNear,StateType = S
Trigger3 = EnemyNear,HitDefAttr = S,AA
Trigger3 = EnemyNear,Time <= *
Trigger3 = EnemyNear,Vel Y > 0
Trigger4 = EnemyNear,StateType != S
Trigger4 = EnemyNear,HitDefAttr = S,AA
Trigger4 = EnemyNear,Time > *
Trigger4 = EnemyNear,Vel Y > 0
屈み移行のTrigger2は立ち下段対策ですが、一応Velが入っています。
これの詳細は後述を参照してください。
立ち移行のTrigger2は中段対策です。
これは&u(){「相手の立ち打撃が*フレーム以上で立ち状態である」}ということで中段と判断させております。
次に屈み移行のTrigger3は&u(){「相手の立ち打撃が*フレーム以上で立ち状態じゃなく下降していない」}というものです。
これは後述するP2StateType中心のトリガーにおけるVel Y = 0に対する屈みと同じようなものです。
もし相手が屈み状態ならばVel Y = 0に当てはまって屈んでくれます。
相手が空中状態であっても下降攻撃以外は屈んで避けてしまえというものです。
といっても対応できる攻撃には限界がありますが・・・。
まさか昇竜に中段があるとは思えませんけどね。
そして立ち移行のTrigger3,4。
この2つは屈み移行のTrigger2,3に対応させています。
まずTrigger3の意味は&u(){「相手の立ち打撃が一定フレーム未満or下降中」}です。
下降中という場合ほとんどが空中状態になっているはずです。
空中状態で攻撃した場合は普通空中属性が付いた攻撃になります。
その場合は立ち移行ステートのTrigger1が反応して立ちます。
もし相手の攻撃が立ち属性の場合はまず屈み移行のTrigger2か3が反応します。
しかしそれは&u(){「相手が下降していない状態」}が条件となりますのでそれに対して&u(){「相手が下降している状態」}という条件のトリガーが立ち移行に必要です。
そのため屈み移行のTrigger2に対して立ち移行のTrigger3が、屈み移行のTrigger3に対して立ち移行のTrigger4があります。
以前は(EnemyNear,Time < *) || (EnemyNear,Vel Y > 0)という記述を使いこれ一つで両方に対応させようとしていましたが、
これだとまだ反応してくれない攻撃があるのでTrigger3と4の2つに分けました。
こちらの方が丁寧と言えば丁寧なんですけどね。
そして最後に飛び道具対策ですが、現段階では完全には出来ません。
ただし無いよりはマシなのでそれを加えた暫定完成形は
[屈み移行ステート]
TriggerAll = AIフラグON
TriggerAll = StateType != A
Trigger1 = Enemy,NumProj > 0 || Enemy,NumHelper > 0 飛び道具が存在する時
Trigger2 = EnemyNear,HitDefAttr = C,AA,AP || EnemyNear,HitDefAttr = SA,AP
Trigger3 = EnemyNear,HitDefAttr = S,AA
Trigger3 = EnemyNear,Time < *
Trigger3 = EnemyNear,Vel Y <= 0
Trigger4 = EnemyNear,StateType != S
Trigger4 = EnemyNear,HitDefAttr = S,AA
Trigger4 = EnemyNear,Time >= *
Trigger4 = EnemyNear,Vel Y <= 0
[立ち移行ステート]
TriggerAll = AIフラグON
TriggerAll = StateType != A
Trigger1 = EnemyNear,HitDefAttr = A,AA
Trigger2 = EnemyNear,HitDefAttr = S,AA
Trigger2 = EnemyNear,Time >= *
Trigger2 = EnemyNear,StateType = S
Trigger3 = EnemyNear,HitDefAttr = S,AA
Trigger3 = EnemyNear,Time <= *
Trigger3 = EnemyNear,Vel Y > 0
Trigger4 = EnemyNear,StateType != S
Trigger4 = EnemyNear,HitDefAttr = S,AA
Trigger4 = EnemyNear,Time > *
Trigger4 = EnemyNear,Vel Y > 0
となります。
ヘルパーにHitDefを載せた形に対してはInGuardDistが有効みたいです。
というわけで屈み移行ステートにEnemy,NumHelperも追加しました。
しかし途中で気付いたので修正したのですが、&u(){ガード移行ならともかく立ち屈み移行にInGuardDistって必要ないですよね?}というわけで修正しました。
これでもしっかりと動いてくれます。
もしInGuardDistが無効になってもそのときはガードを止めてくれますからね。
そして立ち移行からEnemy,NumProj = 0が無くなりました。
これは&u(){「飛び道具がある時確実に屈むから中段で崩される」}という弱点を無くすためです。
もしこれがあった場合、例えば波動拳キャンセル禊なんかくると確実に屈んでしまうため屈みガード不可である禊を受けてしまいます。
そういったものを防ぐために消しました。
&italic(){&u(){P2StateType中心のステート}}
皆さんが良く使うP2StateType(あるいはEnemy,~、EnemyNear,~)についてやってみます。
実はこれ&bold(){だけ}だと一部攻撃には対応できませんが、Timeなどの他のトリガーと組み合わせると対応可能です。
まずは&u(){「相手が空中状態の時のみ立ち他は屈む」}という風にすると
[屈み移行ステート]
Trigger1 = P2StateType != A
[立ち移行ステート]
Trigger1 = P2StateType = A
となります。
ただしこの状態だと立ち中段で余裕で崩されるのでそれに対する対策もします。
[屈み移行ステート]
Trigger1 = P2StateType != A
Trigger2 = P2StateType = S
Trigger2 = EnemyNear,Time < *
[立ち移行ステート]
Trigger1 = P2StateType = A
Trigger2 = P2StateType = S
Trigger2 = EnemyNear,Time >= *
ここまではEnemyNear,HitDefAttr中心のステートとほぼ同じです。
本来ならこれだけでも上等なのですが更にガチガチにしたいという人は
[屈み移行ステート]
Trigger1 = P2StateType = A
Trigger1 = EnemyNear,Vel Y = 0
Trigger2 = P2StateType = C
Trigger3 = P2StateType = S
Trigger3 = EnemyNear,Time < *
[立ち移行ステート]
Trigger1 = P2StateType = A
Trigger1 = EnemyNear,Vel Y != 0
Trigger2 = P2StateType = S
Trigger2 = EnemyNear,Time >= *
とすればOKです。
上との違いはP2StateTypeがAでも場合によっては屈むという条件が追加されている事です。
この場合は&u(){「相手が空中状態で地面と平行に移動している時は屈みそれ以外は立つ」}という条件が追加されています。
これに当てはまる攻撃は限られている気がしますが例としてはサイコクラッシャーとかですね。
まあこれは立っていてもガードできますが。
どっちかというと&u(){「空中突進とか屈んでスルーしようぜ」}というコンセプトでやりました。
役に立つかどうかは不明ですが・・・。
ちなみに普通に空中攻撃をしてもその技独自の動きか重力によってVel Y != 0になるので立ち移行は可能です。
あとこのステートは下段飛び道具とかには完全には対応していないので注意して下さい。
その対応度はEnemyNear,HitDefAttr中心より低いですがまあ気にするほどのものでもありません。
最後に途中までガードするけど途中からガードしなくなるなどの現象はガードに移る条件や
[State X]
Type = ChangeState
Trigger1 = (略)
Value = 140
となっている記述のトリガーをいじってみてください。
自分もこの辺はまだ完璧ではないのでこれ以上は何とも言えません。
・各トリガーの欠点 最終更新12/8
AIを作成する際にはトリガーは非常に重要です。
ですがトリガーにも色々な落とし穴があります。
それについて気付いたものを適当に書き連ねようかと思います。
&italic(){&u(){InGuardDist}}
ガードや回避の際にお世話になるトリガーです。
しかしこれにもいくつかの欠点があります。
&s(){一つ目は&u(){自分の中心軸よりX軸方向に-にいけば無効になる。}}
&s(){簡単に言えば背中側のものは認識しないと言う事です。}
&s(){レミーの上ソニックで調べましたが、まだ前に存在する状態では有効になってました。}
&s(){しかし屈んでいる状態で通っていった時、無効になりました。 }
&s(){いくら相手の飛び道具を屈んで避けれても背後に回った部分に当たってしまっては元も子も有りません。}
&s(){多分めくりに対しても同じことが言えると思います。}
&s(){さらに詳しく実験したところ-方向にいてもしっかりと有効になるようです。}
&s(){しかしProjectileに対しては無反応でした。(レミーの件の他にも斬空など)}
&s(){このことから&u(){同一ステート内においてP2Dist Xの正負が逆になった場合無効になる。}}
&s(){ということが言えるかもしれません}
&s(){ただ現在も実験中なのでハッキリとは言えませんが・・・。}
&s(){ちなみにInGuardDistだけでガードステートに飛ばした場合めくりに対して対応しきれていませんでした。}
更に少しだけ捻って実験してみたところ&u(){「自分と対象のFacingが負の関係にあり自分の中心軸よりX軸方向に-にいけば無効になる。」}
ということが分かりました。
これならめくり攻撃の件も飛び道具の裏周りの件も説明が可能です。
しかしこの対象というのが曖昧なんですよね。
この部分は説明しにくいのでまあ何となくとでも理解して下さい。
二つ目は&u(){GuardDist=0を使用しているものには反応しない。}
これは主に突進系の攻撃によく見られます。
GuardDistとはガードステートに移行する距離のことですが、それが0の場合密着状態じゃないと有効になりません。
突進系の攻撃に対してほとんど対応できていない場合はこれが原因かもしれません。
他にGuardDist=0が用いられるとしたら投げぐらいでしょう。
&italic(){&u(){EnemyNear,~}}
これは自分が主に使っているものです。
勿論他にも使っている人は大勢居るでしょう。
この効果は&u(){自分に最も近い相手の~}です。
やはりこれにも欠点はあります。
それは&u(){ヘルパーに対応していない}ということです。
これについての実用例は後で詳しく説明します。
もしこれがヘルパー対応でしたらそれはそれですごいことになるでしょうが。
EnemyNear,IsHelperとかできたら良かったのになあ。
&italic(){&u(){EnemyNear,HitDefAttr}}
いうまでもなく相手のHitDefAttrを認識するトリガーです。
当身などには何かと便利なのですが地味にいやらしい欠点があります。
一つ目は&u(){攻撃判定が無いと無効になる。}
まあ実際はあまり関係無いのですが、これ中心の記述だと移行が遅れるみたいです。
当然ですよね。相手のHitDefが有効にならないと作動しないのですから。
が、逆を言えば&u(){HitDefが有効にならない限りという条件}がつけられる・・・かもしれません。
編集中に思いついただけなので期待しないで下さい。
それに実用方法が思いつきません。
移行が遅れるのを防ぐにはP2StateTypeだけにするとよいみたいです。
二つ目は&u(){Projectileには反応しない。}
これは実にいやらしいです。
これのせいでEnemyNear,HitDefAttrだけでガードを組むことができませんから。
&s(){またEnemyNear,という記述上&u(){ヘルパーのHitDefAttrを認識できない}という欠点も持ち合わせています。}
&s(){なんか間違いだらけだったのですがEnemyNearでもヘルパーは認識できるようです。}
&s(){これならEnemyNear,IsHelperと組み合わせて何か出来そうですが・・・。}
やっぱりヘルパーの認識は無理みたいです。
というわけで&u(){ヘルパーのHitDefAttrを認識できない}という欠点はやはりあったようです。
・おまけ 最終更新12/1
ここでは愚痴みたいなものを書いていきます。
というよりは現状AIに認識不可能なものを少し。
&italic(){&u(){HelperにHitDefを載せた飛び道具の裏回り状態}}
これは本当に認識不可能です。
いや一応可能と言えば可能なのですが、それをやると今度は必要以上に固まってしまいます。
もしこれがProjectileならばEnemy,NumProj > 0と!InGuardDistによって認識することが可能です。
ProjectileならできてHitDefでは出来ない理由はHelperであることが最大の原因です。
トリガーの欠点について書いてある通りにヘルパーの存在を認識できても詳細は一切認識できません。
ここでProjectileならNumProjとInGuardDistの2つのトリガーによって認識できますが、HitDefだとInGuardDistでしか認識できません。
更にそのInGuardDistも裏回りが認識できません。
無論ヘルパーの存在はNumHelperで認識できますが、それが何かの処理を行うためのものなのか攻撃用のものなのかは認識できません。
そのためInGuardDistなどの相手が攻撃している状態を認識できるトリガーを一緒に組まない限り必要以上にガードするのです。
が、InGuardDistを組ませると裏回りが・・・というジレンマが発生します。
ですのでこれは現状諦めたほうが良いです。
情報提供:B9MW85qx氏
:EQbnUkn9氏