Remember not to waste your memory

13
Official Construct Post
Ashley's avatar
Ashley
  • 1 May, 2013
  • 2,022 words
  • ~8-13 mins
  • 19,312 visits
  • 9 favourites

Occasionally we're asked questions like "I want to make a game with huge levels all made of uniquely drawn art tiles. Can Construct 2 handle this?" Alternatively, users go ahead designing levels with HD-size tiles, then find mobile devices can't handle it. Then they might even accuse Construct 2 of having poor mobile support because they can't make a game with all those images. That's not quite the case!

This happens frequently enough that I think it deserves a blog post to cover in more detail. Construct 2 is great for non-technical people to easily get in to game design, and it makes it easy to throw loads of content in your game. But it's still necessary to know the limits of typical desktop and mobile systems. Computers don't have infinite resources, and you need to design your game accordingly.

No Framework Can Handle That

If you're planning to use lots of huge images, often the case is no engine or framework can handle that. It's to do with how much memory is available, which is a hardware limitation. Even if you wrote your engine super-efficiently in C++, it still probably wouldn't work. Let's investigate why that is.

Images are made up of pixels. If we take a HD-sized tile measuring 1920x1080 pixels, this is a total of 2073600 pixels. Pretty amazing when you think computer displays commonly have that many physical pixels!

Each pixel in an image takes up four bytes for the red, green, blue and alpha channels (allowing for 256 different possible values for each channel). To work out the size of the image in memory, each pixel takes four bytes, so we multiply the number of pixels by 4. This means our 1920x1080 tile takes up 2073600 x 4 = 8294400 bytes, or about 8 megabytes.

I should also point out images are fully decompressed in memory. If you have a solid black texture sized 1920x1080, it will probably save to a tiny PNG file which is just a few kilobytes. This means it downloads nice and quickly. However images cannot be rendered to the screen from a compressed file. They're decompressed to their full size in memory for rendering, which means your 5kb PNG file of solid black still takes up about 8mb in memory. So playing with your image formats such as using PNG-8 or JPEG instead of PNG-32 only affects the download size - it does not affect memory use.

Many mobile systems don't support images which are not a power-of-two size (e.g. 32x32, 64x64, 128x128...). To work around this images will be placed in memory on a power-of-two size texture big enough to fit it. In this case the 1920x1080 image will be placed on a 2048x2048 sized texture in memory! This means it uses 16mb of memory - about double, on a system with even tighter memory limits! Construct 2 automatically spritesheets smaller images on export to save memory, but such large images don't benefit from this.

Common desktop limitations

"What's the problem?" I hear you ask. "Most computers have 4GB+ of memory these days." That's true, but desktop devices often have separate video memory (VRAM) for rendering. For maximum performance the images should all be able to fit in to VRAM. In some cases the system can place images in main memory, but it's slower.

A cheap or old graphics card might have 256mb of VRAM. That means to still achieve maximum performance you can fit a maximum of 32 of your big tiles in to video memory, and nothing else. In reality you can't even use the full memory size, because the operating system will be using some for the current display, and other applications might be using some as well. Then don't forget you have the images for the rest of your game! You can only rely on perhaps half that memory, and that leaves you with room for only 16 tiles.

Some cheap new systems don't have VRAM, and exclusively use system memory for images. This is not necessarily better. It's usually a lot slower to access images from main memory, and using lots of large tiles is likely to very quickly bog down the system and drag framerates down.

Common mobile limitations

Like cheap desktop systems, most mobile devices have no dedicated VRAM and use system memory for everything. Not only that, but system memory is often also limited. It's possible a mobile device only has 60-100mb of free memory available. Due to the power-of-two limitation, it's likely each tile actually also uses 16mb of memory. Assuming your game will use half of the free memory for everything which is not backgrounds, you might have room for two background tiles, or four if you're lucky. That's not a very big level any more!

As I hope is beginning to become obvious, there is no way you can realistically design a game like this.

The better way: composition

In practice, nobody develops games with large image tiles - not even professional developers. Your artist might want to draw expansive huge levels as giant unique images, but the reality is you can't make a fast game that runs everywhere like that.

Instead, use tiled backgrounds to cover large areas with repeating images. Then use sprites and other tiled backgrounds for scenery and decoration to break up the repetitiveness. Construct 2 allows you to arbitrarily scale and rotate these objects, which can do a great deal for avoiding a repetitive appearance. For example, a huge boulder can be re-used as some small pebbles; a forest could be made out of just three or four different kinds of tree; distant mountains could be composed from the same objects that make up the nearby ground; and if your player has 20 weapons, make the weapon a separate object positioned by the player to avoid having to re-animate the player 20 times over (which would use 20 times as many images). This re-use of existing art is the key to efficient games with low memory use - and it's a real art in itself of being able to compose detailed worlds from a small set of parts.

