目次

はじめに
内部AIの仕様 AIフラグ

はじめに

このページではまずMUGEN内部AIの動作を説明し、それを応用してAIフラグに関して説明や改善などについて書いています。
間違いや抜けているものなどを発見された場合は画面右上のCONTACTからお知らせください。
このページで書いてあるラベルとは[Command]のnameの種類のことです。
またカタカナのコマンドは[Command]のcommandのことです。
nameが同じ[Command]は例えコマンドが違っていても同じラベルとして扱われます。
このラベルの数なのですが、126までは大丈夫なのですが、127以上あるとエラーメッセージを表示し落ちます。
この時のエラメにOnly 128 unique commands labels allowed. と表示されているのでこのページではラベルと書いています。
(ちなみに実際は126までなのに何故か128までと表示されています。)

内部AIの仕様

内部AIの動作し始めるタイミング

いずれかのラベルが真になると変数が増加するようにしたところ、
ラベルが真になるタイミングから、内部AIはRoundState=2になった瞬間から動作し始めていることが分かりました。
また以降説明する内部AIの2つの動作の両方で確認できました。
ちなみに、ライフバーのCtrl.Timeは無関係でした。

ラベルを無条件に真にする

まず内部AIの動作その1です。
[Command]
name = "F"
command = F
time = 1
[Command]
name = "FAI"
command = F
time = 1
として、
trigger1 = command = "F" && command != "FAI"
というtrigger1は人操作なら command="F"もcommand="FAI"も共に真であるため満たせません。
しかし、内部AIはこのtrigger1を満たすことがあります。
このことから内部AIはラベルを無条件に真にすることができる、ということが分かります。
(これが人操作では不可能なコマンドを持つラベルを真にできる理由です。)

キー入力

内部AIの動作その2です。
内部AIは、sキー以外のキーで、例えば上記の[Command]で
trigger1 = command = "F" && command = "F"
とするとtrigger1は真にできます。
[Command]を3つ以上にしても同じようにtrigger1は真になります。
つまり、内部AI人操作と同様にキー入力も行っており、その際にコマンドを満たしたラベルは全て真になります。

しかし、sキーの場合のみ上記のような[Command]をsキーで作り、
trigger1 = command = "s" && command = "sAI"
としても、このtrigger1は500,000,000F経過しても真になりませんでした。
つまり、内部AIはsキーのみキー入力を行いません。
また、ラベルを真にする効果は1Fに最大でも1ラベルにしか働かないということも分かります。

キー入力の頻度

まずコマンドが同じでラベルが異なるコマンドを2つ登録した状態で、
各ラウンド毎に内部AIが両方のラベルを真にするまでのフレームを40000ラウンド計測しました。
この結果の「各フレームにおける真になったラウンド数」は早いフレームほど機会が多いため、
後のフレームほどラウンド数が少なくなりやすいので頻度を考えるには適していません。
そこで各フレームで真になる確率を計算しました。
この確率はあるフレームで真になったラウンド数をx、そのフレームまでに真になったラウンド数をyとすると、
x/(40000-y)で求めました。
このためyが大きくなるほど、つまりフレームが経過するほど誤差が大きくなるため、
以下のグラフでは300F間に限定して載せています。
(内部AIが起動するのはRoundState=2になったフレームからなので、このフレームを1F目としています。)
KeyInput.png(9964 byte)

1~300F間の各キー入力が行われる確率

補足としてまずa,b,c,x,y,zキーは等確率であり、オプション設定のDifficultyの影響を受けるため省略しています。
Difficulty=8の場合はおおよそB,Uより少し上に、
Difficulty=1の場合はおおよそD,UFと同じぐらいになりました。
またsキーは上で述べたようにキー入力が行われません。
グラフから分かることとしては、Fキーの入力が圧倒的に多く、確率が約0.035に達するまで上昇するということです。
次にB,Uキーが約0.01まで、少し下がってD,UFキーが約0.07まで、最後にUB,DF,DBキーが0.002弱まで上昇しています。

上記の計測は試合開始時の距離(座標では140ほど)で行いましたが、距離に応じても入力頻度が変わるようです。
そこで距離を3種類に分けた状態で、各キーの入力頻度を計測しました。
なおDifficultyは8、計測期間は約10,000,000Fです。
また、sキーは全く反応しなかったので表から省いています。

