Masteroid sectors are built up using layered sprites. There are star sprites, clouds, planets, etc. These are colorized, rotated and scaled to give each sector a unique look. All of those sprites add up and too many start causing frame drops and slow downs. Right now between the sector art, ships, asteroids, stars and shots, there are about 2,500 actively-updated objects on screen during gameplay.
I’ve wanted Masteroid to have beautiful background starfields in each sector since early in development. The ideal way of doing this would be to actually have a huge amount of stars in the background but there’s no practical way to render 10,000 background objects efficiently. Another option would be to have a large starfield sprite in the background. This is what most space games do. But then I need to manually create a large sprite for every sector, which inflates the install size and makes sectors more time-consuming and complicated to create. So, I split the difference…
The first thing I did was just work on drawing a bunch of things once on a “Render Target” – basically a piece of video memory that can be treated as a sprite texture. In this image I’ve drawn thousands and thousands of circles to a Render Target and then used that target as the texture for a rotating sprite.
The next step was to create a test screen that draws real stars and clouds instead of just circles. I created a test screen where I could press the spacebar to draw a new starfield using a random seed. At this point it was taking a couple of seconds to draw 10,000 stars and a few clouds to a Render Target.
A few seconds is a fairly long time in game development. Vic, the creator of the FlatRedBall game engine, joined a screenshare with me to look at the drawing performance. Part of the time taken to draw was because FlatRedBall does a lot of extra stuff to make it easy to manage sprites. But none of that is necessary because I’m creating thousands and thousands of star sprites, drawing them once, and destroying them – they don’t need all of the boilerplate required for management over time. So we added a couple of methods to the core engine allowing advanced users to bypass some of that. Vic also pointed out some general optimizations to make the process faster. After about an hour of tweaking we had the render time down from 4 seconds for 10,000 stars to 0.2 seconds for 20,000 stars!
The starfields need to draw consistently so that each sector is unique but the background starfield for a sector is the same from session to session. The generator was built to work from a provided seed but I had to modify the sector data object to save that seed. I also had to modify my sector editor to allow the artist to rapidly test a lot of seeds to find one that’s visually pleasing and fits the sector! Once that was done I reworked some of the sectors to remove a lot of extra sprites that are no longer needed to add depth now that starfields exist. Here’s the resulting sector with a nice background starfield!
But now I had another small problem. While 0.2 seconds is pretty fast to generate the starfield, it may be significantly slower on lower-end machines. And that’s still a minimum of a 12 frame stutter in the sector load up while it draws the starfield. Sectors were already choppy for a few seconds while loading. The game has to create tons of asteroids, stars, ships, etc and the framerate right when a sector starts was dropping to single digits. I needed to give the game a few seconds to get everything loaded up… enter the loading screen.
Previously, I always thought of a loading screen as a sort of separate “stage” the player sees while the main stage is being prepared with props. However, I now suspect that for most games it’s more like a curtain over the main stage that simply slides away when the stage is ready. This is exactly how I implemented it..
I created a black overlay that hides the sector. I kept it pretty simple, it shows a loading bar and a random hint, like many other loading screens. The game is doing exactly what it was before, I just hide it behind a big black square. This lets the sector draw its starfield, load up a bunch of objects and even let the AI ships start flying towards their task. Not only does this mask the frame drops, it also makes it look like stuff was already happening before the player warped in – slightly better immersion. I give the game a few seconds to sort itself out, and then I hide the loading screen and warp the player in.