If you have 10 tiled backgrounds repeating 512x512 images, and 30 different sprites at 512x512 for decoration, that will use about 40mb of memory. You can probably use the same objects to create several unique levels, and it will still run on even the most resource constrained mobile phones. On top of that, it's likely to run at a much better framerate on desktop systems with dedicated VRAM. Then there are gameplay benefits, like being able to create and destroy parts dynamically, or animate parts of the level. Virtually all professionally designed games take this approach.

Example: Rayman Origins

Here's a good example of image re-use in a professional game. I've stolen an image off Yann from the forums (sorry!) where a few re-used images have been highlighted:

Yann only made a brief attempt to highlight some obvious examples, and if you look closely there is a lot more image re-use going on than has been marked. Yann also noted they wouldn't be surprised if the distant mountains re-used some of the grass images from the foreground, and that later levels re-use some plants with a tint (which you can do in Construct 2 with the tint shader effect). Note how scale, angle and overlap avoids a repetitive appearance, which is also easy to do in Construct 2's layout view.

I think this is a beautifully designed game, both artistically and technically. The impression of the level is an organic and detailed forest scene, but looking closely you can see many images re-used to keep the memory use low. It's also easy for the level designers to make much longer, more detailed levels, since extending the level doesn't need more tiles and more memory. By animating or moving individual objects (e.g. using the Sine behavior) and adding parallax layers you can make environments bursting with life and movement - impossible to achieve with pre-rendered tiles.

This is what the professionals do. In fact my opinion is the re-use of images almost certainly made Rayman a better and more exciting game, since they weren't held back by memory use limitations and were able to design expansive and detailed levels. Re-using images does not mean a game has to look repetitive - it probably actually makes it better!

A word on texture loading

In Construct 2, images are loaded layout-by-layout. This means when a layout starts, every object on the layout is loaded in to memory immediately. This is to avoid mid-game pauses as textures are loaded on the fly. When the layout ends, it will free all the images in memory not used by the next layout, and load any new images the next layout uses. This means your game's peak memory use is based only on the layout with the most images, rather than all the images in the project. So you can happily have something like four different "worlds", e.g. forest, snow, desert, and space, all using different sets of images - and the "snow" world won't make the "forest" levels use any more memory.

Construct 2 displays an estimated memory use in the status bar. You should keep an eye on that. The estimate is based on the largest layout's image memory use, plus the memory used by two images the size of the window (which will probably be necessary by the OS or engine rendering system). With good image re-use, it should be easy to keep this under 60-80mb.

Mobile overdraw

While we're on the subject of mobile limitations, it's worth mentioning some mobile devices can only draw each pixel on the screen 3 times per frame and still reach 60 FPS. In other words, if you have four window-sized images on screen, you cannot reach 60 FPS on such a device. (Note Construct 2 renders scenes from the back to the front, so four overlapping objects are all still rendered.) Perhaps surprisingly, this includes transparent pixels. The GPU processes the full rectangle of a texture regardless of the content, and a transparent pixel still uses up your drawing budget, so four window-sized transparent images would still not reach 60 FPS. Similarly with memory usage, this is a device hardware limitation and you'll have the same limitation with any framework.

The solution here is again to prefer using small images instead of large ones. A large image will eat up lots of the mobile's drawing budget in one go, whereas it's easier for it to render several spread out smaller objects. For example, a window-sized sprite to add borders round the edge of the screen is very inefficient, since the transparent pixels in the middle still use up the draw budget; using four separate sprites for each edge of the screen would be a lot faster.

Conclusion

You have to design mobile games really carefully to get the most out of the often very limited hardware. All good mobile developers do this, even when writing native apps, using all kinds of clever tricks to avoid having too many objects on-screen or images in memory while still achieving a similar visual appearance. You have to be equally careful with Construct 2 games. Just because Construct 2 makes it easy to drag and drop in loads of artwork doesn't necessarily make it a good idea.

As ever, you should make sure you grab a mobile device similar to what you intend your game to be played on, and test regularly on it. It makes it much easier to notice a particular change reduced performance or used too much memory, and then work out something else you can do. If you just port a complete desktop game to mobile and it doesn't run well, you'll have a really tough time trying to figure out exactly what the problem is.

Game development on any platform or framework often involves trickery and illusions to get maximum artistic benefit out of minimum hardware requirements. With the same knowledge and creativity, you can design Construct 2 games the same way.

Subscribe

Get emailed when there are new posts!