まず、入力される回数を計測しました。[Command]の例は
[command]
name = "a"
command = a
time = 0
で、条件は、
trigger1 = command="a" && command="aAI" && command="aai"
で計測しました。
結果は下表のようになりました。
回数 F B U D UF UB DF DB 方向
密着 190747 90488 57904 66331 44687 15044 15335 14923 495459
中間 363724 114416 100508 92117 65386 18143 17599 18147 790040
遠距離 356485 118028 104960 96477 63622 18336 17917 18537 794362
回数 a b c x y z 6キー 全合計 キー数/1F
密着 254372 254367 254895 254108 254006 254189 1525937 3547333 0.35
中間 59781 60053 59319 59413 59869 59773 358208 1506456 0.15
遠距離 39752 39848 39586 39862 39963 40059 239070 1272502 0.12
近距離では6キーが押される回数が高く、方向キーは少なくなっていました。
逆に近距離以外では方向キーの回数が高く、6キーが少なくなっていました。
また、方向キーは方向毎に大きく回数が変わっており、前>>後ろ>上下>斜め前上>残り斜め3方向となっていました。

次に各キーが入力されている時間を計測しました。[Command]の例は
[command]
name = "a"
command = a
time = 0
[command]
name = "/a"
command = /a
time = 0
で、条件は、
trigger1 = command="a" && command="aAI" && command="aai"
trigger2 = command="/a" && command="/aAI" && command="/aai"
として計測し、同時に
trigger1 = command="/a" && command="/aAI" && command="/aai"
も計測しました。
押し+持続のみ
F B U D UF UB DF DB 方向
密着 845816 93978 260819 378718 376655 15778 127707 15854 2115325
中間 3773647 115337 500687 617947 1284997 18347 324625 18368 6653955
遠距離 4111579 119017 537774 668840 1445849 18805 378622 18550 7299036
a b c x y z 6キー 全合計
密着 4961289 4965982 4968837 4970724 4964548 4970459 29801839 61719003
中間 4932627 4969627 4924402 4963896 4952893 4929393 29672838 65999631
遠距離 4965792 4906182 4920390 4933673 4921911 4934762 29582710 66464456
持続のみ
F B U D UF UB DF DB 方向
密着 845816 62817 235868 362796 376655 15778 127707 15854 2043291
中間 3773647 73046 455129 602395 1284997 18347 324625 18368 6550554
遠距離 4111579 74099 489284 653091 1445849 18805 378622 18550 7189879
a b c x y z 6キー 全合計
密着 4928535 4932966 4936030 4937531 4930937 4937367 29603366 61250023
中間 4927987 4965119 4919824 4959303 4948273 4924943 29645449 65841452
遠距離 4962919 4903203 4917510 4930831 4919050 4931936 29565449 66320777
6キーは距離によらず(回数によらず)ほぼ同じ時間押されているのに対して、方向キーは回数が増えると時間も長くなっていました。
また、前方向の3つは他の方向より時間が長く、距離が開くとさらに長くなっていました。

上のデータの差をとりました。
(ちなみに、この差はこするように押せば手動でも再現できました。)
この差から/の[Command]が真になるには1Fかかると推測したので、ここではこの差のことを「0F押し」によるものと考えています。(0F押しはここでの呼び方です。)
F B U D UF UB DF DB 方向
持続 0 31161 24951 15922 0 0 0 0 72034
密着 0 42291 45558 15552 0 0 0 0 103401
中間 0 44918 48490 15749 0 0 0 0 109157
a b c x y z 6キー 全合計
持続 32754 33016 32807 33193 33611 33092 198473 468980
密着 4640 4508 4578 4593 4620 4450 27389 158179
中間 2873 2979 2880 2842 2861 2826 17261 143679
0F押しの発生回数は押された回数に比例しているようでしたが、方向キーの前と斜め方向では一切見られませんでした。

回数と時間の表から1回あたりの押されている時間の平均をとりました。
1回あたりの時間
F B U D UF UB DF DB 方向
持続 4.4342 1.0385 4.5043 5.7095 8.4287 1.0487 8.3278 1.0623 4.2694
密着 10.3750 1.0080 4.9815 6.7082 19.6524 1.0112 18.4456 1.0121 8.4223
中間 11.5336 1.0083 5.1236 6.9326 22.7256 1.0255 21.1319 1.0007 9.1885
a b c x y z 6キー 全合計
持続 19.5040 19.5229 19.4936 19.5614 19.5450 19.5541 19.5301 17.3987
密着 82.5116 82.7540 83.0155 83.5489 82.7288 82.4685 82.8368 43.8111
中間 124.9192 123.1224 124.2962 123.7688 123.1616 123.1873 123.7407 52.2313
全体的に方向キーの方が短く、また後ろ方向の3方向は押されている時間が特に短くなっており、斜め前の2方向が長くなっていました。

ラベルを無条件に真にする継続時間

コマンドが"s"の[Command]1つが真になった時のgametimeを記録しました。
Difficulty = 1の場合
369 521 1752 2390 2773 3705 4086 4244 4494 4596
5598 5747 6625 6801 7146 7230 7296 7392 7417 8341
8704 9013 9034 10397 10544 11076 11189 11324 11428 11913
12307 12319 12326 12378 12388 13096 13507 13705 14049 14539
15451 15737 15831 16048 16600 17219 17448 18052 18090 18457
18859 19382 19665 19771 20893 21076 21265 21286 21411 21580

