2012-03-02 3 views
4

저는 캔버스 태그를 사용하여 간단한 자바 스크립트 기반 게임을 진행하고 있습니다. 게임의 일환으로, 화면에 등장하는 캐릭터와 관련된 애니메이션이 포함 된 몇 개의 큰 스프라이트 시트 (예 : 2816x768 및 4096x4864)가 있습니다. 게임이 시작되면 게임에는 단순히 캐릭터의 유휴 애니메이션이 재생됩니다. 사용자가 공간을 누르면, 전적으로 다른 때로부터 다른 애니메이션을 재생하기 시작합니다.Chrome에서 처음으로 큰 이미지를 그리는 데 약간의 지연이 있음

는 사용자로부터 1.5 초 지연이
Stage.prototype.loadImage = function(src) 
{ 
    var image = new Image(); 
    this.incAssets(); 
    var stage = this; 
    image.onload = function() 
    { 
     stage.decAssets(); 
    } 
    image.src = src; 
    return image; 
} 

문제가된다 : 여기

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

그리고 이미지를로드하는 코드입니다 : 여기

는 스프라이트를 그리는 코드는 새 스프라이트 시트의 프레임이 실제로 그려지는 공간을 누른다. 이것은 한 번만 수행되며 다음 애니메이션의 매끄러움에 영향을 미치지 않습니다. 이미 스프라이트 시트가 new Image을 사용하여 미리로드되어 있고 게임이 모든 해당 image.onload 이벤트가 시작될 때까지 시작되지 않으므로 브라우저가로드 할 때까지 기다리지 않고 있음을 알 수 있습니다. Chrome 17.0에서 디버거를 사용하여 JavaScript를 단계별 실행하고 drawImage 호출에 대한 지연을 컨텍스트에서 좁혔습니다. 가장 불편한 점은 Firefox 10.0.2에는이 지연이 없으므로 Chrome과 관련된 문제입니다. 그것은 게임 플레이에 매우 혼란 스럽습니다.

내가 뭘 잘못하고 있니? Chrome에서이 지연을 줄일 수 있습니까?

편집 : 피터 위 샤트 (Peter Wishart)가 제안한대로로드하자마자 다음 프레임 전체를 그려 보았습니다.하지만 그 영향은 미미했습니다.

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; 
}; 

이 너무 효과가 없었다 : 나는 또한 다음과 같이 loadImage를 수정했습니다.

사실 솔루션을 찾았지만 대단히 비효율적입니다. 크롬이 해독 된 후 이미지 메모리로 똑똑한 작업을하려고했을 수도 있습니다. 이미지가 오래 동안 사용되지 않고 다시 추측되는 경우 Chrome은 메모리에서 디코딩 된 데이터를 삭제하고 다시 필요할 경우 다시 가져옵니다. 일반적으로 디코딩 프로세스에는 눈에 띄지 않는 시간이 걸리지 만 큰 이미지를 사용하면 성능이 크게 떨어집니다. 이것을 사용하여 draw loop를 바 꾸었습니다 :

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

음 ... onLoad가 해고되었지만 Chrome이 압축을 풀거나 그래픽 카드에로드하는 등의 이미지를 준비하기 위해해야 ​​할 일이있을 것입니다.

사용자가 공간을 누르기 전에 지연이 이동되도록 미리 첫 번째 프레임을 강제로 화면 밖으로 드래그하거나 숨길 수 있습니까?

0

크롬이 정확하게이 목적을 위해 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

관련 문제