Is the 8-Frame Sprite Sheet Rule in Construct 3 an Optimization or a Quirk?

Not favoritedFavorited Favorited 0 favourites
  • 3 posts
From the Asset Store
Casino? money? who knows? but the target is the same!
  • Hello Ashley!

    I’ve been investigating how Construct 3 assembles sprite sheets during export, especially regarding memory optimization and the organization of multiple objects and animations. I carefully read the manual and conducted several practical tests, and I’d like to confirm if my interpretation is correct — particularly on a point that I couldn’t find mentioned in the manual.

    What is already documented (and confirmed through testing):

    Sprite sheets are always assembled in sizes that are powers of two.

    For example, if an object has a 32x32 texture, it will be placed in a 32x32 sprite sheet. If there are more objects or more frames, the size can increase to something like 64x128.

    There is padding between images.

    Even images that are exactly the right size (like 32x32) can end up taking up more space due to this automatic padding — the manual recommends that images be a few pixels below a power of two (like 508px instead of 512px) for better space usage.

    Sizes slightly above powers of two waste memory.

    For example, a 530px x 530px image fits poorly in a 2048x2048 sprite sheet compared to a 500px x 500px image — this point is well explained in the manual.

    Additional observations based on testing:

    Sprite size influences the sprite sheet layout.

    If I create two 32x32 objects, the resulting sprite sheet that contains them becomes 64x128, presumably due to padding.

    ➤ However, if I create the same objects at 30x30, the resulting sprite sheet is 32x64 — showing that slightly smaller objects effectively save space, as the manual suggests.

    NEW DISCOVERY

    (main point of my question):

    If two different objects each have fewer than 8 frames, they are typically grouped together in the same sprite sheet.

    ➤ However, if a single object has 8 or more frames, it gets its own sprite sheet, even if its frames are small (like 32x32). This consistently occurred in my tests, including when changing resolutions and the number of objects in the layout.

    My questions are:

    Is this behavior of isolating objects with 8 or more frames in their own sprite sheets intentional?

    Is there a specific technical reason for this 8-frame limit? (e.g., limitations of the texture packer, loading optimizations, etc.)

    Is it possible to control or influence this behavior in any way to better group similar objects together?

    I find this behavior quite interesting and think it could help many developers optimize their projects better — but I wanted to confirm if my analysis is correct

    I appreciate any clarification you can provide!

  • It's intentional. It is just one of probably dozens of subtle trade-offs and heuristics in the spritesheeting system that we've carefully tuned over the years.

    The limit is arbitrary, but the goal is to avoid a worst-case scenario of a single small sprite image sharing a spritesheet with another sprite with loads of animation frames. For example imagine a small 50x50 image for a button on the title screen ends up placed on a 4096x4096 spritesheet which is entirely full of animation frames from the boss at the end of the game. Now to display that button on the title screen, it must load the entire spritesheet of mostly boss images, using a minimum of 64 MB memory for the entire spritesheet. If you imagine that happening another 10 times with different objects, now you are looking at an extraordinarily high memory usage of 640 MB for just a few buttons on the title screen - an appallingly inefficient result. This heuristic means the boss sprite gets its own spritesheet and avoids that happening. There could still be other unrelated shared content on the button's sprite sheet, but there are other heuristics to try to group objects likely to be used together on the sheet, and if lots of different objects are on the sheet it's more likely some of them will also be useful.

    In other words sprites with lots of animation frames tend to use a lot of memory, and in that case it's best to move them off to their own spritesheet so they are loaded separately for better memory loading granularity. This is also usually a good idea to reduce the download size as well, as modern image compression algorithms do a better job when an image has lots of repeating or similar content on it. We have an arbitrary threshold of 8 frames to switch to this mode. I prefer not to document such fine details of the spritesheeting engine, because we change such details from time to time, and if people assumed we used some specific number and then we change it, it might actually make their project less efficient. So my advice is to ignore such things.

    In case you're wondering if Construct could do a better job, I'd point out rectangle packing is NP-hard, which basically means an optimal solution is an unsolved problem in mathematics, and that's not even taking in to account other factors like memory loading granularity and download size optimization.

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • Thank you for the detailed response, Ashley — it really clarified things. I found it fascinating that there’s a specific rule in place to handle this scenario.

    Based on your explanation, I had a question related to the design of my own game: in many cases, my characters are composed of multiple distinct objects, such as the body, weapon, and projectiles. All of these elements typically appear together on screen during gameplay.

    With that in mind, I was wondering:

    Is there any way to influence the grouping of these related objects so that they end up on the same sprite sheet? The idea would be to ensure that, when a character is loaded, all associated elements are loaded at once — avoiding partial or redundant loading during gameplay.

    Or, based on how the current system works, does Construct already handle this kind of scenario well through its existing heuristics — and trying to force this grouping manually might actually be counterproductive?

    Thanks again for your attention! Your response has already given me many valuable insights on how to better optimize the project.

Jump to:
Active Users
There are 0 visitors browsing this topic (0 users and 0 guests)