Difficulty = 8の場合
0325 0783 0848 1030 1118 1185 1222 1230 1352 1363
1403 1454 1533 1766 1873 1991 2056 2457 2464 2504
2562 2596 2617 2620 3063 3065 3214 3276 3440 3739
3790 3921 3975 4057 4165 4361 4768 4983 5081 5158
5170 5217 5510 5616 5696 5988 6074 6357 6527 6567
6646 6746 6826 6910 7128 7302 7395 7428 7510 7511
この表よりDifficulty = 8の最後以外は1F以上差が開いているため基本的に効果は1Fであり、
最後のものはたまたま1F後に次の効果が働いたと考えました。
(何度か試しましたが、持続しているような値が確認できたのはこの1回のみでした。)

また、このDifficulty = 8の表から2596Fから2620Fまでの24F間に3度の入力が確認できたので、
ラベルを真にする頻度は一定F間に1回働くのではなく、1Fに一定確率で働くようです。

ラベルを無条件に真にする頻度

まずコマンドがsのラベル1つのみを登録した状態で、
各ラウンド毎に内部AIが最初にこのラベルを無条件に真にするまでのフレームを40000ラウンド計測しました。
この結果の「各フレームにおける真になったラウンド数」は早いフレームほど機会が多いため、
後のフレームほどラウンド数が少なくなりやすいので頻度を考えるには適していません。
そこで各フレームで真になる確率を計算しました。
この確率はあるフレームで真になったラウンド数をx、そのフレームまでに真になったラウンド数をyとすると、
x/(40000-y)で求めました。
このためyが大きくなるほど、つまりフレームが経過するほど誤差が大きくなるため、
以下のグラフでは350F間に限定して載せています。
またオプションのDifficulty=8の場合とDifficulty=1の場合を載せています。
(以降のグラフで共通ですが、内部AIが起動するのはRoundState=2になったフレームからなので、このフレームを1F目としています。
また、線が細かく揺れているのは実験による値がばらつくためです。)
Label1_1-350F.png(10989 byte)

ラベル数登録数1で1~350F間のラベルが無条件に真になる確率

このグラフよりDifficulty=8の方が確率が高い事がわかります。
また約250F目までは確率が上昇していますが、それ以降はあまり変わらないことも分かりました。
この確率が変わらないことを確認するために3001Fから計測し、同様に確率を計算した結果が下のグラフです。
Label1_3001-3350F.png(10930 byte)

ラベル数登録数1で3001~3350F間のラベルが無条件に真になる確率

1-350Fのグラフと比べると、250Fから350Fとあまり変わっていません。
この時のそれぞれ確率はDifficulty=1で約0.00311、Difficulty=8で約0.008307と約2.7倍になっています。

次にDifficulty=8とし、登録しているラベル数を2,5,20,126とし、いずれかのラベルが真になる場合も調べました。
Label1-126_1-350F.png(16187 byte)

ラベル数登録数1,2,5,20,126で1~350F間のラベルが無条件に真になる確率

この図より基本的には登録されているラベル数が多いといずれかのラベルが真になる確率も高いことが分かりました。
ただし、ラベル数1とラベル数2では大きな差があるがラベル数2とラベル5、ラベル数5とラベル数20、ラベル数20とラベル数126とラベル数が多くなるほど上昇幅が小さくなっていることが分かります。
また更に計測した所、ラベル数126で250F以降での確率は約0.017であり、ラベル数が60を超えたあたりからあまり変わらないことが分かりました。

最後に、同一のラベルでコマンドが異なるCommandをもう一つ作り、ラベルは1であるがCommandは2つの状態で計測した所、上でグラフにしたラベルが1つの場合と重なったので、やはりラベル単位で無条件に真にしていることが確認できました。

ヘルパーでの内部AIによる仕様

ここまでは本体の話でしたが、ここからはヘルパーのCommand認識についてです。
KeyCtrl=1のHelperはHelperTypeに関係なくCommandを認識出来ます。
まず人操作の場合を検証しましたが、本体と全く同じを認識します。

次に内部AIの場合を検証しました。
本体の時と同様に同一commandの中で一つのラベルのみが真になったことから、
ヘルパーでもラベルを無条件に真になる効果が働いていることが分かりました。

本体と同様にcommand="s"は同時に2つ真にならないことを確認し、
本体でのラベルを真にする頻度を計測した時と同様の事をヘルパーからroot,command="s" && command="s" で試した所、
Difficulty=8で10000ラウンド中9791ラウンド、Difficulty=1で10000ラウンド中7667ラウンドと上記の結果とほぼ同じになりました。
また、root,command = "s" && command != "s"のみで試した所、真になることはありませんでした。
よって、ラベルが無条件に真になるタイミングは本体とヘルパーで全く同じのようです。

