1

Node.js をサーバーとして使用してマルチプレイヤー ゲームを開発しています。現時点では、プレイヤーが画面上を移動できるのは単純な 2D の三角形です。ゲーム ループはサーバー上で実行され、ゲーム ワールドの状態の更新をクライアントに送信します。クライアントは、更新された位置と方向を使用して三角形をキャンバスに描画する描画ループを実行しています。

問題:

描画ループに 30 ミリ秒の間隔で setInterval を使用しました。ただし、ゲームの動きはかなりぎくしゃくすることがあります。以下のコードに示すように、あるループの開始から次のループまでの時間を測定してみました。結果は、ループ間で 1 ミリ秒から 200 ミリ秒かかることを示しています。

コンソール出力の例:

looptime: 59
looptime: 14
looptime: 22
looptime: 148
looptime: 27

私がクライアント側で実行しているのは、サーバーにデータを送信するための onkeyup/onkeydown リスナーと socket.io リスナーだけです。どんな助けでも大歓迎です。

コード:

...

function init(){
    var canvas = document.getElementById('canvas');
    if(canvas.getContext){
        setInterval(draw, 30);
    }
}

function draw(){

    timeNow = new Date().getTime();
    console.log('looptime: '+(timeNow-startDrawTime));
    startDrawTime = new Date().getTime();
    var ctx = document.getElementById('canvas').getContext('2d');
    triX = tri.pos.x;
    triY = tri.pos.y;

    ctx.save();
    ctx.clearRect(0,0,400,400);// clear canvas

    ctx.save();
    ctx.translate(triX, triY);
    ctx.rotate(tri.orientation);

    ctx.save();
    ctx.beginPath();
    ctx.arc(0,0,5,0,Math.PI*2, true);
    ctx.stroke();
    ctx.restore();

    //draw tri

    ctx.save();
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.moveTo(0, -5);
    ctx.lineTo(5, 5);
    ctx.lineTo(-5, 5);
    ctx.closePath();
    ctx.fill();
    ctx.restore();

    ctx.restore();

    ctx.restore();
    //console.log('looptime: '+((new Date().getTime())-time));
}
4

2 に答える 2

2

これが setTimeout の仕様です。Javascript は順番に実行され、ループを完了するのに時間がかかる場合は、ループを完了するのに時間がかかります。

この場合、一貫性を確保することは単にパフォーマンスの問題であり、コードにはそのままの状態で多くの粗雑なものがあります。いくつかのパフォーマンスの改善で注釈を付けました。

Firefox での実行速度が遅い理由は、console.logステートメントが原因です。それを取り除くと、はるかに高速に実行されます。console.log も chrome で遅くなっていました。私は dev バージョンしか持っていませんが、修正されて久しいと思います。実行中のデバッガーは遅くなりますが、それは正常です。

function init() {
    // Never ever reference the DOM unless you absolutely have to
    // So we do it once, here, outside of the loop
    var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');
    if (canvas.getContext) {
        setInterval(draw, 30, canvas, ctx);
    }
}

function draw(canvas, ctx) {

    timeNow = new Date().getTime();
    // console statements can be slow in some browsers, so make sure they're gone from the final product
    console.log('looptime: ' + (timeNow - startDrawTime));
    startDrawTime = new Date().getTime();

    triX = tri.pos.x;
    triY = tri.pos.y;
    // This clears the transformation matrix and resets the canvas
    canvas.width = canvas.width;

    ctx.save();
    ctx.translate(triX, triY);
    ctx.rotate(tri.orientation);

    ctx.beginPath();
    ctx.arc(0, 0, 5, 0, Math.PI * 2, true);
    ctx.stroke();
    ctx.restore();

    //draw tri
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.moveTo(0, -5);
    ctx.lineTo(5, 5);
    ctx.lineTo(-5, 5);
    // no need to close the path since we aren't stroking
    ctx.fill();
    //console.log('looptime: '+((new Date().getTime())-time));
}​
于 2012-06-30T05:50:34.213 に答える
1

パフォーマンスを高速化するためにできることがいくつかあります。1 つ目は、コンテキストをキャッシュすることです。draw関数の外で変数に入れて、

var ctx = document.getElementById('canvas').getContext('2d');

次にctx、描画関数を参照するだけです。そうしないと、高価な dom EVERY ループを検索することになります。

私が次にお勧めするのは、requestAnimationFrameoverを使用することですsetTimeout

// requestAnim shim layer by Paul Irish
    window.requestAnimFrame = (function(){
      return  window.requestAnimationFrame       || 
              window.webkitRequestAnimationFrame || 
              window.mozRequestAnimationFrame    || 
              window.oRequestAnimationFrame      || 
              window.msRequestAnimationFrame     || 
              function(/* function */ callback, /* DOMElement */ element){
                window.setTimeout(callback, 1000 / 60);
              };
    })();

MDN ソース

基本的に、再描画が必要なときはブラウザーが制御するため、アニメーションや動きがよりスムーズになります。上記の shimsetTimeoutはサポートされていない場所にフォールバックしますが、canvasゲームを作成しているため、使用しているブラウザーに関係なくサポートされている必要があります。

このように実装します

draw(){
    // All your other code etc..
    requestAnimFrame( function(){draw()} );
}
于 2012-06-29T21:04:25.080 に答える