How tilemaps may ruin your project. And your sanity

Not favoritedFavorited Favorited 3 favourites
From the Asset Store
This is a black tileset with 2 tilemaps, props, one animated character and more.
  • Sorry for the clickbait title, but if you’re using tilemaps in your projects, or you’ve ever had the editor crash with an out-of-memory error - you really should read this. TL;DR at the end.

    The problem

    You may have noticed that tilemaps remember their previous size. That kinda makes sense: if you shrink a tilemap and later make it bigger again, the tiles aren’t erased - they’re still there.

    But now imagine these scenarios:

    1. You have a large open-world layout, say 20,000×20,000 pixels, and you add a new Tilemap object. By default, the tilemap takes up the entire layout, so its size becomes 20,000×20,000. You then resize it to what you actually need - say 300×200 - and think nothing of it.
    2. You have a fairly large tilemap, maybe 3200×3200, and you want to reduce the tile size from 32 px to 16 px. But instead of typing 16×16, you accidentally enter 1×1. Oops. You notice the mistake, change it to 16×16, and move on. No harm done, right?

    Wrong.

    In both cases, the tilemap will now forever remember its maximum size.

    Tilemap #1 is now 20,000 / 32 = 625 × 625 tiles

    Tilemap #2 is a staggering 3200 × 3200 tiles - tiles, not pixels!

    Why is this bad?

    Browsers have a hard memory limit per tab. In Chromium-based browsers it’s about 4 GB. That means the Construct 3 editor - including all its modules and your loaded project - must fit within that limit.

    Now let’s see how much memory our “rogue” tilemaps consume:

    A tiny tilemap #1 with a visible size of 300×200 px takes 15 MB of RAM.

    And that’s per instance. If you copy that tilemap to 100 layouts, that’s 1.5 GB - over a third of the total allowed memory.

    Tilemap #2 uses 410 MB. That’s 10% of the entire memory budget. Duplicate it once? Boom - another 410 MB gone.

    It doesn’t matter if the instances are on different layouts — the editor loads all tilemaps from all layouts into memory.

    And eventually this happens:

    There is a bit of good news: it seems that invisible areas that are completely empty (tileID = -1) don’t get loaded into memory. Unfortunately, the moment you use the Bucket tool, those areas get filled with tiles — and now they do count.

    Real-life implications

    “But those are unrealistic scenarios” you might say.

    Ha. Let me tell you a sad story.

    While working on our game, I’ve been dealing with random “Out of memory” crashes for years. I upgraded RAM multiple times, tried every Chrome flag imaginable, switched to Edge and Brave — nothing helped.

    Our project sits at around 3.5 GB of memory usage, right on the edge. Any sudden spike (for example, running a big search) can push it past 4 GB and crash the tab.

    We use tilemaps a lot. Just one example: we have 30 dungeons, each built from lots of small tilemaps (rooms). Each tilemap’s visible size is 40 × 22 tiles, but their maximum (invisible) size was 335 × 138.

    I honestly don’t remember how this happened. Maybe originally we planned one big tilemap per dungeon and later resized it down to single rooms. But Construct remembered the original size forever.

    I’ll spare you the math, but that’s ~20 million invisible dungeon tiles just sitting in memory, wasting RAM and CPU.

    Yesterday I ran a script that updated all tilemaps across all layouts.

    It processed 560 tilemaps and removed 98796127 tiles. 99 MILLION. Freeing almost 3 GB of RAM.

    No more crashes. And the editor runs a lot smoother.

    Important note: this applies only to the editor. In exported projects, invisible tiles don’t matter nearly as much — they will probably increase memory usage and save size, but won’t crash your game.

    What this means for you

    Check your tilemaps, people.

    Here is the script that automatically resizes tilemaps to their visible size. (requires NWjs for batch mode). Use it at your own risk, and please back up your project first.

    EDIT: R0J0hound made a much better version, use that instead.

    TL;DR

    Tilemaps in Construct remember their maximum size, even after you resize them. This means a tiny-looking tilemap can secretly contain millions of invisible tiles, eating huge amounts of RAM in the editor. Since browsers have a ~4 GB memory limit per tab, this can cause random “Out of memory” crashes. Check your tilemaps and make sure their max size matches what you actually use.

    Tagged:

  • Kudos for finding the cause of your projects running out of memory.

    Can’t it just be reported as a bug so it gets fixed? Seems like an oversight that space gets reserved for the biggest we’ve resized a tilemap instead of only storing the visible ones used.

  • Wow, that is hugely important bit of info. I was just about to start as project with tilemap size of 98304 x 98304 pixels and even thinking about increasing it. Might want to switch engines at this point.

    EDIT: mistakenly wrote tiles instead of pixels. My project is 1536x1536 tiles

  • Can’t it just be reported as a bug so it gets fixed? Seems like an oversight that space gets reserved for the biggest we’ve resized a tilemap instead of only storing the visible ones used.

    This is definitely an oversight, but Ashley will probably argue that not all tilemaps can be safely cropped. What if you resized it by mistake? Or maybe you keep a large tilemap shrunk in the editor to save space, and only resize it to its full size when needed?

    I was just about to start as project with tilemap size of 98304 x 98304 tiles

    If my math is correct, this will use about 400 GB of RAM :)

  • If my math is correct, this will use about 400 GB of RAM :)

    EDIT: My mistake, it is PIXELS, not tiles :D

    I have the tilemap in project, it is running fine. But so far I only generate random tiles to it in game. So yeah... when I am going to paint the tiles in editor, which will take a lot of time.. there is a big problem. I probably have to do it in chunks and even re-use chunks.

    I should switch to Godot at this point, especially if normal Construct usage requires actual programming...

    One thing to resolve this, would be a tilemap that has no size, it would act as a layer, like in other engines. Gdevelop tilemap is also infinite. Resizeable and movable tilemaps have their perks of course. Perhaps a separate tilemap object or layer?

  • Nice discovery! Hope it can get fixed

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • EDIT: mistakenly wrote tiles instead of pixels. My project is 1536x1536 tiles

    1536x1536 tiles should be perfectly fine! Just make sure that "max-width" and "max-height" values in the layout.json for this tilemap are also 1536.

  • > EDIT: mistakenly wrote tiles instead of pixels. My project is 1536x1536 tiles

    1536x1536 tiles should be perfectly fine! Just make sure that "max-width" and "max-height" values in the layout.json for this tilemap are also 1536.

    Layout.json? Where is that? Do I have to download a project as a folder structure for that? Things like these should be in the editor, lots of artist and non-web developers alike are using construct, precisely to whom this seems targeted to.

  • Layout.json? Where is that? Do I have to download a project as a folder structure for that?

    Yes, save as a project folder. Or simply unpack the C3P fie - it's actually a ZIP.

  • That's an interesting find and sounds really painful.

    Some ideas how Scirra could fix it:

    - using uint16 arrays for the tiles, halving memory usage

    - only store a specific amount of tiles larger than the visible size (for example 128 tiles wider and 128 tiles higher than the visible size, making sure this can't get out of hand)

    - only keep the last few layouts in memory, instead of all tabs. This may also fix some other editor memory and stability issues

  • Amazing find. I don't think I'd have managed, my patience for debugging and finding workarounds has been long depleted.

    Congratulations! And thank you for sharing (I'm not a tile-map user, never liked them, but I know plenty of people that use those).

  • Another solution (besides optimizing the way Tilemaps are stored, of course) would be to do the resize to visible size action:

    -on manual save

    -on Save on Quit

    Plus, a button in Tilemap properties to resize would be good too.

    Finally, since crossing the browser mem limits can be predicted with a high degree of accuracy, C3 should internally detect if a resize etc. operation would put the tab in the crash state and disallow with a message...

  • Another solution (besides optimizing the way Tilemaps are stored, of course) would be to do the resize to visible size action:

    Or maybe a checkbox - "Trim unused tiles" or "Crop to content" - on the tilemap object. It should be enabled by default and affecting all instances.

  • It should be automatic to just crop when resizing. If they want to preserve the outside tiles in case of accidental resizes it should be part of the undo stack or strictly temporary instead of never cropping smaller ever.

  • dop2000

    I wanted to experiment with modifying zip files, and the idea of cropping rle data sounded interesting so here's something similar to your script that runs on c3p files directly using a js zip library.

    To use you select a c3p file, it crops all the tilemaps, and finally downloads a modified copy. yourGame.c3p -> yourGame_tilemaps_cropped.c3p

    https://www.dropbox.com/scl/fi/bq5x4pphbsdil2p16ox6t/c3p_tilemap_cropper.c3p?rlkey=jsag5662smgxbpl2leos633hy&st=9je4x6p0

    Edit:

    Pulling for now since there are issues beyond my testing.

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