次に内部AIのキー入力に関して調べました。
同じコマンドで異なるnameの[Command]を各コマンドに3つずつ用意し、各種それぞれですべてのラベルが真になったかで調べました。
結果としては、まず本体と異なりヘルパーは内部AIのキー入力ではコマンドに/Fのように持続を表す/を使ったコマンドを持つラベルしか真になりませんでした。
通常の押した瞬間の"F"や離した瞬間の"~F"や同時押しの"F+D"や方向キーのみで使える"$F"のみのコマンドを持つラベルは真になりませんでした。
また、/さえ使っていればよく、"/~F"、">/F"、"/$F"、">/~$F+$D"と複合した場合も認識しました。
これらから内部AIはヘルパーと本体とで入力が異なる事はなく同一である事がわかりました。

2016/01/08追記:(仮称)ヘルパーキー認識バグ
イントロ中(RoundState=1)に1度でもキーを入力すると、
人操作でもRoundState=2での最初のキー入力のみ、
内部AIのキー入力と同様に持続を表す/を使ったコマンドを持つラベルしか真になりません。

後述するヘルパー単独式によるAI判定での暴発原因を探していた際に判明したため、
検証記述の根幹はヘルパー単独式の記述となっています。
  ここをクリックで検証記述を開閉します。
[Command]
name = "a"
command = a
time = 1
[Command]
name = "a2"
command = a
time = 1
[Command]
name = "/a"
command = /a
time = 1

[StateDef -1]
[State -1, AI起動用ヘルパー]
type = Helper
helpertype = Normal
name = "AI"
stateno=10000
ID=10000
pos=9999,9999
keyctrl=1
pausemovetime=2147483647
supermovetime=2147483647
trigger1 = !NumHelper(10000)
trigger1 = !var(59)

[StateDef 10000]
movetype = A;行動順を本体より早くし、1F目から判定可能に。
ctrl = 0
anim = 10000;出来れば透明かつ判定の存在しないアニメを選ぶ。

[State 10000,人操作フラグON]
type = ParentVarSet
var(59) = -1
triggerall = RoundState = 2
trigger1 = Command = "a" && Command = "a2"

[State 10000,AIフラグON]
type = ParentVarSet
var(59) = 1
triggerall = RoundState = 2
;triggerall = root,var(58)
triggerall = !root,var(59)
trigger1 = Command = "/a"

[State 10000,AIサブフラグON]
type = ParentVarSet
var(58) = 1
triggerall = RoundState = 2
trigger1 = Command = "/a"

[State 10000,本体にフラグが立ったら消去]
type = DestroySelf
triggerall = IsHelper
trigger1 = root,var(59)

検証記述ではRoundState=1でキー入力せずにRoundState=2で人操作でAキーを入力すると、
人操作フラグONステートによりvar(59)が-1になり人操作判定になることを確認できます。
しかし、RoundState=1でAキーを入力してから同様にするとvar(59)が1になります。
これは上記のバグが原因で人操作フラグONステートで人操作判定が行われず、
AIフラグONステートでAI判定されたと考えられます。

次にAIフラグONステートの;triggerall = root,var(58)のコメントアウトを解除することで、
AIサブフラグONステートが判定されてからAIフラグONステートが判定されるようになります。
この場合、RoundState=1でキー入力していてもvar(59)は-1となり人操作判定となります。

以上よりRoundState=1でキー入力を行った場合、バグが起きると推測しました。

ちなみに、特定条件下でRoundState=1でキー入力することでイントロスキップが起きますが、
このキー入力は「A,B,C,X,Y,Z」で起き、「方向、Start」では起きませんでした。
方向やStartキーでもイントロスキップは発生しませんがこのバグが起きることを確認しています。
なお、イントロスキップに関しては現在下記のことが確認されています
キーを押して飛ばした場合、イントロを無視して2へ飛ぶ。
  • イントロを飛ばせるのはHelperをもったキャラのみ?
  • イントロを飛ばした場合一度Explod,Helper,Projectileを全て消去する。
引用元:MUGEN CNS WIKI CHAOS@予定 - T-/RoundStateのLv1-記述例・補足・注意点

さらに追記
上記の検証記述のコメントアウトしたままで、RoundState=1でキーを入力せず、
RoundState=2になってからA以外のキーを入力し、Aキーを入力するとAI判定されました。
また、上記のバグと同じくコメントアウトを解除すると発生しなくなります。
このため同じ原因のバグだと考えられます。

MoveType=HかつHitFall=1の場合の内部AIの動作

