2011-12-10 12 views
8

Estoy haciendo un pequeño juego HTML5 y, al cargar mis sprites al comienzo del mapa, hago un poco de procesamiento con GetImageData()/bucle sobre toda la imagen/PutImageData().Canvas horrible GetImageData()/PutImageData() el rendimiento en el móvil

Esto funciona fantásticamente genial en mi PC, sin embargo, en mis teléfonos celulares es tremendamente lento.

PC: 5-6 ms 
iPhone 4: 300-600 ms 
Android HTC Desire S: 2500-3000 ms 

que he estado haciendo alguna evaluación comparativa muy básico, y ambos getImageData y PutImageData correr muy rápido, lo que está teniendo mucho es el bucle a través de los contenidos.

Ahora, I obviamente espero una desaceleración en el teléfono, pero 1000x suena un poco excesivo, y la carga tarda aproximadamente 4 minutos en mi HTC, por lo que no va a funcionar. Además, todo lo demás en el juego funciona a velocidad muy razonable (sobre todo porque la pantalla es ridículamente pequeña, pero aún así, funciona sorprendentemente bien para JS en un teléfono celular)


Lo que estoy haciendo en este procesamiento básicamente está "oscureciendo" el sprite a un cierto nivel. Simplemente recorro todos los píxeles y los multiplico por un valor < 1. Eso es todo.

Dado que esto es demasiado lento ... ¿Hay una forma mejor de hacer lo mismo, utilizando la funcionalidad Canvas (composición, opacidad, lo que sea), sin recorrer todos los píxeles uno por uno?

NOTA: Esta capa tiene unos 100% de píxeles transparentes y unos 100% de píxeles opacos. Ambos necesitan permanecer 100% opacos o 100% transparentes.

Cosas que he pensado que no funcionarían:
1) Pintando los sprites en un nuevo lienzo, con menor opacidad. Esto no funcionará porque necesito que los sprites permanezcan opacos, solo que más oscuros.
2) Pintar los sprites y pintar un rect negro semitransparente encima de ellos. Esto los hará más oscuros, pero también hará que mis píxeles transparentes ya no sean transparentes ...

¿Alguna idea?

Este es el código que estoy usando, por si acaso ves algo terriblemente estúpida en ella:

function DarkenCanvas(baseImage, ratio) { 
    var tmpCanvas = document.createElement("canvas"); 
    tmpCanvas.width = baseImage.width; 
    tmpCanvas.height = baseImage.height; 
    var ctx = tmpCanvas.getContext("2d"); 
    ctx.drawImage(baseImage, 0, 0); 

    var pixelData = ctx.getImageData(0, 0, tmpCanvas.width, tmpCanvas.height); 
    var length = pixelData.data.length; 
    for (var i = 0; i < length; i+= 4) { 
     pixelData.data[i] = pixelData.data[i] * ratio; 
     pixelData.data[i + 1] = pixelData.data[i + 1] * ratio; 
     pixelData.data[i + 2] = pixelData.data[i + 2] * ratio; 
    } 

    ctx.putImageData(pixelData, 0, 0); 
    return tmpCanvas 
} 

EDIT: Este es un ejemplo de lo que estoy tratando de hacer con la imagen :
original: http://www.crystalgears.com/isoengine/sprites-ground.png
oscurecido: http://www.crystalgears.com/isoengine/sprites-ground_darkened.png

Gracias!
Daniel

+0

¿por favor muéstranos las fotos del antes y después del efecto que intentas lograr? –

+0

Acabo de agregar enlaces en la parte inferior de la pregunta. ¡Gracias! –

+3

¿Estás tratando de oscurecer algunos sprites? Por amor de Dios, no use datos de imagen por píxel para eso. Simplemente dibuje sobre negro semitransparente (con un [[globalCompositeOperation'] diferente (http://www.tutorialspoint.com/html5/canvas_composition.htm) para preservar el alfa). – Phrogz

Respuesta

11

Phrogz tiene la idea correcta. En realidad, solo desea pintar un negro medio transparente (o transparente) sobre todo con GlobalCompositeOperation "fuente en la parte superior".

De esta manera: http://jsfiddle.net/F4cNg/

no era en realidad una buena pregunta sobre el oscurecimiento sofisticado como este, pero el autor lo borró, que es una verdadera pena. Ciertamente es posible hacer máscaras oscuras en cosas dibujadas, incluso con formas sofisticadas.Puede que no lo ayuden, pero para completar y para cualquier persona que busque "lienzo oscurecido", donde algunas partes se mantienen livianas (zonas de exclusión), puede hacerse con la operación global'oror o 'xor', así:

http://jsfiddle.net/k6Xwy/1/

+0

Muchas gracias, esto es exactamente lo que necesitaba. Consideré oscurecer el resultado final del dibujo. El truco de XOR es genial, mucho más simple que el que estaba planeando hacer, pero incluso sin él podría pintar un rect con "agujeros". En ese momento, ya no me importan mis píxeles transparentes. No estoy tomando ese enfoque, sin embargo, porque estoy usando una perspectiva ISO, y mi método, aunque mucho más lento, me permite tener un poco más de precisión en algunas cosas que me importan. Gracias por el consejo, sin embargo, definitivamente seré útil alguna vez. ¡¡¡GRACIAS!!! –

10

Ha visto esto ?: rendimiento punta http://ajaxian.com/archives/canvas-image-data-optimization-tip

Ellos hablan de reducir las llamadas al DOM para aumentar el rendimiento.

Así, sobre la base de este consejo puede probar:

var pixel = ctx.getImageData(0, 0, tmpCanvas.width, tmpCanvas.height); 
    pixelData=pixel.data; // detach the pixel array from DOM 
    var length = pixelData.length; 
    for (var i = 0; i < length; i+= 4) { 
     pixelData[i] = pixelData[i] * ratio; 
     pixelData[i + 1] = pixelData[i + 1] * ratio; 
     pixelData[i + 2] = pixelData[i + 2] * ratio; 
    } 

Sus llamadas .data puede usted ser más lento.

Cuestiones relacionadas