XD瞬きの難しさを言語化しておきたい
ベースの処理はCoと同じ
「前の瞬きから何フレーム経過したか」を記録しておくカウンタを持っている
カウンタの値に応じて閾値が決まり(60Fまでは単調増加、その後は定数)、毎フレーム判定を行い、180F経過すると強制的に瞬きする
単位は60fps換算。30fpsの場合は1回の描画ごとにカウンタが+2される
Coと異なるのは以下の点
Coはステータス画面では30fpsだったが、XDは60fps
前回の描画処理からの経過時間を高精度で取得でき、1/60秒に満たない場合はカウンタが加算されずに判定が行われる(以下、停滞と呼ぶ)
特に厄介なのが後者で、以下の2パターンのアクシデントが生じる。
閾値が増加する最初の60F間で停滞が生じ、なおかつ加算される差分が乱数値を跨ぐ場合、起きるはずだった瞬きが発生することなく判定が継続する。
瞬きが発生せず180F経過してしまった場合、なおかつその最中に停滞が生じていた場合、実際には180Fよりも遅れて瞬きが発生することになる。
これは180F経過してしまった場合は非常に高い確率で発生する。
じつはCoでも60fpsで瞬きを観測すると同じ現象が起きるのかもしれない。
ボックス画面でポケモンの数が少ない時とか、スナッチリストとかから瞬きを観測すれば60fpsで観測できるよ。
検索するときはどうするか?
パターン1は非常に低確率でしか発生しないため(ちゃんと計算はしておいたほうが良いけど)、起こらないものとして無視してしまって良いと思う。と書いていたが、実際に計算してみると案外頻繁に発生していたので、無視はできないと思う…。
パターン2が観測された区間内に含まれる場合は、クエリ自体を棄却するか、一定の誤差を認めて検索を行うかになる。
ここの誤差は瞬き発生後の系列にも影響を及ぼすため、計算量は膨れ上がる。
パターン2の亜種で、「前の瞬きから180F以上経過している状態で満期が発生する前にrand < 0.1を満たすseedに当たってしまい、非満期な瞬きが発生する」がある
本来満期の瞬きが発生していれば発生していなかったはずのseedにおいて瞬きが発生することになる。
上記の議論はカウンタの停滞がごくまれにしか起こらない前提で書いていた。しかし、エミュレータで停滞の発生回数を調査する方法を見つけたので、実際に調査してみたところ、結構な頻度で発生していることがわかってしまった。
調査方法は以下の通り
ゴクリンをマルノームに進化させた画面でステートセーブ
瞬きが発生したときに通るアドレスにブレイクポイントを仕掛けておき、止まった時点での瞬きカウンタの値を記録する
以下、調査記録
250730Fスタートで250764Fに瞬きが発生した(この間34F)。
スタート時点での瞬きカウンタは90。停滞が発生しなければ瞬き発生時点でカウンタは124になる。
観測結果10回分のカウンタの値は以下の通り。
table:result
カウンタ 停滞回数
121 3
118 6
115 9
118 6
116 8
119 5
121 3
117 7
122 2
121 3
34Fの間に最小でも2回、最大で9回、平均5.2回の停滞が発生している。
約6.5Fに1回停滞が生じる計算になる…
しかもブレが大きい…
瞬きからseed特定をする実験を行っている最中に、210F前後の瞬き間隔を観測することが頻繁にあったが、これも180Fに上記の頻度で停滞が起きた場合の実経過時間とおおよそ一致する。
以上から、seed特定後の瞬きの系列を愚直にエミュレートするのは、不確定要素が多すぎて無理無理の無理。
ただ、瞬きを行っているオブジェクトは1体だけであり、消費速度は瞬き後のクールタイムを除いて常に1であるため、「瞬きが発生するたびに一定の残り時間を加算するタイマー」を使えば、エミュレート無しにそこそこの精度を出せるものと思われる。
クールタイム自体も停滞によって伸びる可能性があるため、依然不確定要素はあるが…。
また、seed特定も上記の事情を鑑みてある程度大雑把に行える必要がある
Co向けに実装してあった厳密なアルゴリズムは恐らく使えない。