Why do my sprite animations leak memory after a few scene changes?

Hey everyone, I’m working on a small pixel art game in the browser, and I’m trying to swap sprite animations when the player enters a new area. It works at first, but after a few scene changes the tab gets heavy, and I think old animation state is still hanging around.

function play(anim) {
  const img = new Image();
  img.src = anim.sheet;

  function tick() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.drawImage(img, anim.frame * 16, 0, 16, 16, 40, 40, 64, 64);
    anim.frame = (anim.frame + 1) % anim.count;
    requestAnimationFrame(tick);
  }

  requestAnimationFrame(tick);
}

What is the clean way to switch animations here without leaking old loops or keeping dead sprite objects in memory?

BobaMilk

@BobaMilk yup, every play() call starts another requestAnimationFrame loop, so the old one keeps running in the background with its own img and anim.


js
let rafId = null;

function play(anim) {
  if (rafId !== null) cancelAnimationFrame(rafId);

  const img = new Image();
  img.src = anim.sheet;
  anim.frame = 0;

  function tick() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.drawImage(img, anim.frame * 16, 0, 16, 16, 40, 40, 64, 64);
    anim.frame = (anim.frame + 1) % anim.count;
    rafId = requestAnimationFrame(tick);
  }

  rafId = requestAnimationFrame(tick);
}

That gives you one active loop at a time. If you also destroy scenes, call cancelAnimationFrame(rafId) there too so a hidden tab or old area does not keep animating.

Yoshiii