2012-06-29 69 views
1

我正在開發一個使用Node.js作爲服務器的多人遊戲。目前它只是一個2D三角形,玩家可以在屏幕上行駛。遊戲循環在服務器上運行,並將遊戲世界狀態的更新發送給客戶端。客戶端有一個繪製循環運行,使用更新的位置和方向將三角形繪製到畫布上。用於遊戲繪製循環的Javascript setInterval不一致運行

問題:

我已經使用的setInterval與拉伸環的30毫秒間隔。然而,遊戲的運動會變得相當不安。我試過測量從一個循環開始到下一個循環的時間,如下面的代碼所示。結果顯示,循環之間的時間在1ms到200ms之間。

實例控制檯輸出:

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)); 
} 
+0

認爲''save''和'restore'調用對性能來說真的很糟糕,實際上在代碼中確實需要它嗎? – Delta

回答

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)); 
}​ 
+0

謝謝。很有幫助。 – RobotEyes

+1

注意,'setInterval(draw(canvas,ctx),30)'只會在那兒調用'draw',然後設置* draw的返回值* - 這不是函數或字符串,所以如果它甚至設法得到沒有TypeError我會很驚訝。改爲說'setInterval(繪製,30,畫布,ctx)'。並聲明'draw'採取你傳遞它的那些參數。 :P – cHao

+0

哎呀!這就是爲什麼它在jsfiddle中擁有完整代碼的原因!否則我會用手提供答案。好眼睛! –

1

好了,所以那裏有幾件事情可以做,以提高性能。首先是緩存你的上下文。把它放在繪製函數的變量外,

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

然後,只需引用ctx抽獎功能。否則,你正在尋找可能是昂貴的dom EVERY循環。

我建議接下來的事情就是使用​​在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 source

時需要重新繪製它基本上是你的瀏覽器控件,讓您更加平滑的動畫/運動。上述墊片回落到setTimeout不支持的位置,但由於您正在製作canvas遊戲,因此無論您使用哪種瀏覽器,都應該支持該遊戲。

你會實現它這樣

draw(){ 
    // All your other code etc.. 
    requestAnimFrame(function(){draw()}); 
} 
+0

謝謝。我實施了你的建議,並且似乎每16ms在一幀左右平穩運行。但是,現在的Firefox更糟,幀速率從1到220 + ms更加不穩定。我注意到,當我打開Fire-bug控制檯或Chrome開發者控制檯時,情況會變得更糟。有什麼建議麼? – RobotEyes