I'm developing a top-down 2D tile-based canvas game. I have a single sprite sheet of all my tiles, and then a JSON tile map array of where they're placed.
Previously I would render all the layers of tiles out to a single canvas element once, and then re-render that every frame. This would give me 300+ FPS because it would just be a single draw call each frame to redraw this canvas.
However, the issue with this is that the map is not just a "flat" image. Sometimes tiles need to be destroyed, or sometimes the player needs to stand behind certain tiles (such as when the player is above them), which doesn't seem possible if the map is just a static image.
As a result, I believe I instead need to re-render all the tiles every frame. However, even if I only re-render the tiles that the user can see, the FPS drops tremendously. With just two tile layers and a 100x100 map, the FPS drops to 20.
I would have assumed that, despite there being 100 * 100 * 2 canvas.context.drawImage
calls per frame, that it would still be fine, because it was leveraging the GPU, and I'm using a single sprite sheet, so there should be no texture swapping. Apparently this is not the case.
I was looking for a way to possibly speed this up, but the recommendations seem to be extremely heavy-handed and opinionated libraries like three.js and pixi.js. These libraries would be great, except they do too much. In PIXI and Three.js you need to add objects to a scene and they're automatically redrawn each frame. This is not what I need, as my current ECS architecture demands an immediate-mode renderer, and I have my own scene graph already, so I can't (and don't want to) use theirs.
Is there a solution here? The only thing I really need to do is draw images clipped from a spritesheet quickly. Can this be done using immediate-mode rendering? Or is it doomed to be 20 FPS?