戻る

 AI制作の手引き その2「ステート内部の情報」 by ADI
12:58 2012/01/21 リカバリーについて誘導追加
16:15 2011/10/29 ちょっと追記
05:16 2011/03/22 動作調査中用のAIフラグの操作
21:09 2011/03/04 ちょっと
・・・
22:54 2009/10/22 AIの初歩 から書き直し始め
 これから、AIに関する記述をするための情報を集めます。


 が、第一にデフォルトのAIが付いているかどうか、確かめます。
 付いている場合は、それの大半を削除することになりますが、
  記述の一部は、流用することになるでしょう。

 まず-1ステート、もしくは-3ステートに、Command="***"のない、
  かつTriggerの多いChangeState大量の記述が無いかどうか。
 それはおそらく既にあるAI記述ですので、削除するか、
  別のファイルへ移して、参考にしたりしましょう。

 次にCommand="AI**"もしくは="CPU**"といったトリガーが、
  大量に書かれたVarSetなどが存在しないかどうか。
 こちらはAIフラグを立てるための記述で、無くてもつける為、
  VarsetのV=**、もしくはVar(**)のメモをして、そのままです。


 で、これからAIを記述するための内部情報を調べつつ、
  AI用の記述変更をしていくこととなります。

  >Var変数の仕様表
  >-1,-2,-3ステートの位置。
  >Command="*コマンド名*"の位置(修正する為)

.Var変数

>Varの初歩
 [Varの初歩/txt]なども参照。

 簡単にいうとVarとは変数、
  変数とは「好きな数字を入れておいて保管できるもの」です。
 「○○の数字を保管しておきたい」という時に使われます。

 例えば「AIの動作」と「手操作」を1キャラで分けたい場合、
  AIであるのか、手操作であるのか、その情報の保持が必要です。
 そして、そこでVarが使われています。

 オーソドックスなものは、「基本・手操作」で、
 「手操作では不可能なコマンド」を確認した時、Varに数値を入れ、
  そのVarに数値が入っている場合は「AIフラグ有り・AI動作」という具合。

 このVar変数は1ユニットにつき計100個のスロットがあり、
  整数限定の Var(**)  が0〜59の計60スロット
  小数可能な Fvar(**) が0〜39の計40スロット
 全てのユニットが、キャラ・ヘルパー共に100個ずつ保持しています。

 特殊ゲージなどの制御にもVarは使われ、技の条件にもよく使われます。
 その為、まず「何番のスロットが既に使われているのか」
  使用されているVarの仕様表を作ります。


>Varの仕様表
 まずVarを記録する新しいテキストファイルを作ります。>VarSlot.txt<をどうぞ。

 そして、キャラクターに付属しているテキストファイル、もしくはCnsファイルの中に、
  Var表がある場合それを参考に、Varスロットの表を埋めていきます。
 無い場合は全てのファイルでVarsetなどを探します。

 [ Varset ] [ Varadd ] [ VarRandom ] [ VarRangeSet ]
 [ ParentVarAdd ] [ ParentVarSet ] のステートコントローラー名と、
 [ := ]という条件式中にVarsetする記述を、検索ワードにすれば探せます。
 スロットは V=** var(**) や FV=** fvar(**) の**を参照。
  VarRangeSetは、VもしくはFVの First=** から Last=** までのスロット。
 ただし[StateDef 5900]にあるVarRangeSetは
  チームモード時用のリセットなので無視して構いません。

 := は、トリガー記述と同じように書きますが、代入を行うのは参照したときのみ。
 例えばトリガーの最後尾に書かれているものなどは、
  そのトリガーが実行される時に代入しされます。
 細かい参照などについては、序にあったTriggerの図解を御参照ください。


 ただ何に使われているかは、説明も名前も無い場合、
  ステートコントローラーのトリガー記述などから察するほかありません。
 また、これらだけだと「ヘルパー管理のVar」なのか、
  「本体管理のVar」なのかも分かりません。
 なので良く分からない場合は「有」とだけ記録しておけばいいでしょう。
 一応、[Helper]で検索をかけていってそれっぽい記述を探す方法もありますが。

 なお、 Var( x + Var(**) ) = といった記述は極めて特殊です。
 V = x + (*条件式*) というような記述であれば、
  (*条件式*)は、条件式が真なら1を、偽なら0となるので、
  xとx+1のスロットを記録するだけでいいのですが、
 Var(x+Var(**))といった記述は、どこまでの範囲なのか分からない為、
  そのVar(**)がなんなのかなど、調べなければいけません。
 そこまで複雑なものだと、全てのStateDefに目を通し、
  そのキャラクターの仕組みそのものを熟知する必要があります。



 全て埋め終えましたら、「AIフラグ用Var」を決めましょう。