MUGENのデフォルトコモンでは[Statedef 5050]においてCommand = "recovery"で復帰するようになっています。
しかし、上記の内部AIの動作頻度では実際の復帰頻度にはならないように思われます。
これは本体がMoveType=HかつHitFall=1を満たしている場合、内部AIの入力頻度が変わるためです。
まずラベル数30で、Difficulty = 8の場合にキー入力と無条件にラベルを真にする動作を分けて1,000,000F間でそれぞれのキーのラベルが何回真になったかを計測しました。
内部AIの動作 HitFall F B U D UF UB DF DB
キー入力 0(通常) 37620 34976 10191 17843 7238 622 1772 8081
1 24420 21872 6768 11418 4563 86782 1217 4550
ラベルを無条件に真にする 0(通常) 109 116 91 134 102 88 118 101
1 69 67 66 77 58 57 60 52
a b c x y z s 合計
キー入力 0(通常) 607 622 563 595 557 616 0 121903
1 86817 86815 406 86255 86254 390 0 508527
ラベルを無条件に真にする 0(通常) 105 90 101 107 99 115 119 1595
1 66 56 63 54 64 58 60 927

この表から通常時に比べHitFall=1かつMoveType=Hを満たしている場合は、
ラベルを真にする効果とUB以外の方向とc,zキーの入力頻度は減少しますが、
a,b,x,yキーの入力頻度が著しく上昇する事がわかります。
(デフォルトのKFMではCommand = "recovery"はx+yなのでこの効果により復帰しやすくなっています。)

また、この効果によりFall=1をつけたHitDefの攻撃やHitFall=1にする投げでダウンを奪った場合などでは、
HitFall=0の場合に比べて著しく起き上がりの時間が早くなっています。
(例:liedown.time=600の場合、HitFall=0で平均77Fが、HitFall=1で平均34Fほどになる。)

また、ヘルパーも入力自体は同期しているため、本体が条件を満たしている場合は、同様の傾向になります。
ただし、ヘルパーのみがMoveType=HかつHitFall=1を満たしても入力頻度の変化は起こりません。

次にDifficulty = 8からDifficulty = 1にして計測しました。
内部AIの動作 HitFall F B U D UF UB DF DB
キー入力 0(通常) 34511 21596 10888 13043 6486 291 1770 4004
1 22095 13963 7442 8465 4152 87226 1130 2264
ラベルを無条件に真にする 0(通常) 30 40 38 32 40 48 43 29
1 19 25 20 21 19 26 26 32
a b c x y z s 合計
キー入力 0(通常) 277 290 288 260 276 287 0 94267
1 87373 87368 185 86894 86887 178 0 495622
ラベルを無条件に真にする 0(通常) 35 49 45 32 28 25 34 548
1 22 25 20 18 17 20 33 343
上の表と比べると基本的には回数が下がっていますが、キー入力のa,b,x,yのみはあまり変化がないことが分かります。

最後に時間経過による頻度も調べましたが、やはり時間が経過するにつれ入力頻度は上がりました。
aキーのキー入力頻度はキー入力の頻度のFとほぼ同じになりましたので省略させてもらいます。

タッグでのAI動作

タッグで内部AIはパートナーと同一コマンドが入力されるかどうかを調べました。
まずパートナーのCommandを参照すると、異なるキャラ同士の場合正常にコマンドが参照できません。
これはパートナーで真になったラベルと同一の順番にある自分のラベルが真になるためです。
なお、これは相手のCommandを参照する場合も同じです。
よって以下では同キャラをタッグにして検証しました。
まずラベルを無条件に真にする効果を調べました。
trigger1 = (command = "a" + command = "A" = 1) + (partner,command = "a" + partner,command = "A" = 1) = X
のXを1と2でそれぞれ違う動作にすると1の場合の動作が確認できました。
次にキー入力を調べました。
trigger1 = (command = "a" && command = "A") + (partner,command = "a" &&&& partner,command = "A") = X
も同様にXを1と2でそれぞれ違う動作にすると1の場合の動作が確認できました。
X=1の場合はパートナーとコマンドが同期していないことを表し、2の場合は同期していることを表しています。
なお、人操作の場合はキー入力の場合のtrigger1で2の動作になります。

トレーニングモードでのCPUの仕様

Dummy control AIにした場合のみ内部AIが動作。
Guard mode ガード開始ステートに移動
Dummy mode 状態に応じたキー入力
Distance 距離を保つ方向にキー入力
Button jam 対応したキー入力
注:内部AIのキー入力と同様、ヘルパーで真になる[Command]は/のついたコマンドのみ

内部AIの仕様のまとめ

AIフラグ

AIフラグとは

ここではMUGEN内部AIでなくcnsにより作成したAIを動作させる際に、人かCPUかを判定するフラグをAIフラグと呼びます。
CPU操作と判断するには内部AIが動作しているかで判定します。

新MUGENではそれ用のトリガーがあるのですが、winMUGENではそのようなトリガーが無いため、ここまで上に書いてきた内部AIの動作を利用して判定しています。

