This game seems very simple, but the performance is horrid. At startup the frames drop to less than 5 with only 30 sprites. The goombas have a two frame animation. The turtles just go back and forth. I have experimented with removing animations with no real change. The only thing that helps is reducing active sprites. Is arcade really unable to render this game as it is designed? Any dos and donts in here regarding performance?
This one’s really subtle, so thanks for sharing! It led to some good discussion / a good idea for a perf improvement for future versions of arcade.
I made a few small changes that bumped it up from about ~12fps to about about ~17fps on my meowbit (and ~25-30 on the second level):
The key part here is that this part:
has some side effects that may be surprising. images that are static (i.e. not editted at run time, only in the image editor itself) have some benefits for us – we can guarantee they’re the same as they started, and so we can use that in the physics. Once they’re changed at runtime – cloning in this case, but even just setting a single pixel – that is no longer true. At that point, we have no guarantees that the images haven’t been mutated beneath us - if we aren’t careful, you’ll have sprites passing through the tilemap because pixels were changed without updating the hitbox.
In this case, we’re being very careful, and updating the hitbox for every sprite every single frame that the image they are currently set to is one that is modified at runtime (and on some occasions, a few times in a single frame):
This makes us build a bounding box of the pixels in the sprite, so it’s a little expensive – not too bad usually, but really bad for fps when it’s done constantly.
We have an idea of how to fix this in the future (current plan in my head is something along the lines of an ‘editCount’ on the image itself that we increment on each edit to the image in the c++, that we can track on the hitbox and only update the hitbox when that does not match), but for now the easiest thing is to just make all the images you can in the image editor – all I did in this case was copy the original images and use the horizontal flip tool in the image editor.
and side note – if you need to edit the image at runtime for a game to work that is totally fine, especially if it’s only a handful of images! The bad case just comes up when it’s repeated across a ton of sprites that exist at once – so getting rid of runtime edits when possible is ideal. It’s also important on hardware because it saves memory space, as we only have to allocate space in memory for the image when it is modified at runtime.
Thanks much for the deep insights on this. And here I was (thinking) I was teaching a good practice to make image changes easy…edit one master, let the code do the magic BTW: I came up with this method before you added the image flip capabilities in the editor
I will make a version with all static images and measure the diff. As someone who instrumented code a long time ago, it would be cool to have a basic profiler to know where the work is happening. Sounds like your proposed fix would really help.
We do have some light profiling but it’s been a while since I’ve actually made use of it:
I believe there were a few other ways to debug hardware perf that I’ll have too look for, but it’s always something that is good to improve – I have to admit that I personally haven’t done too much profiling on the hardware side, mostly it’s just been gut checks / having a rough idea of where things would be worst in the game engine so far hah
In case it helps, I added a simple performance tracer to Space Rocks 3D that works on hardware. You can activate it from the game’s menu via “enable perf tracing”, and then use “show trace results” after letting it run for a bit. It shows two summary screens, one sorted by exclusive% (time spent in code not counting called subroutines), and one by inclusive% (total time including subroutines).
On the code side, take a look at the simpleperf code in triangle.ts (that reminds me, I should organize the code better). It’s based on defining counters that need to be manually started on function entry and stopped on exit. There’s no need to instrument all functions. Any uninstrumented code will count as part of the caller function, or shown as “untraced” if there is none. Example:
Interestingly, when I made the changes, I was only see a fps improvement around 7, but visibly better performance. Once I closed the tab and then reopened the game, I got the perf mentioned above. Curious, coincidence, or something to this?
Oh, I’d kill if you made the stats persistent across game starts to streamline perf testing. Honestly, just have it one all the time if in the editor…don’t show if in full screen mode?