2012-01-27 14 views
4

これは私の前の質問からのフォローアップの質問であることに注意してください: "How to memorize user's progress through the application?"。Javascriptタイマーの精度

答えの後、私は間違いがユーザーがゲームに勝ったかどうかを判断するためにJavascriptを使用することでした。だから私は私のコントローラーにロジックを移しました。ユーザーがレベルを開始したときにUNIXタイムスタンプをセッションに保存し、ユーザーがセッションを終了したときの違いを計算します。ユーザーがレベルを完了するまでにX秒以上かかっていない場合は、次のレベルへのアクセスなどを許可します。

Javascriptで作成されたクライアント側のタイマーを導入するまでは、すべてうまくいきました。タイマーは、PHPのものとは明らかに正確ではありません。なぜなら、ユーザーのCPUに依存し、サーバーのものに依存しないからです。したがって、2つのタイマーは同期されません。ゲームは、時間枠が大きい場合(たとえば、ユーザーが4〜10秒の間にレベルを完了しなければならない場合)には動作しますが、時間枠が小さければ(1秒または2秒)期待どおりに動作しません。たとえユーザーが当選した時間枠内をクリックしたとしても、PHPは彼に勝てなかったと伝えます。

私はいくつかの試みがなされてきたし、ここに私の結果は次のとおりです。

|===========================| 
| # | PHP | JS | Ratio | 
|===========================| 
| 1 | 6.20 | 5.29 | 1.17 | 
| 2 | 7.32 | 6.27 | 1.16 | 
| 3 | 2.89 | 2.24 | 1.29 | 
| 4 | 22.56 | 20.13 | 1.12 | 
| 5 | 50.15 | 45.24 | 1.10 | 
|===========================| 

(はい、私は知っている、これはこれまでに作った最悪のASCIIテーブルである。)

そして、これは私が「タイマーですjQueryのを使用して作られまし(私は本当にこの言語で訓練を受けていないよ、それはまた、おそらくこれまでに作ったより悪いJavascriptのタイマーです):私はAJAXのように、さまざまなソリューションを試してみた

$(document).ready(function() { 
    window['time'] = { 
     'cseconds': 0, 
     'dseconds': 0, 
     'seconds': 0, 
     'minutes': 0, 
     'hours': 0 
    }; 

    $("#timer").everyTime(10, function() { 
     window['time']['cseconds'] += 1; 

     if (window['time']['cseconds'] > 9) { 
      window['time']['cseconds'] = 0; 
      window['time']['dseconds'] += 1; 
     } 

     if (window['time']['dseconds'] > 9) { 
      window['time']['dseconds'] = 0; 
      window['time']['seconds'] += 1; 
     } 

     if (window['time']['seconds'] > 60) { 
      window['time']['seconds'] = 0; 
      window['time']['minutes'] += 1; 
     } 

     if (window['time']['minutes'] > 60) { 
      window['time']['minutes'] = 0; 
      window['time']['hours'] += 1; 
     } 

     cseconds = window['time']['cseconds'].toString(); 
     dseconds = window['time']['dseconds'].toString(); 
     seconds = window['time']['seconds'].toString(); 
     minutes = window['time']['minutes'].toString(); 
     hours = window['time']['hours'].toString(); 

     if (seconds.length < 2) { 
      seconds = "0" + seconds; 
     } 
     if (minutes.length < 2) { 
      minutes = "0" + minutes; 
     } 
     if (hours.length < 2) { 
      hours = "0" + hours; 
     } 

     $("#timer").text(hours + ":" + minutes + ":" + seconds + "." + dseconds + cseconds); 
    }); 
}); 

:最初のタイマーが唯一の頼りAJAXリクエスト(これは何千ものHTTPリクエストにつながった)、それはまだ不正確でした。それから、PHPをX秒ごとに同期させるように修正しましたが、うまくいきませんでした。

ヒントはありますか?

答えて

1

でしょうか?それは私の心の第二の解決策でした。サーバーからの時間であるため、動作しなければなりません。

最初の解決策は非常に簡単で、私は最も正確だと思います。 Javascriptの定期的な関数実行に頼るのではなく、システムの日付時刻に頼ってみてください。 Javascriptの定期的な関数を使用して画面の時刻を更新しますが、単純なseconds += 1の代わりにシステムの日付/時刻を使用してください。いくつかの擬似コード:

var startTime = new Date(); 

// Every 1/2 second or less... 
var elapsedTimeInMs = new Date().getTime() - startTime.getTime(); 

私はあなたがDateオブジェクトのドキュメントを読むことをお勧めしかし。

+0

それはうまくいくようです。あなたが私に見せてくれたので、とても分かりました。 :D私はいくつかのテストをさせて、私はおそらくあなたの答えを受け入れるでしょう。 –

+0

魅力的な作品です!あなたの助けをたくさんありがとう:) –

+0

Bene、di nulla;) –

0

AJAXソリューションが動作しませんでしたなぜあなたは、AJAXを使用する必要がありますが、唯一のゲームを終えたユーザのイベントに、サーバー上の時間を得るために...

+0

私は彼の問題は、(JSを使って計算しなければならない)表示された時間は、ゲーム終了時にAJAX経由でフェッチされたサーバー1と同期していないと思うと思います... –

+0

私はできません:毎時のサーバーの時刻を知ることができます。さらに、ユーザーがゲームを終了した時点を判断するPHPであるため、レベルが完了してから時間を表示することは意味がありません。 –

+0

申し訳ありませんが、私はそのことを考えていません –

3

イベントの開始時刻と終了時刻の両方でnew Date()を実行してイベントを実行し、それらの経過時間の差を比較すると、javascriptを使用して非常に正確なタイミングが得られます。現代のブラウザでは、タイマーの精度はしばしば数ミリ秒で、古いブラウザでは15ミリ秒より悪くありません。

あなたのコードは、インターバルタイマーとカウント間隔を使用しようとしているようです。それはあまり正確ではありません。 javascriptはシングルスレッドなので、javascriptタイマーが起動する正確なタイミングはあまり正確ではないので、イベントの正確なタイミングに頼るべきではありません。つまり、起動したタイマー間隔をカウントするのではなく、経過したシステム時間を測定する方がはるかに正確です。

+0

タイマーをローカルに増やすためにタイムアウトに頼るのをやめ、最初のタイマー、現地時間を知ってくださいサーバーから(ajaxを介して)読み込み、次に必要なのは現在のローカル時刻です。 'initialserver + currentlocal-initiallocal'と同じくらい簡単です。 – Blindy

+1

私はいくつかの最新のブラウザは、タブが非アクティブなときにプロセッサの負荷を減らすために、焦点の合っていないウィンドウ/タブでタイマーの解像度を落とすと考えているので、ユーザーがウェブアプリケーションから離れた場合に間隔の精度をさらに悪化させるでしょう – GordonM

+0

私が提案したソリューションを使って解決したもう一つの問題です。 –