目次
はじめに
内部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目としています。)
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目としています。
また、線が細かく揺れているのは実験による値がばらつくためです。)
ラベル数登録数1で1~350F間のラベルが無条件に真になる確率
このグラフよりDifficulty=8の方が確率が高い事がわかります。
また約250F目までは確率が上昇していますが、それ以降はあまり変わらないことも分かりました。
この確率が変わらないことを確認するために3001Fから計測し、同様に確率を計算した結果が下のグラフです。
ラベル数登録数1で3001~3350F間のラベルが無条件に真になる確率
1-350Fのグラフと比べると、250Fから350Fとあまり変わっていません。
この時のそれぞれ確率はDifficulty=1で約0.00311、Difficulty=8で約0.008307と約2.7倍になっています。
次にDifficulty=8とし、登録しているラベル数を2,5,20,126とし、いずれかのラベルが真になる場合も調べました。
ラベル数登録数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はラベル自体を無条件に真する動作と人操作のようなキー入力の動作をする。
- 共にRoundState=2になった瞬間から動作するが、しばらく(約150~250F目まで)はあまり動作しない
- ラベルを真にする動作は1F毎にいずれかのラベルを働く。
- この確率はDifficultyの設定で変わる。
- キー入力は相手との距離に応じて確率が変わる。
- a,b,c,x,y,zキーはDifficultyの設定で入力される確率が変わる。
- 方向キーは距離が遠いほど頻度が高く、a,b,c,x,y,zキーは距離が近いほど、総合も距離が近いほど、確率が高い
- キー入力の頻度の方がラベルを無条件に真にする頻度より高い。
- KeyCtrl=1のヘルパーでのラベルは人操作の入力なら本体と同様に真になるが、内部AIのキー入力ならコマンドに/を含むラベルのみ本体と同様の真偽になる(コマンドに/を含まないラベルは真になることがない)。
- ラベルを無条件に真にする効果で真になるラベルは本体と同期している。
- 本体がMoveType=HかつHitFall=1の時、a,b,x,y,UBキーはDifficultyに関わらずキー入力される頻度が著しく高まる。
- 人操作と異なり、タッグではパートナーと動作が独立している。
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の略です。)
グラフ:ラベル数登録数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になっています。