2012-03-02 10 views
4

私はキャンバスタグを使用した簡単なJavaScriptベースのゲームに取り組んでいます。ゲームの一環として、スクリーン上のキャラクターに関連するアニメーションを含むいくつかの大きなスプライトシート(例:2816x768と4096x4864)があります。ゲームが始まると、ゲームは単にキャラクターのアイドルアニメーションを再生します。ユーザーがスペースを押すと、私はまったく違うシートから別のアニメーションを再生し始めます。ここでChromeで初めて大きな画像を描画する際の遅延が小さい

は、スプライトを描画するコードです:

Sprite.prototype.drawFrame = function(x, y) 
{ 
    ctx.drawImage(this.image, 
     x*this.width, y*this.height, 
     this.width, this.height, 

     this.position[0], this.position[1], 
     this.width, this.height); 
}; 

そしてここでは、画像をロードするコードです:

Stage.prototype.loadImage = function(src) 
{ 
    var image = new Image(); 
    this.incAssets(); 
    var stage = this; 
    image.onload = function() 
    { 
     stage.decAssets(); 
    } 
    image.src = src; 
    return image; 
} 

問題はときに、ユーザーから1.5秒の遅延があることがあります新しいスプライトシートからのフレームが実際に描画されるときにスペースを押します。これは1回のみであり、次のアニメーションの滑らかさには影響しません。私はすでにnew Imageを使ってスプライトシートをプリロードしてあり、対応するすべてのimage.onloadイベントが発生するまでゲームが開始されないので、ブラウザがロードを待っていないことがわかります。 Chrome 17.0でデバッガを使用してJavaScriptを使いこなし、コンテキスト上でdrawImageコールの遅延を絞り込んだ。最も困惑していることは、Firefox 10.0.2ではこの遅延が存在しないため、Chrome固有の問題です。それは非常にゲームに混乱している。

私はここで間違っていますか?とにかくChromeでこの遅延を減らすことはできますか?

編集:私はPeter Wishartが提案したように読み込まれるとすぐに次のフレーム全体を描画しようとしましたが、それは最小限の効果しかありませんでした。私もloadImageを次のように修正しようとしました:

Stage.prototype.loadImage = function(src) 
{ 
    var image = new Image(); 
    this.incAssets(); 
    var stage = this; 
    image.onload = function() 
    { 
     ctx.drawImage(image, 0, 0); 
     stage.decAssets(); 
    } 
    image.src = src; 
    return image; 
}; 

このこともあまり効果がありませんでした。

実際、私は解決策を見つけましたが、それはひどく非効率です。デモ後にChromeが画像メモリでスマートなことをしようとしている可能性があります。画像が十分に長く使用されておらず、やはりこれは単なる推測である場合、Chromeはデコードされたデータをメモリから削除し、必要に応じて再度取り込みます。通常、デコード処理には目に見えない時間がかかりますが、私が使用する大きな画像は非常に劇的なパフォーマンスの低下を招きます。これを使用して描画ループを変更しました:

function draw() 
{ 
    var currentTime = new Date().getTime(); 
    var deltaTime = currentTime - lastTime; 
    lastTime = currentTime; 

    var dt = deltaTime/1000.0; 

    // The hack that keeps all decoded image data in memory is as following. 
    if (this.stage.nextStage != undefined) 
     this.stage.nextStage.draw(0); // The 0 here means the animations advance by 0 milliseconds, thereby keeping the state static. 

    ctx.clearRect(0, 0, canvas.width, canvas.height); 
    ctx.drawImage(backgroundImage, 0, 0, canvas.width, canvas.height); 
    if (stage != undefined && stage.loaded) 
    { 
     stage.draw(dt); 
    } 
} 

この解決策は機能しますが、私が言ったように、ひどい廃棄物のようです。デコードされたデータがChromeで古くなるのを防ぐため、次の一連のアニメーションのフレーム全体を描画する必要があります。

この戦略には、無駄が少なく、ハックの少ない代替品がありますか?

答えて

2

Chromeは、しばらくしてデコードされた画像データを捨ててしまったという考えで、キャンバスをメモリから取り除くことを気にしないという前提で、オフスクリーンキャンバスに画像をコピーするだけでした。これを行うコードはloadImage関数にうまく収まります。

Stage.prototype.loadImage = function(src) 
{ 
    var useCanvasCache = Prototype.Browser.WebKit; // If we are in a WebKit browser (e.g. Chrome) 
    var decodeCanvas; 
    var dectodeCtx; 
    if (useCanvasCache) 
    { 
     // Creates a canvas to store the decoded image. 
     decodeCanvas = document.createElement('canvas'); 
     dectodeCtx = decodeCanvas.getContext('2d'); 
    } 
    var image = new Image(); 
    this.incAssets(); 
    var stage = this; 
    image.onload = function() 
    { 
     stage.decAssets(); 
     // Simply transfer the image to the canvas to keep the data unencoded in memory. 
     if (useCanvasCache) 
     { 
      decodeCanvas.width = image.width; 
      decodeCanvas.height = image.height; 
      dectodeCtx.drawImage(image, 0, 0); 
     } 

    } 
    image.src = src; 
    // Canvas works the same as an image in a drawImage call, so we can decide which to return. 
    if (useCanvasCache) 
    { 
     return decodeCanvas; 
    } 
    else 
    { 
     return image; 
    } 
}; 

これも機能します。ページがロードされているときに小さな初期ペナルティがあり、より多くのメモリを使用する可能性がありますが、このアプリケーションのメモリよりも速度が重要なため、実行可能なソリューションです。

0

Hmm .. onLoadが解凍されているにもかかわらず、圧縮解除のような画像を準備するためにChromeが必要とするものがあります。グラフィックカードにロードします。

最初のフレームを強制的に非表示にするか、または非表示にすることができます。これにより、ユーザーがスペースを押す前に遅延が移動されますか?

0

正確にこの目的のためにchromeがdecode関数に追加されたように見えます。最初のDOMへの追加時のデコード遅延を防ぎます。

FirefoxやIEでは実装されていません。

const img = new Image(); 
img.src = "bigImage.jpg"; 
img.decode().then(() => { 
    document.body.appendChild(img); 
}).catch(() => { 
    throw new Error('Could not load/decode big image.'); 
}); 

詳細情報:https://medium.com/dailyjs/image-loading-with-image-decode-b03652e7d2d2

関連する問題