4:AI製作開始

上記で確定したcommandを含むstateを全て、上記で特定した[statedef-3]の下で、他のstatedefの上にコピペする
配置は自由だが、すでに記述されてる内容の阻害をしないように、最下段に挿入するのが望ましい
また、statedef-3が存在しなかったり、良く分からないなら、[statedef-1]に挿入しても良い
(-2ステートで行っている処理の内容によっては同一フレームにおける-3ステートと-1ステートの状況が異なる場合があるので、
 厳密にAIを作る場合は-1で行動用の記述を組む方が望ましい)

上記で把握した、各種技の特性に合わせてtriggerを設定する
(triggerの詳しい仕組みや内容などは、ググるか、和訳KFMを見れば把握できるので、ガンガレ)

また、元からある条件は遵守すること。じゃないと技の性能が変わり、改変となるため
ただし、元の条件に含まれているなら、記述そのものを変更して問題は無い

 注意点
AIを入れるのは、コピペした方のみ
元記述を直接変更すると、操作出来なくなる可能性が高い

Before

;高火力、非固定の乱舞技。移動距離は短い。根元から当てないと安い
;三烈カンフー突き手(ゲージレベル1)
[State -1, Triple Kung Fu Palm]
type = ChangeState
value = 3000
triggerall = command = "TripleKFPalm"
triggerall = power >= 1000
trigger1 = statetype = S
trigger1 = ctrl
trigger2 = statetype != A
trigger2 = hitdefattr = SC, NA, SA, HA
trigger2 = stateno != [3000,3050]
trigger2 = movecontact


After

;高火力、非固定の乱舞技。移動距離は短い。根元から当てないと安い
;三烈カンフー突き手(ゲージレベル1)
[State -1, Triple Kung Fu Palm]
type = ChangeState
value = 3000
triggerall = var(59) = 1 && RoundState = 2
triggerall = power >= 1000
triggerall = statetype != A
triggerall = p2statetype != L && P2BodyDist X = [0,60]
trigger1 = ctrl && random<=20 && p2movetype != A
trigger2 = (stateno = [1000,1010]) || stateno = 210
trigger2 = stateno != [3000,3050]
trigger2 = movecontact


triggerall:共通条件。これが満たされて無いと起動しない
trigger1:基本トリガー。これが無いとエラーが出る
trigger2:3,4,5と増やせる

上記の場合、KFMが地上に居て、相手がダウン時以外で、ゲージが足りて、
ある程度的が近くに居る時に、低確率で発動
または、カンフー突き手の弱&強や立ち強パンチが相手に当たった(ガード含む)時にキャンセルして発動する

 <内訳>
 triggerall
var(59) = 1
AI発動スイッチ。ようするにvar(59)の中が「1」の場合
RoundState =2
戦闘中の意味。これが無いと、戦闘終了後も動き続ける
power >= 1000
パワーゲージが1本以上。つまり1000点以上溜まってる場合
statetype != A
自分の体勢。空中にいるとき意外の場合。ダウン中も含むので注意
p2statetype != L && P2BodyDist X = [0,60]
相手の体勢。相手がダウン中以外の場合で、さらに、ある程度近く(60pixel以内)にいる場合

 trigger1
ctrl && random<=20 && p2movetype != A
キーコントロール可能な状態(自由行動可能な状態)で、さらに、0~999の乱数が20以下
さらに、相手が攻撃状態、以外の場合

 trigger2
(stateno = [1000,1010]) || stateno = 210
ステート番号1000から1010の間のステートにいる場合、または、ステート番号210にいる場合
stateno != [3050,3100]
ステート番号3000から3100の間のステートにいる場合、以外
movecontact
攻撃が相手に接触(ガード&ヒット問わず)した場合

 補足
ステート番号1000~1010に該当するのは、「カンフー突き手」の弱と強のみ
ステート番号210に該当するのは、「立ち強パンチ」のみ
ステート番号3000~3050に該当するのは、「三烈カンフー突き手」と「スマッシュカンフーアッパー」のみ
「&&」はand。ようするに「~と」、「~で、~の場合」
「||」はor。ようするに「~か」「~、または、~の場合」
「(**&&**)」は括弧。括った範囲のみで答えが処理される
「[*,*]」は「~から~、までの範囲」 ※[~以上,~以下]
「!」は「~以外」付ける位置によって、エラーが出るので注意
「>」や[<]不等号。「~未満(同数は含まない)」または「~超える(同数は含まない)」
「=」イコール。一致した場合。「>=」や「>」などと、適時使い分けること
「<=」や「>=」不等号Ⅱ。「以下~(同数も含む)」または「~以上(同数も含む)」

  纏め
triggerall
var(59)が1で、戦闘中で、パワーゲージが1000(一本)以上あり、
自分が空中以外にいて、相手がダウン中以外の状態で、さらにある程度近くにいる場合

 trigger1
