4 - Juegos Multimedia HTML5 - Mejorando animaciones (requestAnimationFrame, fps, full-page)

Tras aprender cómo crear el game loop vamos a descubrir una función que nos permitirá realizar animaciones mucha más fluidas que las realizadas con setInterval(). Se trata de la función requestAnimationFrame(). Además haremos que nuestro canvas se ajuste automáticamente a la ventana del navegador (full-page). Para terminar veremos como realizar un contador de fotogramas por segundo (fps) pero no sin ver antes las posibilidades que nos brinda el navegador Google Chrome para realizar esa tarea.



Aquí tenéis el archivo particulas.html. Podéis verla funcionando aquí. Además captura eventos de ratón (al hacer clic en el canvas cambia el origen de las partículas) que implementaremos en el siguiente videotutorial.
<!DOCTYPE html>
<html>
  <head>
    <title>Part&iacute;culas</title>
    <meta charset="UTF-8">
    <meta name="author" content="http://programmingheroes.blogspot.com.es">
    <style>
        body {
            background-color: #80F;
            overflow: hidden;
            margin: 0;
        }
        div {
            -moz-user-select: none;
            -webkit-user-select: none;
        }
        #fps {
            position: absolute;
            top: 10px;
            left: 10px;
            text-align: left;
            color: #FFF;
        }
    </style>
    <script>
        window.addEventListener("resize", resizeCanvas, false);
        
        var frameCount = 0, currentFPS = 0, timeFrame =new Date().getTime();
        
        var canvas, context, w, h, particles = [];
        
        var img = new Image();
        img.addEventListener("load", start, false);
        img.src = "img/rock.png";
        
        window.requestAnimationFrame = 
                    window.requestAnimationFrame       || 
                    window.webkitRequestAnimationFrame || 
                    window.mozRequestAnimationFrame    || 
                    window.oRequestAnimationFrame      || 
                    window.msRequestAnimationFrame     ||
                    function (callback) {
                        window.setTimeout(callback, 1000/60);
                    };
        
        function start() {
            canvas = document.getElementById("c");
            context = canvas.getContext("2d");
            resizeCanvas();
            window.requestAnimationFrame(update);
        } // fin de start();

        function resizeCanvas() {
            if (!!canvas) {
                w = canvas.width = window.innerWidth;
                h = canvas.height = window.innerHeight;
            }
        } // fin de resizeCanvas();

        /*
         * Game Loop, se repite hasta que el usuario decide
         *  salir de la página.
         */
        function update() {
            updateFPS();
            if (Math.random() < 0.1) {
                particles.push(new Particle());
            }
            moveParticles();
            paint();
            window.requestAnimationFrame(update);
        } // fin de update();

        function updateFPS() {
            var currentFrame = new Date().getTime();
            if (currentFrame-timeFrame >= 1000) {
                currentFps = frameCount;
                frameCount = 0;
                timeFrame = currentFrame;
                paintFPS();
            }
            frameCount++;
        } // fin de updateFPS();

        function paintFPS() {
            var divFps = document.getElementById("fps");
            var text = document.createTextNode("FPS: "+currentFps);
            divFps.replaceChild(text, divFps.childNodes[0]);
        } // fin de paintFPS();
        
        function moveParticles() {
            for (var i=0; i<particles.length; i++) {
                particles[i].move();
            }
        } // fin de moveParticles();
        
        function paint() {
            context.fillStyle = "rgba(0, 0, 0, 1)";
            context.fillRect(0, 0, w, h);
            for (var i=0; i<particles.length; i++) {
                /*var x = particles[i].x, y = particles[i].y;
                context.beginPath();
                context.arc(x, y, 20, 0, Math.PI*2);
                var grd = context.createRadialGradient(x, y, 0, x, y, 50);
                grd.addColorStop(0, particles[i].color);
                grd.addColorStop(1, "rgba(0,0,0,0)");
                context.fillStyle = grd;
                context.fill();*/
                context.drawImage(img, particles[i].x, particles[i].y);
            }
        } // fin de paint();
        
        function Particle() {
            this.x = 0;
            this.y = 0;
            this.vx = Math.random()*5;
            this.vy = Math.random()*5;
            /*this.color = "rgb("+(~~(Math.random()*255))+","
                +(~~(Math.random()*255))+","+(~~(Math.random()*255))+")";*/
        } // fin de Particle();
        
        Particle.prototype = {
            move: function() {
                this.x += this.vx;
                this.y += this.vy;
            },
        } // fin de Particle.prototype;
        
    </script>
  </head>
  <body>
      <noscript>
        No tiene habilitado JavaScript. Debería habilitarlo para poder
        disfrutar al completo de los contenidos de esta página.
      </noscript>
      <div>
          <canvas id="c">
              Tu navegador no soporta canvas.
          </canvas>
          <div id="fps">
              FPS: -
          </div>
      </div>
  </body>
</html>

La imagen de la roca la tenéis aquí.


Y ahora os dejo con estos dos canvas. Intentar adivinar (sin inspeccionar elementos con el Chrome xD) cuál funciona con setInterval y cuál con requestAnimationFrame. Si os interesa el código o queréis saber la respuesta pedirlo en un comentario.


No hay comentarios :

Publicar un comentario