>AIフラグ用Var
 冒頭で言っていた「Command="AI**"」などが大量に書かれたトリガーの、
  Varsetが存在している場合は、そのVarを使います。
 それが無い場合は、空いているVarをAIフラグ用にしますので、
  Varの仕様表で確認し、「AIフラグ」と表に加えておきましょう。

 AIフラグは、これでもかというくらい使うようになる為、
TriggerAll = !Var(*AIフラグスロット*);AI停止時
TriggerAll = Var(*AIフラグスロット*) ;AI起動中
 というトリガーを作っておきましょう。(以下*AIフラグ*と省略)
 AI停止時はCommand="**"のある記述に使い、
 AI起動中はその代替記述、AI動作の記述で使います。


 あと最低限使いそうなAI用Varは、
  EnemyNear(x),用Varにコンボ判別用のVar。
 ちょっとこって技振り用のRandomVarや細かい処理にコマンド用Varくらい

>AIフラグを立てる記述の設置方法
 AIフラグの記述が元々無い場合の為の方法です。

 オーソドックスだと言っていた代表的な記述 >[AI用Cmd式 AIフラグセット/txt]

 この他HelperとCommandを使ってAIフラグを立てる方法や、
  (※参考:平成a氏のAI説明書 基本.txt とか※)
 手操作の場合に特殊な操作を行う事でAIフラグを抑制するなども。

 設定項目を作り、そこで常時起動状態にもできるAIもある。
 それら以外ではPalNo(カラー番号)を条件にして、PalNo>6(7番以上)で
  スタートボタンを押して選択した場合にフラグを立てるという方法もあります。


 AI動作を作って確認している間は常時起動にしておくか、
 もしくはCMDファイルに下のようなコマンドを追加して、
[Command];※Commandの種類上限に注意
name = "AIholds"
command = /s;←Startボタン押しっぱなし
time = 1
 -1か-3ステート(できるだけ分かりやすい所)に下の記述を追加すれば、
[State adi];-1か-3ステートに置く
Type = Null
TriggerAll = 1 ;使わないときは0,使うときは1
Trigger1 = Var(*AIフラグ*) := (Command="AIholds") ;必要なら(Command="AIholds")*10などにする。
 これを使う状態の時はスタートボタンを押し続けている間のみ、
  AIが起動するという状態にできるため、好きなときに起動・停止でき
  細かいAI動作の調査がしやすくなります。