triggerallの条件に加えて、行動可能で、さらに乱数が指定した数値の範囲内の場合のみ
valueのステートにジャンプ(移動)する(ようするに技が発動する)

 trigger2
triggerallの条件に加えて、カンフー突き手(弱&強)、もしくは立ち強パンチが、相手に接触した場合で
自分が「スマッシュカンフーアッパー」を出していない時に、
現在の行動を中断して、valueのステートにジャンプする(ようするに特定の行動をキャンセルして、技が発動する)


気づいたと思うが、実は、

trigger2 = stateno != [3000,3050]

は、元の条件の

trigger2 = hitdefattr = SC, NA, SA, HA

だと「スマッシュカンフーアッパー」や「三烈カンフー突き手」も条件に含まれるために、それを除外するために記述されたtriggerである

故に、元の条件から、

trigger2 = (stateno = [1000,1010]) || stateno = 210

に変えた時点で不要となってる
ようするに削除しても問題ないのだ(しなくても不具合は無い)

また、ステートの1000、1010、210は、全て、

trigger2 = hitdefattr = SC, NA, SA, HA

に含まれてるため「元の技の条件から外れないこと」と言う、前提条件は崩れていない


 <注意点>
triggerallの記述は全てに適用される
ゆえに、ゲージ消費や繰り出せる姿勢などは、ここに記述される場合が多い
また、ctrlをここに記述するとキャンセル出来なくなる
(state実行中は、殆どの場合、ctrlが0。ようするにコントロール不能状態のため)

!や><を記述する位置は、=の左側
「!=」や「>=」などと記述。逆だとエラーになりやすい(例外あり)

「[*,*]」を用いた場合、その後に何か記述するとエラーになる。ただし「()」で括れば大丈夫
また、【】は「=」とのみ併用する事(ただし、「!=」は、おk)

trigger1 = stateno = [1000,1010] || stateno = 210

だとエラー

trigger1 = (stateno = [1000,1010]) || stateno = 210


trigger1 = stateno = 210 || stateno = [1000,1010]

だと大丈夫

また、
trigger2は、乱数を入れてないため、条件を満たしたら100%発動する
これが強すぎると判断するなら


trigger2 = (stateno = [1000,1010]) || stateno = 210
trigger2 = stateno != [3050,3100]
trigger2 = movecontact && random <=400

に書き換えたり

trigger2 = (stateno = [1000,1010]) || stateno = 210
trigger2 = stateno != [3050,3100]
trigger2 = movecontact
trigger2 = random <= 400

などと、追記すれば良い



例文、その2

Before

;立ち強パンチ
[State -1, Stand Strong Punch]
type = ChangeState
value = 210
triggerall = command = "y"
triggerall = command != "holddown"
trigger1 = statetype = S
trigger1 = ctrl
trigger2 = (stateno = 200) && time > 5 ; 「 && 」は両方が同時に成立( and )する時の意味です
trigger3 = (stateno = 230) && time > 6


after

;判定は並。リーチは短め。出は速め
;立ち強パンチ
[State -1, Stand Strong Punch]
type = ChangeState
value = 210
triggerall = var(59) = 1 && RoundState = 2
triggerall = statetype != A
triggerall = p2bodydist X <=30
trigger1 = ctrl && p2movetype != A && (p2statetype = S || p2statetype = A)
trigger2 = (stateno = 200) && time > 5
trigger3 = (stateno = 230) && time > 6


上記の場合。KFMが地上に居て、行動可能なときに、相手が近くで立ってるか、浮いてる時に、強パンチを繰り出す
または、同条件で立ち弱パンチ、または立ち弱キックを出してたら、それをキャンセルして、強パンチを繰り出す

 <内訳>

 triggerall
var(59) = 1 && RoundState =2
AI発動スイッチ。ようするにvar(59)の中が「1」の時で、戦闘中の場合
statetype != A
自分の状態が空中以外。Sから変更した理由は、そのままだと屈み状態では反応しないため
(ただし、屈み状態から、立ち状態に移行するのに、異様に時間がかかるキャラなら、Sのままにすること)
p2bodydist X <=30
相手と自分の距離が(ぶつかり判定の位置から)30pixel以内の場合
<=で指定してるので、飛び越されたりして、後ろに回られても、振り向くまでは、条件は満たされるので注意

 trigger1
ctrl && p2movetype != A && (p2statetype = S || p2statetype = A)
キーコントロール可能な状態(自由行動可能な状態)で、相手が立ち、または屈み状態の場合

 trigger2
(stateno = 200) && time > 5
ステート番号200にいる状態で、5フレームを超えて経過してる場合

 trigger3
(stateno = 230) && time > 6
ステート番号230にいる状態で、6フレームを超えて経過してる場合

 補足