まずCMD式と言われる判定方法は人操作では不可能なCommandを多数作り、それらのうち一つが真になるとCPUであると判定します。
つまりラベルが無条件に真になる機能を利用しています。
導入が簡単であるため、AIを作った経験のある方はCMD式で作成された経験があると思います。
欠点としてはラベルを真にする動作に頼るため判定速度が遅く、またオプションのDifficulty設定に速度が左右されます。

次にまだ通称が無いのでここではラベル式と呼ばせて貰う方法があります。
まず元からある[Command]をコピーし、複製したもののnameを変えて別ラベルとします。
ここでは例としてname="~"をname="~AI"としてコピーしたとします。
こうすると内部AIならラベルを真にする動作によりcommand="~"かcommand="~AI"のどちらか一方のみ真というトリガーを満たせるので、CPU操作と判定できます。
利点はCMD式で判定に使うラベルは新たに追加したラベルのみであるのに対して、
ラベル式は元から使われているラベル全てを判定に使えるためCMD式より高速です。
ただしラベルを真にする動作に頼るため、CMD式と同様の欠点を持っています。
ちなみに登録ラベル数によるラベルを無条件に真にする動作の頻度の上昇は60以上ではほぼ0なので、元のラベル数が30以上あればそれらの複製を1つずつ作るだけで上限になります。
参考:ふぁんしーむげん ヘルパーを使わないでできるだけ早くAI起動

最後にヘルパー式と言われる判定方法はKeyCtrl=1のヘルパーで本体のラベルのみ成立した場合にCPU操作と判定します。
人操作のキー入力はKeyCtrl=1のヘルパーでも[Command]が成立するのに対し、内部AIのキー入力は/のある[Command]でなければ、本体の[Command]のみ成立することを利用しています。
ヘルパー式の最大の利点は圧倒的な判定の速さです(3方式で最速)。
これはラベルを真にする機能よりキー入力の頻度の方が圧倒的に高いためです。
欠点としてはヘルパーを使うため少し難易度が上がる事と暴発しやすい事です。

以下ではヘルパー式の暴発原因を考え、改善をしています。

ヘルパー式の暴発原因

1:command.buffer.time中に召喚されたヘルパーはその[Command]を認識できない。

2:本体とヘルパーの向きが違うことで本体とヘルパーのFとBが逆向きになる。

3:command.buffer.timeを長めに設定した相手にステートを奪われ、ステートを返される前にコマンドを入力し、それが相手の[Command]で成立するなら自身のステートに戻ってもcommand.buffer.time中は同じ並び順の[Command]が成立していることになる。

リンク先に原因と対策が詳しく書かれています。
参考元:名の無限 AI暴発について
3で触れられている記事はこちらlunaの倉庫 // 敵のコマンド感知
ちなみに、コマンドの位置とは正確には[Command]での並んでいる位置ではなくラベルでの並んでいる位置です。
詳しくはこちらを参照ください。豆知識 > コマンドのリダイレクト参照
また、3に関してはヘルパー式以外でも暴発の原因となりえます。

4:HitPause中は成立したCommandが真を維持する。
(一度プレイヤー判定したらヘルパー消すようにしている場合は起きない?)
参考元:DHQの雑記とか commandとhitpause・pause・superpause
未検証:!root,hitpauseをトリガーに入れ、本体がHitPause中は判定しないことで防げないか?

5.トレーニングモードでDummy mode、Distance、Button jamを機能させる。

参考元にさせていただいた記事にもありますが、command.buffer.timeとbuffer.timeは不具合の元になりやすいので、先行入力を実装される場合は、変数を使うことをオススメします。

暴発対策としてのAIを切るスイッチ案

案という理由は検証が足りているか分からないためです。
ヘルパー式以外でも上記の3で暴発する可能性はあります。
そこで暴発した際にAIを切るスイッチを作ることを考えます。
MUGEN内部AIではsキーを入力できないため、
command="s"の[Command]を2つ用意し、その2つが真になった場合AIを切るという案です。

ヘルパー単独式

㍻㌢氏製作のAI説明書のヘルパー式AIフラグを元に暴発防止、起動速度向上を考えました。
上記の目的のためにヘルパーのみで判定を行うことが名前の由来であり、またラベル式の原理も取り入れています。
まず、ヘルパーのステートをmovetype = Aにすることで、本体より先にヘルパーが行動するので、RoundState=2の前からヘルパーを出していれば1F目から判定を行えるようになりました。
その後、ステートでは透明化、無敵化、攻撃範囲消去を行います。
そして、人操作判定ステートになります。
元のヘルパー式の人操作判定ステートでは、本体のラベルも判定に利用しているため暴発の原因となっています。
そこでヘルパーではコマンドに/を含まないラベルが内部AIのキー入力では真にならない性質を利用し、ヘルパーのみで人操作かを判定します。
ただ/を含まないラベルが1種類のままでは、ラベルを無条件に真にする内部AIの動作で真になることがあります。
そのためこれを防ぐためにそれぞれと同じコマンドで真になるラベルを用意し、両方のラベルが満たされた場合に人操作と判定するようにします。