.-1,-2,-3ステート
 -1ステートは、Cmdファイルの中に入っていることが基本ですが、
 -2ステートや-3ステートは、他のステートと同様、Cnsファイルに入っています。

 それらは序で説明した通り、-3ステートは-1ステート同じ準常時監視ステート。
  -2ステートは、相手にステートを奪われていても参照を行う常時監視ステート。
 一応になりますが、それらの位置は知っておきましょう。
 AI記述も処理の関係上、-1ステートの後ろに置くのが望ましいので、ほぼ「一応」なのですが。

 Cnsファイルで片っ端から[StateDef -2][StateDef -3]を検索します。
 それらがステート記述の開始ですので見つかったファイルと場所をメモしましょう。
 あと出来れば、-1ステートも含め、-1,-2,-3ステートの先頭から [StateDef で検索をかけ
  最後尾がどこかも憶えておきましょう。後にStatedefが無い場合は、ファイルの最後尾がそうです。


 ※2010/09/09:追記※
 あとヘルパー関係で探す物があります。
 Cnsファイルで片っ端から HelperType KeyCtrl で検索をかけ、
   HelperType = Player KeyCtrl = 1 が無いかを確かめてください
 一応 HelperType = Normal KeyCtrl = 0 は大丈夫な証です。
  HelperType = Player KeyCtrl = 1 があった場合、そのType=Helperの中で
  指定されている ID = *ここの番号* をメモしておいてください。複数あったら全て。

 説明すると HelperType = Player -2,-3ステートを読み込む設定
   KeyCtrl = 1 -1ステートを読み込む設定で、注意する必要があります。
 それらのヘルパーがAIの記述を読み込んでしまうと不具合を起こす危険性が高いので、
  AIフラグを立てる条件の中にTriggerAll=!IsHelper(*メモした番号*)を並べて、
  AIフラグ立て以外全てのAI記述にTriggerAll=Var(*AIフラグ*)を追加してください。
 調べるのが嫌でしたら、単にAIフラグ条件へTriggerAll=!IsHelperとつけて、
  全てのAI記述にTriggerAll=Var(*AIフラグ*)をおいておけば間違いないです。
 解説するとIsHelperとは「読み込んでいるユニットがヘルパーであるか」という情報で、
  IsHelper(*番号*)とすると「読み込んでいるユニットがヘルパーID*番号*のヘルパー」になり、
  それを!(否定)で繋ぐため「〜ヘルパーではない」という条件になり、
  ヘルパーには一切読み込まれなくなる、ということです。




>-1ステート他のAI用記述化
 まず-1ステートにあるAIフラグセット以外のトリガーに、
  Command=""のある記述全てへ、先ほど作ったこの記述を入れていきます。
TriggerAll = !Var(*AIフラグ*);AI停止時

 その記述を入れることで、AIフラグが立っている間、
  現時点では-1ステートでの動作処理の全ては封印されます。
 試しにウォッチモード(Watch)で動作を確認しましょう。

 すると、AIフラグが立つまでは技などを振るものの、
  AIフラグがたった後も動作を封印したはずなのに動くことが確認できるはず。
  それが「-1ステートで制御されていない動作」です。
 まず、歩き・ジャンプ・屈み以外の動作がある場合は、
  -2,-3ステートでCommandを探し、AI停止時のトリガーを加えましょう

 歩き・ジャンプ屈みなどのステート制御でない動作を防ぎたい場合は、
[State adi, NoMove];AI記述ステートの最後に加える
Type = ChangeState
Value = 0 ;強制立ち
TriggerAll = Var(*AIフラグ*);AI起動中
TriggerAll = PrevStateNo = 0;直前が立ちステート。
TriggerAll =(StateType = S || StateType = C) && Ctrl && !Time ;地上+Ctrl+Time=0
Trigger1= StateNo = 20 ;左右(歩き)
Trigger2= StateNo = 40 ;上(ジャンプ)
Trigger3= StateNo = 10 ;下(屈み)
Ctrl=1
 この記述を最後に加えることで、MUGEN側のCPU,AIでは0ステートから動かなくなります。
 勿論これだけだとガードをする他、しゃがみ動作中やガードした時などは
  勝手に動いてしまうので、各自調整する必要はありますが。

 AIを作り始めてからの話ですが、
 勝手なジャンプに悩まされる場合はこちらを追加すると、
  ジャンプの代わりに屈み動作を行います。ただし細かい挙動を要確認。
[State adi, NoJump];AI記述ステートの最後に加える
Type = ChangeState
Value = 10 ;強制屈み
TriggerAll = Var(*AIフラグ*);AI起動中
TriggerAll = StateType = S && Ctrl && !Time ;立ち+Ctrl+Time=0
Trigger1 = StateNo = 40 ;ジャンプ

 こちらも細かい挙動を要確認ですが、
  勝手にガードを解くことを制限する場合はこちら。
[State adi, Guard];AI記述ステートの最後に加える
Type = ChangeState
Value = 120;強制ガード
TriggerAll = Var(*AIフラグ*);AI起動中
TriggerAll = PrevStateNo = [120,140] ;直前がガードステート
TriggerAll = InGuardDist && Ctrl && !Time ;InGuardDist+Ctrl+Time=0
Trigger1 = StateNo = 20 ;歩き
Trigger2 = StateNo = 10 ;屈み
Trigger3 = StateNo = 12 ;立ち上がり
Trigger4 = StateNo = 40 ;ジャンプ

 その他、Ctrlのあるステートから関係の無い行動を制御したい場合は、
  ステート側を変える必要がありますので、分からない内は諦める。
※この項は不可欠要素ではないため、精密な動作にこだわらない方、
  またステート記述に慣れていない方は、読まなくても大丈夫ですが、
  軽く読み流すくらいはしておいてほしいです。


.コモンステート(Common State)
 その他のステートのAI用記述化を行いますが、
  まずDefファイルの[Files]にあるstcommonのファイルを探してください。
 特殊なキャラで無い限り、 common1.cns と書かれており、
  キャラクターのフォルダ内には、そのファイルが無いはずです。

 0から199まで、5000から5999までの間にあるステートは、
  コモンステートと呼ばれる、基礎動作のステート群で、
 それらはまず、common1.cnsというM.U.G.E.Nで管理している
  コモンステートだけ書かれたファイルから読み込まれています。
 簡単に言うと「キャラを最低限、動かすためのステート」がコモンステートです。

 キャラクターによっては特殊な動作をさせるため、
  Cnsファイル内に一部のコモンステートを書いている場合もありますし、
  Commonファイル自体をキャラ独自で定義している場合もあります。

 そして、コモンステートにも、Command="***"は使われているため、
  AIでも制御ができるよう、コモンステートを変えなければいけません。
 変えなければいけませんが、common1.cnsを変更するのではなく、
  キャラクターのCnsファイルにコモンステートを追加する形になります。

 もちろん、stcommonがキャラ付属のファイルであったり、
  Cnsファイルにコモンステートがあるなら、それの記述を変更しますが。


>コモンステートのAI用記述化 (大雑把ですが)
 まず最初は、全てのCnsファイルへ
  [StateDef 20] [StateDef 40] [StateDef 45]で検索をかけ
  ステート20,40,45の3つが記述されているかどうか探しましょう。

 20は歩きステート、40,45は地上ジャンプ,空中ジャンプの始動ステートです。
 ある場合は、ステート記述を読み、どうなっているのかを確認し、記述を調整。
 無い場合はCommon1.cnsの中から記述を移すことになります。


 Common1.cnsはMUGENのdataフォルダ内にあります。
 そのファイルで[StateDef 20] [StateDef 40] [StateDef 45]を検索し
  それらのステートをキャラクターのCnsファイルへと移します。
 既存ファイルに分かりやすいようメモと目印をつけて入れるか、
  AI用のCnsファイルを新規に追加するかは各自の判断で。分かりやすいように。
 Cnsファイルの数には Cmd + StCommon + Stが9まで と上限がある為、注意


■State,20
 まず歩きステートである[StateDef 20]
 ステートコントローラーはVelSet2つに、ChangeAnim2つですが、
  AI用に記述を変更するのはVelSetの2つです。

 1度確認の時に使ったChangeStateで、20ステートへ飛ばしてみてください。
 歩かないはずで、レバーを動かすと歩きますがアニメーションが止まりません。

 処理を良く見ると分かるのですが、歩きステートは
  「Command="holdfwd" 」の時、前側へ加速 (+Vel)
  「Command="holdback"」の時、後ろ側へ加速(-Vel)
  「速度が前向き」という時、 (一定条件で)前進アニメに変更。
  「速度が後ろ向き」という時、(一定条件で)後進アニメに変更。
  付け加えると基本動作のステート変更はM.U.G.E.N本体の管理。
 の4つのステートコントローラーで構成されています。
 Commandが無い場合、前へも後ろへも行かないのは、そういう記述だからなのです。

 その為、AI動作では必ず動くよう変更します。
 というわけで、まずCommandのあるステートコントローラーに
TriggerAll = !Var(*AIフラグ*);AI停止時
  ↑こちらの条件式を追加しておき、その下に新しく
[State 20, 1-2];AI用制御 ■前進の制御
type = VelSet
TriggerAll = Var(*AIフラグ*);AI起動中
;Triggerは、AI用の行動条件。各自でキャラにあわせた調整をする
Trigger1 = P2BodyDist X > 80 ;例1:中距離くらい(通常技の届く最長距離辺り)
Trigger1 = Anim != 21 || P2BodyDist X > 80 +30 ;例1:後退アニメでない or 上の数値+30
Trigger2 = BackEdgeBodyDist < 15 || ( Anim = 20 && BackEdgeBodyDist < 45 ) ;例2:壁際対策
Trigger3 = P2MoveType = H ;例3:相手がくらい動作中
;Anim,20は前進の・Anim,21は後退のアニメーション。主に「超高速ジグザグ」の回避。
x = const(velocity.walk.fwd.x)

[State 20, 2-2];AI用制御 ■前進でなければ後退
type = VelSet
TriggerAll = Var(*AIフラグ*);AI起動中
trigger1 = Vel X < const(velocity.walk.fwd.x);前進速度未満の場合、後進
x = const(velocity.walk.back.x)
 という様な記述を追加しましょう。
 念のため、AIフラグのTriggerの先頭に;などをつけて、
  ステート20へ飛ばし、どのような動作をするのか確認しておきます。



■State,40 & State,45
 今度はジャンプ始動ステートの[StateDef 40][StateDef 45]

 まず地上ジャンプステートは
  「sysvar(1)のリセット」 SysVar(1)を 0に(ニュートラル)
  「レバーが前側の場合」 SysVar(1)を 1に(前判定)
  「レバーが後ろ側の場合」SysVar(1)を-1に(後ろ判定)
  「ジャンプ準備アニメ終了時」 VelSetを行う
   >Vel X はSysVar(1)から前後などの速度を決める
   >Vel Y をジャンプ速度にする
  「ジャンプ準備アニメ終了時+直前がダッシュステート(100)+レバー前判定」
   >VelSetで、Vel Xをジャンプダッシュの速度にする。
  「ジャンプ準備アニメ終了時」 ChangeStateで空中ステート,50へと入り、Ctrlを取り戻す
 という処理。AIで手を加える場所はSysVar(1)をセットする部分になります。

 空中ジャンプステートも動作処理はほぼ同じで
  「アニメ番号44があれば」 アニメーションを44番に
  「アニメ番号44がないなら」アニメーションを41番に
  「sysvar(1)のリセット」 SysVar(1)を 0に(ニュートラル)
  「レバーが前側の場合」 SysVar(1)を 1に(前判定)
  「レバーが後ろ側の場合」SysVar(1)を-1に(後ろ判定)
  「ステート経過 Time = 2 で」 VelSetを行う
   >Vel X はSysVar(1)から前後などの速度を決める
   >Vel Y をジャンプ速度にする
  「ステート経過 Time = 2 で」 ChangeStateで空中ステート,50へと入り、Ctrlを取り戻す
 という処理。こちらも、手を加える場所はSysVar(1)の部分だけ。

 歩きステートでのVelSetと同様に、
  Commandの使われている記述にAI停止時限定の記述を追加し、
  AI起動中はCommandと異なる条件でVarSetを行わせる形となります。
 ただし、ジャンプステートは前後のない「ニュートラル」もある為、Varsetは任意です。

 記述例はこんな感じ。
[State AI jump]
type = VarSet
TriggerAll = Var(*AIフラグ*);AI起動中
;Triggerは、AI用の行動条件の1例。各自でキャラにあわせた調整をする
Trigger1 = P2BodyDist X > 120 ;例1:中距離〜遠距離
Trigger2 = P2BodyDist X < 45 && P2Dist Y > 100 ;例2:至近距離で高い。
Trigger2 = FrontEdgeBodyDist > 60 ;例2:前壁対策
Trigger3 = P2MoveType = H ;例3:相手くらい動作中
Trigger4 = BackEdgeBodyDist < 60 ;例4:壁際対策
sysvar(1) = 1

[State AI jump]
type = VarSet
TriggerAll = Var(*AIフラグ*);AI起動中
;Triggerは、各自でキャラにあわせた調整をする
TriggerAll = BackEdgeBodyDist > 70 ;例:壁際対策・後ろが広い
Trigger1 = P2BodyDist X < 45 && P2Dist Y < 100 ;例1:至近距離・高くない
Trigger2 = P2MoveType = A ;例2:相手攻撃動作中
sysvar(1) = -1

; P2Dist Yは、空中ジャンプ用なので地上ジャンプでは削っても良い。
; 高さは EnemyNear(!(EnemyNear,Alive||NumEnemy=1)),Const(Size.Height)に
;  -10から-20 くらいがいいかも。ちなみに↑は「(生きている)一番近い相手の,身長の数値」

 兼用として記述していますが、キャラによって
  ジャンプの地上・空中の性質は異なると思いますので
  フラグの行をコメントアウト( ; )し、試しにジャンプをさせること確認しましょう。


 ちなみに、空中ジャンプをAIにさせたい場合、面倒です。
 まず以下のステートを-1ステートに追加して、
  どういう動作を行うのか実際に見てください。

[State -1, jump]
Type = ChangeState
Value = 40
Trigger1 = Ctrl && ( StateType != A ) ;Ctrl可能+空中でない
[State -1, Air jump]
Type = ChangeState
Value = 45
Trigger1 = Time > 15;タイミング用
Trigger1 = Ctrl && StateType = A ;Ctrl可能+空中

 キャラクターが際限なく上へと、上っていくはずです。
 その原因は「空中ジャンプに制限をかけていない記述」のため。
 ジャンプの制御はMUGEN側でおこなわれており、
  回数を参照するトリガーなども無い為、少々面倒です。

 例えば空中ジャンプをした時( StateNo=45 && Time=1 )に回数をVarで記憶し、
  (Const(Movement.AirJump.Num))の上限数値と、そのVarを比べることで、
  AIに回数制限をかけることができます。リセットはStateType!=A(空中でない)の時。
 ですが、それだけだとAI側のジャンプの回数とシステム側のジャンプの回数は別々なので、
  AI側でジャンプした後にも、システム側のジャンプはできてしまいます。

 私の考えられる対処法はおおよそ2通りで、
  AI用空中ジャンプ以外でジャンプしないよう、空中ジャンプステートなどを書き換える。
  CNS設定にあるMovementのAirJump.Numの数値を最初から0にし、-3か-1のステートで
   システムと同じような条件の空中ジャンプコマンドの記述を書き加える。

 これらはどちらも内部処理を熟知していないと厳禁ですので、
  分からないうちは空中ジャンプの制御はあきらめましょう
 一応後のページで紹介しますが。



 ちなみにジャンプ動作からCtrlの戻るタイミングは早いので、
  Pos Yで高さを確認したり、Timeで動作時間を確認したり、
  Vel Y<0で下降中などといった条件を使って空中ジャンプさせることになります。
 できるなら。


 紹介した方法では基本的にCommandの代替トリガーを作る形で制御していますが、
  そのトリガーをVar(**)=xにすることで制御する方法もあります。
 また動作が全く同じで、かつ独自に制御を行う「AI用ステート」という手段もあります。
 という方法もありますが、詳しいことは割愛。慣れれば難しいでもありませんし。


 ※上の項の続きのようなものですが、こちらは不可欠な場合もあります。
  あと、特殊なキャラは最初から度外視してます。そういったものは慣れてから触れるものです。


■ダッシュステート State,100
 0〜199はコモンステートですが、ダッシュステート[StateDef 100]は、
  キャラによって性質が異なることも多いので、Cnsファイルにあることも多いです。
 ただし無い場合はCommon1.cnsから持ってくる事になります。
  持ってきたりする辺りは上の項で説明していますのでそちらをご参照ください。

 ダッシュはワープやステップならCommand制御自体無いのですが、
  走っていく方式、スライドする方式の場合Commandで制御が行われています。

 では、まず[StateDef 100]を探しておいて、
[State adi]
Type = ChangeState
Value = 100
Trigger1 = StateNo=0
 を-1ステートに記述し、動作を確認しましょう。
 「立ちモーションで前へスライドする」と言った状態や、
  小刻みにダッシュを繰り返す状態の場合、
  レバーを前に倒すと通常のダッシュ状態になるはずです。

 そうしたダッシュステートで使われてる記述は、
Trigger1 = Command != "holdfwd" ; レバーが前側でない
 という条件で、戻るステートへと移行させるもの。
 AIの場合は、Commandの条件を別のトリガーに代え制御することになります。


 Command != "holdfwd"のある記述をコピーし、元の方には
TriggerAll = !Var(*AIフラグ*);AI停止時
 この記述を追加し、複製した方には
TriggerAll = Var(*AIフラグ*) ;AI起動中
こちらの記述を追加し、Command != "holdfwd"のトリガーをAI用に変更します。


 Common1.cnsと同じダッシュステートの場合はこんな感じ。
[State 100, 4]
type = ChangeState
TriggerAll = !Var(*AIフラグ*);AI停止時
trigger1 = command != "holdfwd"
value = 0

[State 100, 4-2 AI]
type = ChangeState
TriggerAll = Var(*AIフラグ*) ;AI起動中
;あくまで1例。キャラクターに合わせて調整すること。
TriggerAll = Time > 5 ;例:小刻みになりすぎないよう
Trigger1 = InGuardDist ;例1:ガード可能範囲内
Trigger2 = P2BodyDist X < 60 ;例2:近距離
value = 0
 またダッシュする条件には、終了条件でないことも加えておきましょう。


■ガードステート State,120~State,155
 ガードの制御は試合に大きな影響を与えかねないものです。
 ガードステート[StateDef 120]を探し、
  Cnsファイルに無い場合、Common1.cnsから持ってきますが、
  今回は120から155全てが必要なわけではありません。

 細かい制御をしたい場合には120から155全てが必要になりますが、
  そうでない場合 120 130,131,132 のステートだけあれば不便はありません。
 そして例によってCommandのトリガーのある記述をコピーして、
  それぞれにAI停止中・AI起動時の記述を追加し、
  AI用側のCommandのトリガーをAI用に変えます。

 まず120ですが、ここはガード始動ステートで120の処理は以下の通り
  「ステート経過時間 Time = 0 で」
  >アニメーション変更
  >ステートタイプ変更 × 3
  「StateType=S && Command ="hloddown" 立ち+レバー下側」  >Hi to LoのStateType変更
  「StateType=C && Command!="hloddown" 屈み+レバー下側以外」>Lo to HiのStateType変更
  「アニメーション時間 AnimTime = 0 で」>ガード待機ステートへ。
  「Command!="holdback" レバー後ろでない」>ガード終了ステート140へ
  「!InGuardDist ガード可能範囲でない」 >ガード終了ステート140へ
 次に130,131のステートは
  「アニメーションが130,131でない」 >アニメーション変更、番号130,131
  130側「Command ="hloddown" レバー下側」  >Hi to LoのStateType変更
  131側「Command!="hloddown" レバー下側以外」>Lo to HiのStateType変更
  「Command!="holdback" レバー後ろでない」>ガード終了ステート140へ
  「!InGuardDist ガード可能範囲でない」 >ガード終了ステート140へ
 と、大半が120からの流用が可能なものです。

 132も、Commandの部分は
  Sysvar(0)は着地判定
  「着地判定+レバー後ろ+ガード可能範囲」>立ちガードステート130へ
  「Command!="holdback" レバー後ろでない」>ガード終了ステート140へ
  「!InGuardDist ガード可能範囲でない」 >ガード終了ステート140へ
 の辺りだけですので、大体は同じなのでサクッとやりましょう。


 まず最初にガード終了ステートへ飛ぶこの記述
[State 13x, Stop Guarding];13x番ステートにある記述
type = ChangeState
trigger1 = command != "holdback"
trigger2 = !inguarddist
value = 140
 ↓こうするだけでも構いません。
[State 13x, Stop Guarding];13x番ステートにある記述の改変
type = ChangeState
trigger1 = command != "holdback" && !Var(*AIフラグ*);AI停止時
trigger2 = !inguarddist
value = 140
 また、空中ガード(132)記述にあるCommand="holdback"の後にも
  ↑と同様にAI停止時用の記述を追加してやりましょう。

 130,131ステートはCtrlもある為、基本的な動作も行わせられます。
  (Cns式の)AIでは140ステートに飛ぶ必要性もありませんので。


 次に Hi to Lo と Lo to Hi の記述書換え、なのですが、
  基本は殆ど同じなので、140と150から153も流用で書き換えることが可能です。
 必要だと思えばどうぞ。

 番号は120ですが、内容は140や150,151,152,153と、120はほぼ一緒です。
[State 120, Hi to Lo];120,140,150,151,152,153番ステートにある記述の改変
type = StateTypeSet
TriggerAll = StateType = S
Trigger1 = Command = "holddown" && !Var(*AIフラグ*);AI停止時
Trigger2 = P2StateType = C && Random < 100 && Var(*AIフラグ*);AI起動中+相手屈み状態
Trigger3 = Random < 100 && Var(*AIフラグ*) ;確率用
statetype = C
physics = C

[State 120, Lo to Hi];120,140,150,151,152,153番ステートにある記述の改変
type = StateTypeSet
TriggerAll = StateType = C
Trigger1 = Command != "holddown" && !Var(*AIフラグ*);AI停止時
Trigger2 = P2StateType != C && Random < 100 && Var(*AIフラグ*);AI起動中+相手屈み以外
Trigger3 = Random < 100 && Var(*AIフラグ*) ;確率用
statetype = S
physics = S

 130と131は、これらのTrigger1とTrigger2などを
  Hi to Lo、Lo to Hiを合わせてTrigger1と差し替えるだけです。
 ガードの切り替え精度を悪くするため、Randomを用いています。
 しかし「切り替えた先でも切り替える」ため、
  気になる場合はTimeなどを追加するといいかもしれません

 ちなみに100%切り替えるようにしてしまうと、
  立ち下段などに100%引っかかってしまいますので注意。


 150,152の制御を行っている場合、それらにある
[State 152, 3]
type = ChangeState
trigger1 = HitShakeOver
value = 151 + 2*(command = "holddown")
 といった記述も
[State 152, 3+AI]
type = ChangeState
trigger1 = HitShakeOver
value = 151 + 2*(command = "holddown"&&!Var(*AIフラグ*)||Random<100&&P2StateType=C&&Var(*AIフラグ*));AI時、相手の体制に依存
 という風に変更しておきます。


 コモンステートはとりあえずここまで。
 Common1.cnsでCommandと探せばリカバリーなども出てきますが割愛
 どうしても知りたい場合は>AI用のリカバリー制御について<を参照

 また、ステート記述に慣れてきて、Varなどを自在に使えるようになってきたら、
  Varを用いた管理を行ってみてもいいかもしれません。出した例はあくまで簡易例です。
.動作ステートのCommand制御
 キャラクターは千差万別。こちらには統一した方法はありませんので、
  ステート記述を見ながら、どううればいいか考えて記述するほかありません。

 その為今回はあくまで大雑把な案だけです。


 まず、動作のステートでCommandを制御するものは、主に4種類あるはずです。
 1.強弱判定。主にTime=0でボタン判定を行うもの。
 2.溜め判定。主にボタンを押しっぱなしにすることで溜められるもの。
 3.キャンセル動作。主に、新たなコマンドを入力することで技をつなぐもの。
 4.特殊効果判定。主に、新たなコマンドを入力することで特殊な効果を加えるもの。


 1はTime=0といったトリガーが特徴で、主に歩き動作などと同様の記述を加えます。
 AI判定用にVarを使うことで細かい制御も可能ですが、
  その場合は Var(**):=xx の代入方法が便利です。
Trigger** = 1|| Var(**):=xx
 というような記述をChangeStateのTriggerそれぞれの最後尾に置くことで、
  ステート変更を行うと同時にVarsetも行えます。もしくは
Value = ( Var(**):=xx )*0 + ( *ステート番号* )
 という記述なら、「Value は 処理を行うときのみ参照する」なので、
  Var(**):=xxを*0(=0)して、ステート番号を加算すれば問題なく動きます。

 その場合の動作ステートの判定記述は、
TriggerAll = Time = 0
Trigger1 = Command ="**" && !Var(*AIフラグ*);AI停止中
Trigger2 = Var(**) = xx && Var(*AIフラグ*);AI起動時

 と
TriggerAll = Time = 0
Trigger1 = Command ="**" && !Var(*AIフラグ*);AI停止中
Trigger2 = Var(**)!= xx && Var(*AIフラグ*);AI起動時

 といった方法ような感じで行わせることになります。
 2つ目を!=で行っているのは「バグ回避用」です。



 2はCommand!="hold***"といったトリガーが特徴で、主にダッシュ制御と同様。
 Commandの代わりにいつ開放するか、といった判断のトリガーを加えます。
Trigger1 = Command !="**" && !Var(*AIフラグ*);AI停止中
Trigger2 = Var(*AIフラグ*);AI起動時
Trigger2 = *条件式*

 という様な形になるでしょう。
 特にいつまでも溜められるような技の場合は、
  Time > xx などの時限式トリガーもつけておくと、溜めすぎを防げます


 3はTime=0はなくCommand="***"のあるトリガーが特徴。
 こちらも2と同様、かつ基本的なキャンセルコンボなどと同じような記述になります。
 4もほぼ同様でしょうか。

 ちなみに2〜4は、-1ステートなどで行っても大差ありません。
  勿論わずかながらな差はありますが、わずかながらのものです。
 とは言うものの、キャラ制作者が自分で無い場合、
  それが大丈夫かどうかの確認するをべきですが。

 設定可能な細かい調整のAILv論を参照。

 こちらではほとんど説明しませんが、
  必要なら最初から準備しておくと楽です。

 その3へ続く。


 ■Common,CommandのVar制御化の手引き
 ガードなどの動作をVar制御にすることで柔軟な動作を行わせるもの。
 考え方は条件を-1か-3のステートで記述してVarsetを行い、
  セットしたVarを条件に動作を行わせるという具合なので簡単です。

 例として、歩き動作では基本記述を
[State 20, 1]
type = VelSet
trigger1 = command = "holdfwd" && !Var(*AIフラグ*);AI停止時
Trigger2 = Var(*AI,Cmd制御Var*) = x && Var(*AIフラグ*);AI起動中
x = const(velocity.walk.fwd.x)

[State 20, 2]
type = VelSet
trigger1 = command = "holdback" && !Var(*AIフラグ*);AI停止時
Trigger2 = Var(*AI,Cmd制御Var*)!= x && Var(*AIフラグ*);AI起動中
x = const(velocity.walk.back.x)
 と言う具合に変更し、
[State -1, state20];前歩き
Type = ChangeState
Value = 20 + (var(*AI,Cmd制御Var*):=x)*0;Varを:=で設定。
TriggerAll = Alive && RoundState && Var(*AIフラグ*);
TriggerAll = Ctrl && StateType != A;歩行条件
Trigger1 = *歩行の始動条件*
Trigger2 = StateNo=20 || PrevStateNo=20
Trigger2 = *歩行の継続条件*
 といった記述で制御するような感じ。

 AI,Command制御のVarは途中で設定を変更したり、
  リセットの設定をしっかりとしておけば兼用もできます。
[State -1, AiCommand Reset];
Type = Varset
var(*AI,Cmd制御Var*) = 0
TriggerAll = Var(*AIフラグ*);AI処理条件
TriggerAll = Var(*AI,Cmd制御Var*)
Trigger1 = StateNo != 20 && StateNo != 40;立ち・ジャンプ始動
Trigger1 = StateNo != 100;ダッシュ動作
Trigger1 = StateNo != [120,159];ガード中


 ■余談:MUGEN側のCPU,AIについて。
 実はあれが起動されている状態でCtrlがあり、
  InGuardDistに入るとCPU,AIがガードを行います。
 レベルによる差は分かりませんが、全く使えない子ではないのです。


 ■余談2:終了時始動
 AIによっては技の終了命令から動作を始動させることもあります。
 もちろん手操作では不可能な動作で軽い性能改変に当たりますが、
  より安定した動作をさせたい場合などに使われるようです。



戻る