2012-05-30 14 views
9

Probé ambos en lienzo y no se mostró nada, también dudo que sea incluso eficiente: /. Estoy tratando de hacer llover en la pantalla ... Preguntándome cuál es la forma más eficiente de hacerlo. Soy un principiante en animación y realmente agradecería ayuda.html 5 lienzo animación javascript de lluvia (cómo implementar de manera eficiente y fácil!)

Sospecho que sería mejor crear un objeto de lluvia, cada uno con la calidad de bajar por la pantalla y luego llegar a la parte superior y luego una matriz con ellos ... quizás con valores x aleatorios con el ancho del lienzo y valores y de 0, pero no sé cómo implementar eso. ¡Por favor ayuda!

   xofRain = 20; 
     startY = 0; 
     ctx.beginPath(); 
     ctx.moveTo(xofRain, startY); 
     ctx.lineTo(xofRain, startY + 20); 
     ctx.closePath(); 
     ctx.fillStyle = "black"; 
     ctx.fill(); 


    function rain(xofRain){ 

     startY = canvas.height(); 

     ctx.moveTo(xofRain, startY); 
     ctx.beginPath(); 
     ctx.lineTo(xofRain, startY + 3); 
     ctx.closePath(); 
     ctx.fillStyle = "blue"; 
     ctx.fill(); 
    } 
+0

¿Cómo debería ser esta "lluvia"? ¿Solo rayas azules? (No agua de refracción, ¿verdad?) – Phrogz

+0

sí, exactamente! simples rayas azules –

Respuesta

15

Aquí viene su respuesta, esta lluvia la nieve se ha creado usando HTML 5 lienzo pura, la técnica utilizada para lograr esta animación se llama "Buffer Animación doble". En primer lugar, es bueno saber qué es la técnica de animación Double Buffer.

Técnica de doble amortiguación: esta es una técnica avanzada para hacer que la animación sea clara y con menos parpadeos. En esta técnica, se utiliza 2 lienzos, uno se muestra en la página web para mostrar el resultado y el segundo se utiliza para crear pantallas de animación en el proceso respaldado.

Cómo esto ayudará, supongamos que tenemos que crear una animación con un número muy alto de movimiento, como en nuestro ejemplo de caída de nieve, hay un número de escamas moviéndose con su propia velocidad, así que manténlos en movimiento, tenemos para cambiar la posición de cada hojuela y actualizarla en el lienzo, este es un proceso bastante difícil de manejar.

Así que ahora en lugar de actualizar cada Flake directamente en nuestro lienzo, crearemos un lienzo de buffer, donde se realizarán todos estos cambios y capturaremos un lienzo Picture from Buffer después de 30ms y lo mostraremos en nuestro lienzo real.

De esta manera nuestra animación será clara y sin parpadeos. Así que aquí hay un ejemplo en vivo de eso.

http://aspspider.info/erishaan8/html5rain/

Este es el código de la misma:

<!DOCTYPE html> 
 
    <html> 
 
    <head> 
 
    <meta charset=utf-8 /> 
 
    <title>HTML5 Rain</title> 
 
    <!--[if IE]> 
 
     <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> 
 
    <![endif]--> 
 
    <style> 
 
     article, aside, figure, footer, header, hgroup, 
 
     menu, nav, section { display: block; } 
 
    </style> 
 
    <script type="text/javascript"> 
 
     var canvas = null; 
 
     var context = null; 
 
     var bufferCanvas = null; 
 
     var bufferCanvasCtx = null; 
 
     var flakeArray = []; 
 
     var flakeTimer = null; 
 
     var maxFlakes = 200; // Here you may set max flackes to be created 
 
    
 
     function init() { 
 
      //Canvas on Page 
 
      canvas = document.getElementById('canvasRain'); 
 
      context = canvas.getContext("2d"); 
 
      //Buffer Canvas 
 
      bufferCanvas = document.createElement("canvas"); 
 
      bufferCanvasCtx = bufferCanvas.getContext("2d"); 
 
      bufferCanvasCtx.canvas.width = context.canvas.width; 
 
      bufferCanvasCtx.canvas.height = context.canvas.height; 
 
    
 
      
 
      flakeTimer = setInterval(addFlake, 200); 
 
    
 
      Draw(); 
 
    
 
      setInterval(animate, 30); 
 
       
 
     } 
 
     function animate() { 
 
      
 
      Update(); 
 
      Draw(); 
 
      
 
     } 
 
     function addFlake() { 
 
    
 
      flakeArray[flakeArray.length] = new Flake(); 
 
      if (flakeArray.length == maxFlakes) 
 
       clearInterval(flakeTimer); 
 
     } 
 
     function blank() { 
 
      bufferCanvasCtx.fillStyle = "rgba(0,0,0,0.8)"; 
 
      bufferCanvasCtx.fillRect(0, 0, bufferCanvasCtx.canvas.width, bufferCanvasCtx.canvas.height); 
 
      
 
     } 
 
     function Update() { 
 
      for (var i = 0; i < flakeArray.length; i++) { 
 
       if (flakeArray[i].y < context.canvas.height) { 
 
        flakeArray[i].y += flakeArray[i].speed; 
 
        if (flakeArray[i].y > context.canvas.height) 
 
         flakeArray[i].y = -5; 
 
        flakeArray[i].x += flakeArray[i].drift; 
 
        if (flakeArray[i].x > context.canvas.width) 
 
         flakeArray[i].x = 0; 
 
       } 
 
      } 
 
      
 
     } 
 
     function Flake() { 
 
      this.x = Math.round(Math.random() * context.canvas.width); 
 
      this.y = -10; 
 
      this.drift = Math.random(); 
 
      this.speed = Math.round(Math.random() * 5) + 1; 
 
      this.width = (Math.random() * 3) + 2; 
 
      this.height = this.width; 
 
     } 
 
     function Draw() { 
 
      context.save(); 
 
      
 
      blank(); 
 
    
 
      for (var i = 0; i < flakeArray.length; i++) { 
 
       bufferCanvasCtx.fillStyle = "white"; 
 
       bufferCanvasCtx.fillRect(flakeArray[i].x, flakeArray[i].y, flakeArray[i].width, flakeArray[i].height); 
 
      } 
 
    
 
      
 
      context.drawImage(bufferCanvas, 0, 0, bufferCanvas.width, bufferCanvas.height); 
 
      context.restore(); 
 
     } 
 
     
 
    </script> 
 
    </head> 
 
    <body onload="init()"> 
 
     <canvas id="canvasRain" width="800px" height="800px">Canvas Not Supported</canvas> 
 
    </body> 
 
    </html>

