How to draw 2 images on canvas with different fps

Asked

Viewed 187 times

0

Let’s imagine 2 images imagem A and imagem B, I want to draw the imagem A at 60 fps, and imagem B at 30 fps.

I wanted to know (using requestAnimationFrame) what is the best way to do this, should create another canvas?

  • Would this image be a set of Commands to draw on canvas, a kind of animated texture or would you just be repainting an image? Anyway requestAnimationFrame will always run at 60fps, if you want anything to run at 30 make a condition that draws the frame image yes frame no, 60/2=30 got it? but this can give you problems if you want things to run at 20 or 40. If you’re not making setInterval games looks good

  • Yeah, the problem is I’m playing a game

1 answer

2


window.requestAnimationFrame() actually only invokes the function passed per parameter every 16.67 milliseconds (that is, 60 times per second). The responsibility of the function passed as parameter to window.requestAnimationFrame() is to draw whatever you need to draw, be it using <canvas>, <img> or <div> with background-image.

Let’s imagine that imagemA and imagemB sane ImageBitmaps with the frames arranged horizontally, side by side, which you draw in a <canvas> using renderingContext.drawImage(). We will then have something similar to:

var canvas = document.getElementById("meuCanvas"),
    ctx = canvas.getContext("2d"),
    imagemA = new Image(),
    imagemB = new Image(),
    num_ticks = 0,
    largura_A, altura_A, frames_A, x_A, y_A,
    largura_B, altura_B, frames_B, x_B, y_B,
    bmpA, bmpB;
// carregar as imagens
imagemA.src = "path/to/imageA";
imagemB.src = "path/to/imageB";
// quando as imagens terminarem de carregar...
Promise.all([
    new Promise(function (resolve, reject) {
        imagemA.onload = function () { resolve(this); }
    }),
    new Promise(function (resolve, reject) {
        imagemB.onload = function () { resolve(this); }
    })
]).then(function (imgA, imgB) {
    bmpA = createImageBitmap(imgA);
    bmpB = createImageBitmap(imgB);
    desenhar_frame(); // inicia a animação
});
function desenhar_frame() {
    // imagemA tem largura_A por altura_A pixels e frames_A frames, sendo desenhado em (x_A, y_A);
    // imagemB tem largura_B por altura_B pixels e frames_B frames, sendo desenhado em (x_B, y_B).
    // o frame de A sempre avança
    ctx.drawImage(
        bmpA,
        x_A, y_A,
        largura_A, altura_A,
        x_A * (num_ticks % frames_A), 0,
        largura_A, altura_A
    );
    // B tem que ser desenhado toda vez, mas o frame só avança chamada sim, chamada não
    ctx.drawImage(
        bmpB,
        x_B, y_B,
        largura_B, altura_B,
        x_B * (num_ticks % (2 *frames_B)), 0,
        largura_B, altura_B
    );
    // avança o contador de frames e registra a função para
    // se chamar de novo daqui a 1/60 segundos
    num_ticks ++;
    requestAnimationFrame(desenhar_frame);
};
  • Upvote because of the imagemA.onload = function () { resolve(this); } that is of a genius ..., I would have passed a reference to imageA in the argument of the resolve.

  • @Coldmeson_06: Actually, how this in that context is imagemA, return a reference would be absolutely equal. In fact, I did not need to pass anything on .resolve(), since the imagemA is always in the scope, but in a less crude example can be a convenient technique.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.