I am developing a 2D game, and I have a lot of sprites. I used 3D animations and models to render into 2D, to give them that "Fallout" or "Diablo" look to them. It is also easier than drawing by hand, lol.
I have already had to cut the framerate down to 15fps, which was the lowest I could lower without making them have a choppy look to them. However, it was sad due to how incredibly smooth 24 frames looked.
There are two reasons I did this:
1) Cut down on HDD space. The fewer the images, the smaller my total game will be.
2) Cut down on RAM consumption. The fewer images to load, the more likely I am to avoid issues bloating my RAM limitation.
However, if there was a way to compress the images in both HDD space and RAM, I would do so. I have tested it before, and most do not receive any change in quality when giving from RGBA8888 to RGBA5555 and only a little hit when converting to RGBA4444 in my TexturePacker program. I do not do this currently, because SFML seems to use the same amount of memory regardless of which type of .PNG image it is. I looked into researching how to load it differently, but failed to find anything on the subject.
I have read a lot about how to handle 2D video games. The consensus is overwhelming: Pack your Sprites into a Bigger Texture for great performance! So I pack my tiny sprites into a much larger spritesheet using TexturePacker.
However, I plan to have 10-15 animations per character, 5 directions to move, and 15-40 frames per animation (probably an average of 24). With 15 animations, 5 directions, and an average of 24 frames per animation; That is 1800 individual frames per character. If packed in a sprite sheet, that is only 75 images instead. (One sprite sheet per Animation, per Direction. 15 * 5)
For the one huge boss character in the game, I cannot use a spritesheet and have to program a way to simply load in one image at a time. I do not know if I can do this for performance yet.
For the characters, I already pack them in a spritesheet. For a single character walking about, this seems to work most of the time, although sometimes it stalls. However, I attribute that to my ill conceived code that swaps out textures instead of preloading all textures for that character.
If I were to preload the textures, it makes sense for sprite sheets. I would only imagine it's a bad idea to preload 1800 tiny images for each character.
However, I imagine streaming them into and out of memory one at a time would be extremely fast, so I would only need to have a single image in memory at one time. Wouldn't this mean that at any given moment I would only have each character consume a few KB instead of 45+MB?
I imagine this would kill my performance, as streaming would need to be incredibly fast (15 images going into and out of memory and rendering, per second) and although the images would be very small- it might be a better idea to load character spritesheets into memory instead. But I will have to code a single-image stream-like render system for my larger boss character anyway.
I have been experimenting, but it is not a simple process. Especially given the fact I am working on other parts of the game engine that do not deal with graphics right now.
Answer
We have a similar case with our RTS Remake. All units and houses are sprites. We have 18 000 sprites for units and houses and terrain, plus another ~6 000 for team colors (applied as masks). Long-stretched we also have some ~30 000 characters used in fonts.
So the main reason behind atlases are:
- less wasted RAM (in older days when you upload NPOT to GPU it stretched/padded it to POT, I read it's still the same with iOS and some frameworks. You better check on range of hardware you target)
- less texture switches
- faster loading of everything in fewer bigger chunks
What did not worked for us:
- paletted textures. The feature existed only in OpenGL 1.x 2.x and even then was mostly dropped by GPU makers. However if you aim at OpenGL+Shaders you can do that in shaders code yourself just fine!
- NPOT textures, we had issues with wrong borders and blurred sprites, which is unacceptable in pixel art. RAM usage was much higher too.
Now we have everything packed in several dozens of 1024x1024 atlases (modern GPUs support even bigger dimensions) and that works just well eating only ~300mb of memory, which is quite fine for a PC game. Some optimizations we had:
- add user option to use RGB5_A1 instead of RGBA8 (checkerboard shadows)
- avoid 8bit Alpha when possible and use RGB5_A1 format
- tightly pack sprites into atlases (see Bin Packing algorithms)
- store and load everything in one chunk from HDD (resource files should be generated offline)
- you might also try hardware compression formats (DXT, S3TC, etc.)
When you seriously consider moving to mobile devices you will worry about constraints. For now just get the game working and attract players! ;)
No comments:
Post a Comment