Además, si usted encuentra esta ayuda completa, acepta como respuesta y lo componen. o_O

¡Salud!

1

No estoy seguro de qué es "más eficiente". Si fuera yo, lo haría en WebGL pero no está claro si es eficiente o no.

En cualquier caso, trataría de usar una fórmula sin estado. Crear y actualizar el estado de cada gota de lluvia es discutiblemente lento.

const ctx = document.querySelector("canvas").getContext("2d"); 
 
const numRain = 200; 
 

 
function render(time) { 
 
    time *= 0.001; // convert to seconds 
 
    
 
    resizeCanvasToDisplaySize(ctx.canvas); 
 
    
 
    const width = ctx.canvas.width; 
 
    const height = ctx.canvas.height; 
 
    ctx.fillStyle = "black"; 
 
    ctx.fillRect(0, 0, width, height); 
 
    
 
    resetPseudoRandom(); 
 
    
 
    const speed = time * 500; 
 
    ctx.fillStyle = "#68F"; 
 
    for (let i = 0; i < numRain; ++i) { 
 
    const x = pseudoRandomInt(width); 
 
    const y = (pseudoRandomInt(height) + speed) % height; 
 
    ctx.fillRect(x, y, 3, 8); 
 
    } 
 
    
 
    requestAnimationFrame(render); 
 
} 
 

 
requestAnimationFrame(render); 
 

 
let randomSeed_ = 0; 
 
const RANDOM_RANGE_ = Math.pow(2, 32); 
 

 
function pseudoRandom() { 
 
    return (randomSeed_ = 
 
      (134775813 * randomSeed_ + 1) % 
 
      RANDOM_RANGE_)/RANDOM_RANGE_; 
 
}; 
 

 
function resetPseudoRandom() { 
 
    randomSeed_ = 0; 
 
}; 
 

 
function pseudoRandomInt(n) { 
 
    return pseudoRandom() * n | 0; 
 
} 
 

 
function resizeCanvasToDisplaySize(canvas) { 
 
    const width = canvas.clientWidth; 
 
    const height = canvas.clientHeight; 
 
    if (canvas.width !== width || canvas.height !== height) { 
 
    canvas.width = width; 
 
    canvas.height = height; 
 
    } 
 
}
body { margin: 0; } 
 
canvas { width: 100vw; height: 100vh; display: block; }
<canvas></canvas>

Tenga en cuenta que podría haber utilizado ctx.moveTo(x, y); ctx.lineTo(x, y + 8); para cada línea y luego, al final del bucle llamado ctx.stroke(). No lo hice porque supongo que sería menos eficiente que usar ctx.fillRect. Para que el lienzo dibuje líneas, en realidad tiene que asignar una ruta dinámica (llama al ctx.beginPath). Luego tiene que registrar todas las líneas que agrega. Luego tiene que expandir esas líneas en vértices de varios tipos para rasterizar las líneas. Básicamente puedes see the various algorithms it uses here.Por el contrario, nada de eso tiene que suceder con ctx.fillRect. No deben ocurrir asignaciones (sin decir que no suceden, simplemente diciendo que no es necesario). El lienzo puede usar un solo quad preasignado y dibujarlo en la GPU pasando la matriz correcta para dibujar el rectángulo que le pidas. Por supuesto, es posible que haya más llamadas generales ctx.fillRect 200 veces en lugar de ctx.moveTo, ctx.lineTo 200s + ctx.stroke una vez, pero realmente eso depende del navegador.

La lluvia anterior puede o no ser un efecto de lluvia lo suficientemente bueno. Ese no era mi punto en publicar realmente. El punto es la eficiencia. Casi todos los juegos que tienen algún tipo de efecto de lluvia hacen algún tipo de fórmula sin estado para su lluvia. Una fórmula diferente generaría lluvia diferente o menos repetitiva. El punto es que es apátrida.

Cuestiones relacionadas