• ベストアンサー

TimerEventで処理が重く時間がズレる時

AS3です。 クイズ問題を作っているのですが 制限時間のタイマーをセットしています。 クイズ全体の制限時間を Timerイベントで管理しているのですが、 クイズの中でクリックする場面も多く、 このようなクリック処理が入ると Timerイベントが遅くなってしまいます。 たとえば制限時間を30分に設定していても 回答者がクリックする頻度によっては 処理が遅れ、実質32分とか33分とかになってしまいます。 そもそも、制限時間を作るときは どのようにつくるとうまくいくものなのでしょうか。。 ご存知の方いらっしゃいましたら、 何卒ご教授のほど、よろしくお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
  • BlurFiltan
  • ベストアンサー率91% (1611/1754)
回答No.1

Timerクラス や setInterval や setTimeout や ENTER_FRAME は, 「だいたい○秒間隔で△を実行する」 というような感じで 何かのイベントをだいたいの時間で定期的に行うものであって, そもそも時間を測るものではありません。 本業は "時間計測" ではなく "イベント実行" です。 時間の間隔を測るのでしたら普通は getTimer を使います。 数時間とか数日間とかすごく長い時間間隔を測る場合は Date の getTime を使う方が正確です。 (実際にはそんなに長時間同じSWFを表示させ続けることはないと思いますが。) ENTER_FRAME で getTimer や Date.getTime を実行しさせて時間を取得します。 上にも書きましたが, ENTER_FRAME 自体はすごくイイカゲンですよ。 でも ENTER_FRAME はイイカゲンでも良いのです。 実行間隔はイイカゲンでも,その実行時の正確な時間を取得出来れば良いのですから。 ※仮にフレームレートを 30fps に設定していたとして   処理が重くなって 10fps になったとしても   それは実行間隔が間延びするというだけの話で   それと実際の時間とは全く関係がないのですから   正確な時間さえ取得できれば   相対誤差は1秒未満で納まるでしょう?   という意味です。 ※パソコンの時計でも1秒の刻み(表示間隔)は   すごくゆらいでいてイイカゲンです。   1秒の刻み(表示間隔)はイイカゲンでも   そのときに取得する時刻が正確であれば   時計として使えます(現に使っています)。 AS3の新規ドキュメントを作成して メインのタイムラインのフレーム1に書くスクリプト例です↓。 //==================================== //---以下動作検証のための下ごしらえ----- var my_txt:TextField = new TextField(); my_txt.x = my_txt.y = 10; my_txt.width = 100; my_txt.height = 20; my_txt.background = true; my_txt.border = true; my_txt.text = "スタート"; // var my_fmt:TextFormat = new TextFormat(); my_fmt.align = TextFormatAlign.RIGHT; my_fmt.font = "_等幅"; my_txt.setTextFormat(my_fmt); // addChild(my_txt); //---以上動作検証のための下ごしらえ----- //クリック時の時間を代入する変数を宣言 var old_time:Number; //my_txtプレス時に関数startTimerを実行 my_txt.addEventListener(MouseEvent.MOUSE_DOWN,startTimer); //関数startTimerを定義 function startTimer(e:MouseEvent):void { //クリック時の時間を保存 old_time = getTimer(); //毎フレーム時間ごとに関数getTimeを実行 this.addEventListener(Event.ENTER_FRAME,getTime); } //関数getTimeの定義 function getTime(e:Event):void { //今現在の時間を取得 var new_time:Number = getTimer(); //クリック時~今現在の経過時間を取得 var past_time:Number = new_time - old_time; //経過分数の取得 var past_min:Number = Math.floor(past_time/(60*1000)); //経過秒数の取得 var past_sec:Number = Math.floor((past_time- past_min*(60*1000))/1000); //経過百分の1秒数の取得 var past_csec:String = (("0" + new_time).substr(-3,3)).substr(0,2); // ~分○○秒○○ の表示 my_txt.text = past_min + "分" + ("0" + past_sec).substr(-2,2) + "秒" + past_csec; } //==================================== SWFを表示させて [ スタート] をクリック(プレス)してもらうとタイマーがスタートします。 家の時計などで正確さを調べてみてください。 私の環境だと, 色々他の作業をしながら30分間測ってみて 誤差は1秒以内でした(小さすぎて正確な誤差がわからない。) 数時間以上計測するとおそらく数秒ほど誤差が出てくると思います(かなり昔に実験したことがあるだけで,今のFlashPlayerでも出るかどうかはわかりませんが)。 もし誤差が出てその誤差も取りたい場合は スクリプト中の //クリック時の時間を保存 old_time = getTimer(); や //今現在の時間を取得 var new_time:Number = getTimer(); の部分を //クリック時の時刻を保存 var old_date:Date = new Date() old_time = old_date.getTime(); や //今現在の時刻を取得 var new_date:Date = new Date() var new_time:Number = new_date.getTime(); に変えてもらうと, 長時間でも正確なタイマーになります。 (大袈裟なのでこちらはあまり使われませんが。。。) 実際にはテキストフィールドに経過時間を表示させるのではなくて, 例えば 「past_time が 1800000ミリ秒(30分) 以上になれば○○を実行」 のような感じになるようにすれば良いということになります。

noname#179453
質問者

補足

取り急ぎありがとうございます!!!! なんてわかりやすい説明なんでしょう、感激しました! 早速ためして見ます、とりいそぎです。 また、アイコンがflashCs4のロゴのイニシャル。。w 僕もまったく同じように、CS4のイニシャル1文字目大文字 2文字目小文字でPCのログインユーザ画像を設定しています。他人とは思えませんでした。。w とりいそぎ、お礼まで。

関連するQ&A