次にAI判定ステートでは、コマンドに/を含むラベルを用意してヘルパーのみでキー入力を感知します。
人操作であれば上にあるプレイヤー判定で人操作フラグが必ず立っているので、その場合は判定しないようにします。
またラベルを真にする動作用に登録ラベルを全て条件に加えておくと起動速度が少しですが上がります。

この方式の利点はヘルパーのみで判定できるため、本体とのズレによって生じる暴発を防ぐことができます。
(暴発理由の5以外は防げると思います。)
また人操作と誤判定する事も減らせるため、もともと速いヘルパー式の判定速度を向上させられます。

なお、MoveType=HかつHitFall=1の場合のキー入力増加を利用してもあまり起動率上昇が見込めなかったため使用しておりません。

基本例

注意
[Command]例を見るのは判定ステート例を見てからのほうが良いです。
本体の変数を使いたくない場合、難易度が跳ね上がります。
原因としてはイントロスキップによってRoundState=1での本体変数以外へのフラグ保存が難しいため、
ヘルパーキー入力バグが発生した状態で人・AI判定する必要が有るためです。
下記の例ではRoundState=1でキー入力された時点で判定を行うことでこのバグも回避しています。

2015/02/10:イントロ終了時にボタンを押したままだとAIが暴発する不具合を修正しました。
修正点:本体AIフラグステート例のトリガーと代入する値、判定ステート例のAIフラグONのtriggerallです。
原因:イントロ終了によりヘルパーの変数がリセットされ、"/command"コマンド成立でAIフラグが立つ。

2015/08/30:試合開始前からボタンを押したままだとAIが暴発する不具合を修正しました。
修正点:RoundState=0,1でボタンが長押しされていると人操作フラグがたつように。
原因:試合開始前からボタンを長押しすることで、ボタン押し判定なしにボタン長押し判定になりAIフラグが立つ。
  ここをクリックで[Command]例を開閉します。
;ちなみにKFMの[Command]ならF,B,U,D,AI,/commandの6ラベルを追加することになります。
;基本コマンド[Command]
[Command]
name = "a"
command = a
time = 1
[Command]
name = "b"
command = b
time = 1
[Command]
name = "c"
command = c
time = 1
[Command]
name = "x"
command = x
time = 1
[Command]
name = "y"
command = y
time = 1
[Command]
name = "z"
command = z
time = 1
[Command]
name = "start"
command = s
time = 1
[Command]
name = "holdfwd";Required (do not remove)
command = /$F
time = 1
[Command]
name = "holdback";Required (do not remove)
command = /$B
time = 1
[Command]
name = "holdup" ;Required (do not remove)
command = /$U
time = 1
[Command]
name = "holddown";Required (do not remove)
command = /$D
time = 1

;判定用[Command]
[Command]
name = "F"
command = $F
time = 1
[Command]
name = "B"
command = $B
time = 1
[Command]
name = "U"
command = $U
time = 1
[Command]
name = "D"
command = $D
time = 1

;人操作フラグ用[Command]:ラベルは同一で問題ない。
[Command]
name = "AI"
command = a
time = 1
[Command]
name = "AI"
command = b
time = 1
[Command]
name = "AI"
command = c
time = 1
[Command]
name = "AI"
command = x
time = 1
[Command]
name = "AI"
command = y
time = 1
[Command]
name = "AI"
command = z
time = 1
[Command]
name = "AI"
command = s
time = 1
[Command]
name = "AI"
command = $F
time = 1
[Command]
name = "AI"
command = $B
time = 1
[Command]
name = "AI"
command = $U
time = 1
[Command]
name = "AI"
command = $D
time = 1

;AI判定用[Command]:ラベルは同一で問題ない。
[Command]
name = "/command"
command = /a
time = 1
[Command]
name = "/command"
command = /b
time = 1
[Command]
name = "/command"
command = /c
time = 1
[Command]
name = "/command"
command = /x
time = 1
[Command]
name = "/command"
command = /y
time = 1
[Command]
name = "/command"
command = /z
time = 1
[Command]
name = "/command"
command = /s
time = 1
[Command]
name = "/command"
command = /$F
time = 1
[Command]
name = "/command"
command = /$B
time = 1
[Command]
name = "/command"
command = /$U
time = 1
[Command]
name = "/command"
command = /$D
time = 1
  ここをクリックでヘルパー呼び出しステート例を開閉します。
