FlexのTimerクラスを使って、ストップウォッチっぽいものをつくっていたけど、このTimerクラスの精度が渋い。

http://www.bit-101.com/blog/?p=910でもガイジンさんが言及しているけど、自分の環境でも1分に3,4秒の狂いが平気で出る。

これは、TimerクラスがTIMERイベントのHandler実行中に、停止してしまう(次のカウントを開始しない)ために起こる。

ので、クラスリファレンスからして

たとえば、SWF ファイルを 10 fps (1 秒あたりのフレーム数)、つまり100 ミリ秒間隔で実行するように設定し、80 ミリ秒でイベントを発生するようにタイマーを設定すると、Flash Player ではおよそ 100 ミリ秒間隔でイベントが実行されます。

と書いてある。

Timerクラスは便利なのですが、実時間と連動するのが必要なタスクには向かないようです。

解決策としては2つが考えられそう。

  • リファレンスに素直に従い、Timer(80)なり、適切なミリ秒を設定する。Timerの動作は、Handlerの動作の間“待ってしまう”ため狂いが大きくなる。そのため、Handlerの動作時間を見越してdelayを与えてやればいい。
  • Timerクラスの使用は諦めて、Event.ENTER_FRAMEを拾う。

上のガイジンさんもお勧めの方法。具体的にはこんな感じ。

addEventListener(Event.ENTER_FRAME, enterFrameHandler);

private function enterFrameHandler(event:Event):void
{
trace("hoge");
}

ただし、Event.ENTER_FRAMEは時間を一切考慮せず、「Flashのフレームの進捗にあわせて」発行されるため、
コンピュータの動作速度等に依存する部分が大きくなる。
また、FlexデフォルトのFPSは24であるため、場合によってはFPSを設定する作業も必要かもしれません。


FPSを変更するためには以下。
stage.frameRate = 60;で、fps=60になるはず。(ただし、表示オブジェクト追加後に呼び出さないとstageからnullが返る。
ので、例えばのcreationCompleteに対応して呼び出すのは不可。applicationCompleteあたりに対応するとうまくいく。リファレンス参照。)


今回くらいだと大して困らないけど、Flexでゲームを本格的に作ろうと思った場合、結構問題になってくると思ってメモ。