stateno200に該当するのは、立ち弱パンチのみ
stateno230に該当するのは、立ち弱キックのみ

(p2statetype = S || p2statetype = A)とstatetype != A は似て非なる条件
(後者は「L」。即ちダウン状態も含むため)
ただし、ctrlなどと併記してる場合、ダウン中はctrl=0なので成立しないため、実質、前者と同じ扱いとなる
また、statenoと併用する場合も、該当するstatenoに、自分の状態が指定されているなら、実質前者と同じ扱いとなる

 纏め

triggerall
AIが発動していて、戦闘中で、自分が地上にいて、敵が近くに居た場合

 trigger1
triggerallの条件に加えて、自分が行動可能で、さらに敵が攻撃状態以外で、立ち、または空中にいる場合

 trigger2
triggerallの条件に加えて、立ち弱パンチのモーション中で、モーションに入ってから4フレーム以上経過してる場合

 trigger3
triggerallの条件に加えて、立ち弱キックのモーション中で、モーションに入ってから5フレーム以上経過してる場合

この場合、trigger2と3には、敵の状態やヒットの有無が条件に含まれてないため、
このままだと、弱パンチ&キックの最中に、敵が近くに居たら、敵がダウンしていても立ち強パンチを繰り出す
さらに、randomなどの、乱数を条件に入れて無いので、100%発動する
また、trigger1も、同様に乱数を入れてないため、100%発動する

このままでも、大きな問題は無いが、これだとパターン化しやすいので、

;判定は並。リーチは短め。出は速め
;立ち強パンチ
[State -1, Stand Strong Punch]
type = ChangeState
value = 210
triggerall = var(59) = 1 && RoundState = 2
triggerall = statetype != A
triggerall = p2bodydist X <=30 && random <=700
trigger1 = ctrl && p2movetype != A && (p2statetype = S || p2statetype = A)
trigger2 = (stateno = 200) && time > 5
trigger3 = (stateno = 230) && time > 6

または、

;判定は並。リーチは短め。出は速め
;立ち強パンチ
[State -1, Stand Strong Punch]
type = ChangeState
value = 210
triggerall = var(59) = 1 && RoundState = 2
triggerall = statetype != A
triggerall = p2bodydist X <=30
trigger1 = ctrl && random <=400 && p2movetype != A && (p2statetype = S || p2statetype = A)
trigger2 = (stateno = 200) && time > 5 && random <=700
trigger3 = (stateno = 230) && time > 6 && random <=300

として、発動率を調整すると良い
特に後者の場合、trigger毎に発動率を微調整できるので、コンボのパターン化けを避けることも出来る

さらに発展系として、

;判定は並。リーチは短め。出は速め
;立ち強パンチ
[State -1, Stand Strong Punch]
type = ChangeState
value = 210
triggerall = var(59) = 1 && RoundState = 2
triggerall = statetype != A
triggerall = p2bodydist X <=30
trigger1 = ctrl && random <=400 && p2movetype != A && (p2statetype = S || p2statetype = A)
trigger2 = (stateno = 200) && time > 5 && random <=700 && MoveHit
trigger3 = (stateno = 200) && time > 5 && random <=200 && !MoveHit
trigger4 = (stateno = 230) && time > 6 && random <=300

として、立ち弱パンチ攻撃が、ヒットした時は高確率で、逆に外した時やガードされた時は低確率で、
立ち強パンチに繋ぐようにする事も出来る

 <注意点>
(stateno = 200)など の「()」は、(stateno = [**,**])からコピペした時の名残と思われる
だから、外しても問題ない(外さなくても問題ない)
tmeの単位は、フレーム。ステートが変わる度にリセットされ0に戻る
MoveHitは、攻撃がヒットした場合を意味する
逆に!MoveHitは、攻撃が当たらなかった場合を意味する(結果的に、外れたり、ガードされたりなどした場合となる)
MoveHitを使うなら、timeは本来不要だが、元の技のキャンセル条件に含まれてるため、削除せず、そのまま使用すること
(削除すると、技の性能の改変となるため)



最後に動作チェックして、問題がなければ、完成 \(^o^)/

 <注意点>
動作チェックの時は、var(59)は常に1になるようにしておく

[State -1, ai]
type = varset
triggerall = 1;var(59) = 0
trigger1 = Command = "AI0"
trigger2 = Command = "AI1"
    ~中略~
trigger50 = Command = "AI49"
trigger51 = Command = "AI50"
var(59) = 1

など。triggerの「1」は、無条件に条件を満たしてる状態を表す
さらに、関係に無いcommandがでないように、確認したい技以外を、一時的に封印しておくのも良い


triggerall = var(59) = 1 && RoundState = 2


triggerall = var(59) = 0 && RoundState = 2

にすれば、AI起動時に使わなく(使えなく)なる


<前へ 4:AIトリガーの設定 次へ>