[StateDef 常時監視]
[State -1, AI起動用ヘルパー]
type = Helper
helpertype = Normal
name = "AI"
stateno=10000
ID=10000
pos=9999,9999
keyctrl=1
pausemovetime=2147483647
supermovetime=2147483647
trigger1 = !NumHelper(10000)
trigger1 = !var(59)
  ここをクリックで本体AIフラグステート例を開閉します。
[state -1,本体AIフラグ]
type = VarSet
ignorehitpause = 1
trigger1 = !IsHelper
trigger1 = NumHelper(10000)
trigger1 = helper(10000),var(59)
var(59) = helper(10000),var(59)
  ここをクリックで判定ステート例を開閉します。
[StateDef 10000]
movetype = A;行動順を本体より早くし、1F目から判定可能に。
ctrl = 0
anim = 10000;出来れば透明かつ判定の存在しないアニメを選ぶ。

[State 10000,間違いで本体が来たら立ちへ移行]
type = SelfState
value = 0
trigger1 = !IsHelper

[State 10000,透明化]
type = AssertSpecial
flag = Invisible
trigger1 = 1

[State 10000,無敵化]
type = hitby
value =
value2=
trigger1 = 1

[State 10000,攻撃範囲消去]
type = AttackDist
value = 0
trigger1 = 1

[State 10000,人操作フラグON]
type = VarSet
var(59) = -1
trigger1 = Command = "a" && Command = "AI"
trigger2 = Command = "b" && Command = "AI"
trigger3 = Command = "c" && Command = "AI"
trigger4 = Command = "x" && Command = "AI"
trigger5 = Command = "y" && Command = "AI"
trigger6 = Command = "z" && Command = "AI"
trigger7 = Command = "start" && Command = "AI"
trigger8 = Command = "F" && Command = "AI"
trigger9 = Command = "B" && Command = "AI"
trigger10 = Command = "U" && Command = "AI"
trigger11 = Command = "D" && Command = "AI"
;ボタン押しっぱなしで試合を開始した時にAIが暴発するのを防ぐために、押しっぱなしのボタンがあれば人操作判定する。 ;RoundState=0はライフバーの設定によっては省略されることもある([Round]のStart.WaitTime=0時)のでRoundState=1も。 trigger12 = (RoundState = 0 || RoundState = 1) && Command = "/command"

[State 10000,AIフラグON]
type = VarSet
var(59) = 1
;人操作フラグまたはAIフラグが既に立っている場合、判定を行わない。
triggerall = !var(59) && !root,var(59)
;内部AIのキー入力を感知。
trigger1 = Command = "/command"
;これ以降は内部AIの無条件にラベルを真にする効果用に存在するラベル全てを条件としていきます。
trigger2 = Command = "AI" || Command = "F" || Command = "B" || Command = "U" || Command = "D"
trigger3 = Command = "a" || Command = "b" || Command = "c" || Command = "x" || Command = "y" || Command = "z" || Command = "start"
;ラベル登録数が60以下の時は適当なnameでラベルを増設したほうが良いでしょう。

[State 10000,本体にフラグが立ったら消去]
type = DestroySelf
triggerall = IsHelper
trigger1 = root,var(59)
;ヘルパー消去は必要に応じて
Q&A
Q.もしコマンドに/を含んだ人では入力不可能なコマンドを作るとAI起動速度が変わるか?
A.コマンドに/を含むと内部AIのキー入力をヘルパーでも感知できるが、内部AIのキー入力では人力不可能なコマンドは入力できない。 そのため単に人では入力不可能なコマンドを作る場合と変わらないので、この方式では単にコマンドを増やした際に少し起動速度が上がるのと変わらない。

各AIフラグ式の起動率

各AIフラグ方式でRoundState=2の何F目でAIフラグがオンになるかをそれぞれ40000ラウンド計測しました。
この結果から各フレームまでにAIがオンになっている確率を計算しグラフに纏めました。
(D1はDifficulty=1、D8はDifficulty=8の略です。)
AI_Flag.png(8861 byte)

グラフ:ラベル数登録数60以上でRoundState=2から500F後までに各AIフラグ方式でオンになる確率
なお、ライフバーのCtrl.Timeの設定は30~130を確認しています。(デフォルトは30)

この図からヘルパー単独式 > ヘルパー式 > ラベル式 > CMD式 になっていることが分かります。
ヘルパー単独式のDifficulty=8とDifficulty=1はDifficulty=8がわずかに上でした。
ヘルパー式のみDifficulty=8のほうがDifficulty=1より低い結果になっているのは、ラベルを無条件にする動作により人操作と誤判定される率が高くなっているためです。
人操作と誤判定したラウンド数はDifficulty=1で905ラウンド(2.26%)、Difficulty=8で1824ラウンド(4.56%)でした。
ヘルパー単独式ではこの誤判定は無かったため、途中から確率が1になっています。
ページのトップへ戻る
inserted by FC2 system