4 ms·
Not OP, but a few tips from my experience: - Use `requestAnimationFrame`, don't use timers. JS timers are really bad, and they won't sync with monitor refresh
by danShumway 7y ago
Not OP, but a few tips from my experience:
- Use `requestAnimationFrame`, don't use timers. JS timers are really bad, and they won't sync with monitor refresh rates.
- If possible, avoid lots of canvas calls. For example, if you want to draw something simple like a bunch of boxes on the screen, grab the pixel array from the canvas and manipulate it directly, don't call `ctx.rect` in a for loop.
I once stuck in a quick dozen-line block of code before a demo that just drew a couple hundred tiny pixel stars in the background and occasionally randomized their position. Went back and profiled later and found out it was taking something like 30% of my render time each frame, and refactoring just that one block of code got rid of a bit of stuttering on old hardware.
- On that note, cache stuff in memory. My game is tile-based. At the start of a level, I iterate over the tiles on an offscreen canvas and generate a single, giant image for the entire map. Then for subsequent frames I can render that with a single sprite call, rather than by iterating over every tile.
Caching visual effects is huge. In general, don't be afraid to stick generated effects in RAM, because every call you make to Canvas has an overhead.
- Also on that note, don't be afraid to use multiple canvases. If you have an overlay or a visual effect on top of your main game, and you can just update that without needing to redraw all of your sprites/tiles, that can sometimes be a big performance benefit.
- chrisweekly 7y ago(Not OP w the Q you answered) Thanks! Great tips. Do you write about this stuff elsewhere?
- danShumway 7y agoI don't have any articles specifically about canvas performance, but I'm pretty open about development so I probably will at some point in the future. If I do they'll be posted at https://loop-thesis.com/blog/ https://loop-thesis.com/blog/ (https://loop-thesis.com/rss.xml https://loop-thesis.com/rss.xml)
- chrisweekly 7y agoCool, thanks for your response. Checked out your "reset hard" prototype demo; it looks great! Reminds me a bit of Bret Victor's talk on inventing from first principles, and a game called "Braid" that involves actively playing with time as a 1st-class property of gameplay. You should post a "show hn" on it! :)
- plopz 7y agoIs requestAnimationFrame still capped at 60fps? My monitor runs at 165hz and the last time I tried requestAnimationFrame it would only do 30 or 60.
- danShumway 7y agoI don't know the answer to that. I imagine different browsers/OSes will have different caps. However, assuming the cap is an issue, I still strongly doubt that with `setInterval` you'll be able to get the precision you need to target specific monitor refresh rates, even if you can figure out a way to detect what the refresh rate is. Maybe if you're targeting Electron, but even there I kind of doubt it. Even with frame caps, `requestAnimationFrame` is still likely the best bet (opinion me). The reality of games on the web is that timing in general, whether it be for update logic, rendering, or audio is kind of a massive pain, and you'll always be accepting some compromises. To me, those compromises aren't big enough to outweigh some of the other substantial benefits, but I don't want to pretend those compromises don't exist.
- hoorayimhelping 7y agoThis little demo runs at 144hz on my gaming monitor: http://hoorayimhelping.github.io/Arty/ http://hoorayimhelping.github.io/Arty/
- enoj 7y agoNo, for a project I am working on using three.js with requestAnimationFrame, it is capped at the refresh rate the monitor is running on. So my gaming monitor running 144hz at 1080p runs the application at 144 FPS according to my FPS counter from stats.js[0] On my laptop running at 60hz it's capped at 60 FPS. There is a huge difference in the "smooth-ness" as well as reduced input lag on the 144hz vs 60hz monitors. So much that I currently dislike working on the app on <100hz monitors. [0] - https://github.com/mrdoob/stats.js/ https://github.com/mrdoob/stats.js/
- plopz 7y agoThat's good to know, might have to try it again. Especially now that shared buffers and atomics are available in web workers.
- dom96 7y agoThank you for your advice! > If possible, avoid lots of canvas calls. For example, if you want to draw something simple like a bunch of boxes on the screen, grab the pixel array from the canvas and manipulate it directly, don't call `ctx.rect` in a for loop. I think this is likely what's causing me the most trouble. The problem is that my game needs to draw many hundreds of circles, each of different colors/sizes. Perhaps I need to pre-render these to an off-screen canvas and then do some blitting. I'm also tempted now to try what someone else suggested and target WebGL instead (likely via Pixi.js).