■ Three player ships with different special abilities and stats ■ 40 different enemies ■ 5 levels ■ 5 bosses in three variations each (15 bosses total) ■ 25 weapons ■ 250 unique waves ■ 5 random events (Warp Malfunction, Asteroid Field, Minefield, Laser Barrage, Meteor Storm) ■ 20 perks to choose from at the end of each level
The most important thing, the flesh of the game, are enemy attack waves. In this short log i will show you how they are made.
The process is a bit tedious and probably can be automated to a certain amount (which i will probably be introducing to add some random variety) but it serves me well and gives a decent amount of control over what i do.
First, i choose what enemies will the wave contain (out of 40 enemies, yikes) and put them in the place i want them to be spawned. In this case, this is a simple one, enemies coming in from one direction.
I usually avoid putting them one behind another to avoid overlapping when they are on the screen if they are using a simple movement pattern (from right to left at a fixed speed).
After that, i put them in prefab and use a template i have for spawning and assigning positions. Spawning coordinates are manually copied from instances into a big table containing all the enemy waves, their elements and their positions.
Depending on the placement on the screen, enemies are applied a defined movement speed and direction. When placed right from the center, they will go left, when placed left of the screen, they will go right, when placed up – they go down, when placed down – they go up.
That’s simple, but it’s boring to have enemies always move in the same manner. All the enemies in the picture above i placed will use their own speed which can cause them to overlap and look messy when they appear on screen. So i have a couple of spawners with their tags. I use them to child the enemies to them and get additional info. For example, i can place them in singles squadron for all of them to use their base speed, or under squadron squadron (yeah, i know) for their speed to be overriden with whatever i type in the inspector. That way i can have that big asteroid cannon move slowly as well as the ships around it, like they are escorting it. I can also select the ships from the wave to keep their own speed, and others move like squadron, together. In this example, i’ve put the purple ones to move slowly with the big asteroid cannon, and the small greenish ones to move at their own accord.
That also gets repetitive so i’ve put another spawner type – waypoint enemies spawner! That way i can select any enemy from the wave and assign it a nice set of waypoints to follow (local or global), stop and continue during the movement and so on.
Another spawner type which is use exclusively on it’s own is the warp spawner, which spawns enemies on a (selectively) random place on the screen. Since it’s semi-random, i avoid using another spawner types to avoid overlapping. Nothing will happen to them since they can’t collide, but it looks ugly and unconvincing.
Of course, when combining waves, appropriate positioning and timing is also neccessary to avoid linear moving enemies with waypoint spawned ones.
In the end, it all looks something like this. Two round guys up and down move down and up, respectivelly. Thew won’t collide since they lock onto player and start following him. Small asteroid cannons follow the waypoints and come in front of the big asteroid cannon and two small ships that are escorting him at the same speed. Four small ships behing the big cannon move on their own accord, they are very fast and will overtake the big guy before they enter the screen.
That’s it, multiply that by several hundred and you’ve got yourself a game 🙂
I’m proud to announce that Rick Henderson has been selected as a participant in the Game Development World Championship 2020 in the commercial title category. GDWC has been (to my knowing) been held since 2012., and it’s a great way to help developers gain visibility.
In today’s video game market, which is overly saturated, it’s quite hard to get your game noticed unless you have a strong publisher, so every bit counts. That’s why, my dear subscribers, i need your help. The more visibility i can get, it will eventually translate to more wishlists and more copies sold and hopefully enable me to work on video games full time – my long time dream. I hope that i can make it with your help.
I’ve been postponing this for a long time, but some time near the end of the past year i realized another overhaul is due, this time for optimization purposes. It’s a long and tedious process and can get you into a rabbit hole that can be hard to get out of. My recommendation is not to overoptimize, but do take care of bottlenecks as soon as they appear since they can get you back to square one too late in the development to fix in a reasonable amount of time. Plan your design accordingly and optimize as soon as you finish an enemy design or feature, that way you lay a solid foundation for future content creation that will utilize the same, optimized framework so you don’t have to worry too much later on.
Avoiding Instantiate and Destroy by using Pooling
Pooling is a great tool to avoid those dreaded instantiate/destroy calls. You’d think that computers in 2020. can chew up pretty much anything you throw at them, but it’s not that simple. Whenever you create a new object (in our case, a prefab instance) it is stored into memory (with resources taken to do the operation itself and memory taken to actually store it) along with the pointers that, well, point to that part of the memory so that it can be found and used whenever needed. Of course, memory manager needs to find the unused part of memory to use and clear it up before use. That process is called Garbage Collection and it’s the usual suspect in most of the performance problems. It all happens quite fast, literally every frame, so if you ever used profiler in Unity you will see a GC Alloc column which tells us how much garbage is generated every frame. You might see a value of 2-3 kilobytes and think “oh, that’s not much”, but bear in mind that if you have 60 frames per second that’s 120-180 kilobytes of garbage per second. Per minute, that’s 7-10 megabytes, so without collecting the garbage your game would probably slow downs and crash quite soon.
Luckily for us, Garbage Collection in Unity is automated so you won’t have memory leaks which will lead to crashing. Automated means you don’t need to clear stuff out of the memory manually, but, unuckily, it uses garbage collector that stops the execution of the game code (though since Unity 2019 you can use the Incremental Garbage Collection which can alleviate these issues if your garbage footprint is small enough). You will see those exact moments in your profiler as a spike and your game will stutter, which is annoying for the player.
So, only reasonable solution to this problem is to avoid creating garbage. But how can you do it if you are creating new bullets, enemies, asteroids and pickups all the time? By reusing them, of course! It is called Pooling (since you use a “pool” of objects) and it is a old but gold method for boosting performance in video games.
It’s not too hard to grasp, you simply instantiate all the objects you will be using on the start of your game (a bit simplified, it takes some time to load everything so you should do it in segments in appropriate time, but more on that later) and then you simply activate them and deactivate them (colloquially called spawning and despawning). Such a simple solution, but with an expected caveat. When you deactivate an object, it keeps all its properties from the last frame of its active state. So, the despawned enemy will keep its position, rotation, hit points, animator states, you name it, and next time you activate an object it will be in the same state as when deactivated, rotated in unusal direction, with 0 HP and animator stuck on same frame in the middle of an animation. So what we need to do is reset everything to its original state before deactivating the object. Seems simple enough, though it can get complicated if you have object that have children and they have their own children and so on, which is usually the case.
In this simple diagram above we can see an enemy ship with two children – Jet and Gunpoint. They are all spawned and need to be despawned. But what is important here is the order of operation. When we first spawned them, we spawned the ship first, then the Jet and Gunpoint as children. So we need to do that in reverse order because if we deactivate the ship first, children will be deactivated too before they get the chance to reset their variables.
When the ship takes enough damage to be destroyed, it sends the event (don’t worry, sending events is quite cheap in Unity, hoorah) to both Jet and Gunpoint to reset their variables and despawn themselves. They can either send the event that they finished their reset process back to the parent (ship), or the ship can wait a few frames for them to finish and then reset its own variables and despawn. That way, we have a nice, clean object ready to be reused for the next ship that will be spawned.
Don’t think that pooling alone will help your game magically run at 300 FPS since it’s not the only part of the equation of successful performance management but it does eliminate the worst offenders – instantiate and destroy calls.
If you’d like to read more on the subject, i recommend a great article by Mark Placzek that i often like to read again. It also has some good technical tips on creating your own pool, but if you’re a one man army like me i really recommend using a plugin for pooling from the asset store, they work great out of the box, they are performant and they are easy to use. The one i use is Pool Boss but i can also recommend Pool Kit if you have 40+ cookies to spare.
For more stuff on memory management and garbage collection in Unity i recommend their own manual which you can find here, it’s a cool read to get into the innards of how things work under the hood.
I posted a small video of an enemy from Rick Henderson on Twitter yesterday and it gained a lot of traction so i think it would be interesting to post some stuff on enemy design and how i do it.
When i started making Rick Henderson i
wanted it to be something unique with easily recognizable enemies
defined by their faction, design and modes of attack. With something so
ambitious as a one man project that works on more than 50 different
enemies, making each ship original can be strained in both design and
financial aspects of game development.
Boshin was originally designed as an abomination of multiple Paragon Cult faction enemies, easily identified by their purple color and glowing orbs. I wanted some more ships for that faction and funds for pixel artist were already spent so i had to think of a way to utilize what i already had since my artistry level is quite low. I was lucky to work with an artist who knew what he was doing, had a concise palette and distinct shapes for each faction. So i made a pixel art collage that was made out of other ships’ parts in a way that makes it recognizable yet different from other ships.
Harder part was designing the pattern of
attack for it. I try to avoid the usual move from right to left while
firing pattern, and if i really have to use it i try to be creative with
it. This was the case with Boshin.
of the most important aspects of enemy design in shoot ’em up games is
“telegraphing”. It is a concept of showing the player that the enemy is
about to fire bullets at him. Though not really important for so called
“popcorn” enemies (easily destroyable, firing slow bullets rarely) it is
a must for enemies like Boshin that fire five fast bullets in a burst.
You need time to react, otherwise it wouldn’t be fair and you would feel
frustrated by getting hit.
So, what could i do with limited time and no further financial resources?
is the image of the ship when it comes into screen, with the lower
portion of wings with guns drawn into hull. We see it for the first time
and we still don’t know what will it do. Upon entering the screen,
after a random time in a defined range, the ship plays its opening
animation. Best i could manage without artist was to simply obscure the
lower portion (wing with gun and an engine) and animate it as going out
of the ship. Now that we see the gun, we have a clear idea that it will
shoot from it. By adding a bright red light we rise the tension by
letting the player know that something is definitely going to happen. It
goes out of the gun, widens, and the gun is fired with bullets coming
out spreading no further then the red light angle implied. To keep
things interesting, i put a new bullet type for Boshin and made the
bullets rotate and move at random speeds.
Opening animation is another example of keeping it cheap while trying to look good. It’s not so big, only 22 frames that were just a few layers of parts moving pixel by pixel. Animation of the red “laser targeting device” is made out of two animations since it’s quite large and can’t fit in one texture (maximum is 8192×8192). I wanted to keep authentic pixel art feeling so i did it manually, it consists out of 93(!) 128×64 frames, which gives us a sprite sheet that is 11904×5952 pixels in size, hence the reason for cutting it into two parts.
After finishing the basic visuals and a
small problem with the sprite sheet size, there were some more technical
challenges that needed to be taken care of.
It is not yet implemented for Boshin, but most of the ships have some kind of blinking lights on them. To have animated blinking light and the attack mode activation animation like Boshin playing at the same time, you require animation layers and a bit of tinkering with that too.
Also, you probably don’t notice stuff
like this, but in the video, lower engine does not have engine jet
animation playing. I might be a bit of a perfectionist, but i like
things nice and tidy. I can either put a new animation, for example a
thruster activating then going into regular loop (which requires yet
another animation layer), or put an already looping thruster animation
as a child prefab and animating its position to follow the animation,
with setting the sorting layer to be behind the ship.
final issue is the collider. As the ship changes its form, it needs to
be able to detect hits on the new, extended part too. That can be either
done by the most gruesome way known to man, by editing it in the
animation window itself, frame by frame, or by using great free asset
from the Unity Asset Store called Advanced Polygon Collider,
a tool that automatically fits your polygon collider to sprite based on
alpha tolerance and scale. It also does a great job in optimizing the
collider by reducing vertices, so you don’t have to worry about the
performance, at least on desktops.
there you have it, from a visual idea, to implementation and overcoming
slight technical difficulties, a fun and engaging new enemy ship is
First thing we need to do will be making the weapon that will actually be launching those missiles, right? It’s a plain and simple contraption made of twoFSM’s i called FiringSystem and FiringTimer. Firing system will handle the missile creation, and FiringTimer will take care of giving the weapon a rate of fire. It’s basically a countdown timer of cooldown between two missile salvos. It’s a really simple setup.
Firing System FSM
Here’s the graph of the system that controls missiles. Let’s get through the states one by one.
Idle and Stop firing states, triggered by Start and StopFiring global events (global event is an event that can be sent to this FSM from any other FSM) are empty. They are used to have the system in the state of waiting for the command from another FSM via global event, in this case, the FiringController (which there’s no need to cover here, it’s just an input system to detect the firing button has activated the FSM).
When the Fire global event has been received (dark gray rectangle, like Start and StopFiring), we will be getting the Countdown Timer Value from the FiringTimer every frame and compare that value via Float Compare action with 0 so we know when the weapon has cooled down. When the counter hits zero, we move to Get Fire Button state where the FSM will anxiously wait for you to mash that button to spawn missiles.
Ok, we’ve hit that button and moved to Missile Counter state. It is set to 0, and it will count the number of missiles we want to spawn. Once it gets to the predefined number, it will stop creating them and move on. Every time we enter the Missile Counter state, +1 is added to the counter variable and the missile is spawned in the connected SpawnMissile state. Immediately afterwards, we go back to Missile Counter state where we check the counter. In my case, when it hits 11 (so 10 missiles are created) we no longer move to SpawnMissile state but to Send Reset Firing Timer Event state. In that state, a global event is sent to the FiringTimer FSM to start counting down. Until the counter tells us it counted down to zero, we won’t be able to fire the weapon again.
Of course, before we get back to the state of waiting for the countdown timer to do its job, we need to reset the Missile Counter to 0 so we can use it again. It is simply done by setting the value of the INT variable Counter to 0 in the mid state called Reset Counter.
Fun part – Missiles!
Now that we created our firing system that happily churns out 10 missiles in a matter of frames, we need to know what to do with them, right? I won’t be covering the topic of playing the sound of the missile or dealing the damage/destroying itself when leaving the screen or making the particle system for the trail as those are really not the point of this blog post and are part of some other intertwined systems. Instead, we will focus on the movement.
Our missiles are made of two components, the bullet itself that contains VerticalTranslate and HorizontalTranslate FSM’s and only the transform component, and the child element that holds the SpriteRenderer.
The reason why the missile is split into two GameObjects is because we will be using translate movement instead of physics for missile movement so we are unable to use the movement vectors for sprite rotation and instead have to rely on a different technique.
Horizontal Translate FSM is straightforward and designed with only one purpose in mind – to control the horizontal movement of the missile.
There’s really not much to it. We will apply a random amount of acceleration per missile so we get the effect of some missile being slower/faster than the others. Bear in mind that you also need to define the starting Speed of the missile if you don’t want it to start at 0 speed. I opted for 1.75.
VerticalTranslate FSM is where things get fun. Start state is a random event in which it is decided by pure randomness whether the missile will start moving up or down.
Oh, this one decided to go up! We’ll just make it move up a bit (you can also randomize that value, which i’ll probably do, but not too much) by adding the float value to the Y axis in the translation.
We will wait for a random amount of time before staring to move down.
The principle is the same, we are applying a negative float value to the Y axis and translating the missile so it slowly straightens itself and then starts nosediving.
If the missile chose to go down instead of up in the Start state, the rest of the states are exactly the same, we just apply negative value to Y axis in the Move Down state to make it go down and then the positive value in the Reverse Move Up state to make it go up.
Now that we have our missile moving all around we need to take care of the visual representation. As noted before, we are not using physics for movement but a simple translate movement (which is equal to clicking on the game object, holding down the button and moving it around the screen) so we need to relate on a simple technique to point the missile towards the movement direction.
First we need to get the current missile position, i’ll be saving it in the LastFramePosition vector2 variable since it will be the last frame position in the next state.
All we need to do now is to rotate the GameObject towards the last frame position and adjust the rotation. Bear in mind that i’m using 0 degrees of the Rotation Offset since my missile sprite is rotated towards left, but if your missile sprite is pointing right as things usually are, you should set the Rotation Offset to 180 so it’s actually looking in the opposite direction of the last frame position.
The reason we are doing the things this way, with the parent in charge of movement and the child in charge of holding the sprite and rotating it is because the rotation of the parent object would cause the missile to not move properly since rotation affects the translation of the objects.
Here is the final result with particle system added for trail as well as damage detection and all the things that make the missile a missile.
Nobody likes to read about failing (or maybe they do since it’s a great opportunity to learn from others’ mistakes), but it’s a harsh reality in this line of work. The most important thing is to learn something new, and that can be only managed through trying. And when you try, you’ll fail. A lot.
A month ago i finally pushed the big, red START CAMPAIGN button on IndieGoGo and hoped for the best. After all, months of preparation were a guarantee that i will succeed, no matter what. I explored many successful crowdfunding campaigns, the pitch was good, teaser was cool, campaign was well designed with all the feature listed, expenditures broken down. I was completely transparent with what the funds will be used on and i hoped the material i provided (along with the demo available) will be enough for a few hundred people to pitch in a few bucks. With all those games gathering tens of thousand of dollars, why wouldn’t i have a crack at gathering only $3000?
I must admit that the only thing i was worried about was extremely small number of people that suscribed to the campaign (40+). Though IndieGoGo clearly states that it’s really important to make a huge mailing list so everyone can be notified of the campaign start (and it does show number of interestees in your product), i was sure that my twitter follower list (1000+) and profiles on various shmup and game development would do the trick.
After all, it’s 2019., who still subscribes to e-mails?
First few days were great, i managed to get $500 (20%) dollars quite quick and i could already see myself gathering enough funds to make the game a shiny pixel art gem i always wanted to make. Alas, upon further inspection, i realised that most of the backers were either my friends and few twitter followers. Only 23% of funding came from direct IndieGoGo traffic. Regardless of that, i was under (false) impression that the funds will keep on coming.
Then donations began to plummet, and 10 days into the campaign i started receiving $0 per day. It was too late to start contacting streamers (woovit page with hundreds of them is still open in my browser) since most of them have really busy schedules and i don’t think they’d find the time to include my game until the campaign ends. I could extend the campaign duration to 60 days, but it would be unfair to all the backers to withold their money for another month when i’m certain i wouldn’t manage to collect another 80% of the funds projected to finish the game. Flexible funding was not an option since i would tie a noose around my neck to follow strict deadlines i imposed and some stuff that really takes time (like Galaxy Database) and not gather enough funds to keep those promises.
Some further analysis showed that i had 238 visits from USA/UK/Germany combined and only $25 pledges combined from those countries, which probably means they had the interest in seeing what’s it all about, but they were either not attracted enough or they though that the game’s never going to reach $3000 so they never pledged. It’s easy to theoreticize now, but if the goal was $1000 and each of those visitors gave $5, the campaign would have been a success.
Mistakes i’ve made
My biggest mistake was setting the bar too high. As you know, backers are turned off when they see the goal is too high to reach. I should have opted for something like $1000 which was attainable and then keep gathering funds via InDemand program.
Not giving enough importance to mailing list.
Not making a good enough teaser (it is ok, but it can be a lot better).
Not contacting streamers before the campaign start.
Starting campaign too early, the demo i released obviously had too many bugs and i don’t have a big enough community.
Overestimating social media. Twitter likes don’t translate to pledges (and won’t translate to sales too i reckon). After all, most of the followers i have over there are gamedevs themselves and need money for development too.
Not including Facebook into the campaign (personal bias, shouldn’t let that affect business).
I didn’t make proper and regular updates to the campaign and i haven’t made a roadmap of campaign updates.
I didn’t make a break before finishing the campaign and pushing the start campaign button, i was EXHAUSTED and i didn’t have the strength to keep pushing through a month of active work on campaign to get more backers.
Things i learned
Making mistakes is good, and even an unsuccessful campaign is a good marketing, i received quite a few publishing offers based on exposure campaign has made.
You can’t rush things. Game entered fourth year of development and i was getting impatient. Big mistake, the game is ready when it’s ready, not after being too long in development.
Managing my expectations. It’s quite easy to give yourself a false impression of things biased by what you think that will and should be.
Of course, the game will keep on developing, but i will have to find another source of funding, probably via publisher. Also, i would like to use this opportunity to send a big THANK YOU to everyone supporting me, see you in Early Access!
The time has finally come to gather funds needed for doing the remainder of the game!
You can get some awesome perks by supporting me: Early Access, game’s awesome soundtrack and game itself discounted from the regular planned price, Galaxy Database in PDF or hardcopy and even an opportunity to design your own enemy or have your name appear on a blimp in-game!
I find the value of audio in video games immensely important, on par with graphic representation. It enables you to pull the player into the world you designed and help him immerse in the way you imagined it to exist.
I believe implementing sound is usually left as the last thing to do (when you work alone) unless you are making a music-based game, but when my inexperience with implementing audio into a video game is taken into account, there’s no moment too early for this. Fortunately, i know a thing or two about sound since i’ve been spinning records, releasing vinyls, CD’s and digital releases and designing sound for almost two decades in my spare time.
I don’t have time for some in depth research of various arcade cabinets, consoles and home computers’ technical specifications, but back in the day when i owned Amiga 500 i only had 4 audio channels (i remember making music in Octamed with 4 channels, it was quite a challenge). In shooter type video game practice, you have one channel for music, one channel for player bullets, one channel for enemy bullets and one channel for explosions, each with one voice, which means, if the explosion channel needs to play another explosion, it will either stop the current explosion sound playing and play the new explosion sound, or it won’t play it at all.
Needless to say, (as far as i know) live audio processing was not available until more modern engines and computers that could process it all appeared. Game would simply play the sound in a predefined manner – and that’s it.
The things i can do with Unity nowadays are incredible. I can have zounds of channels and voices as well as live audio effects and audio source positioning, but i don’t really need that much in a 2D game of this type. With all that power, (i can’t point out this enough) we must be careful not to overuse the possibilites given to us.
I decided to go with the relatively simple approach. Audio mixer compoment has a master bus with sub-bus for music and sub-bus for sound effects. Sound effects bus also has a few more categorized sub-buses (enemy shots, player shots, pickup sounds, explosions and so on). This enables me to fine tune the control of each and every sound via integrated tools since once you import the sound into Unity, you’re done fiddling with it except applying effects (unless you use some of the assets which enable you to do so, which i don’t. This one looks particularly cool, but i’m unable to afford it at the moment).
But an asset i am using is for managing my sounds and music in an organized manner with some added perks. It’s called Master Audio (one of the most popular audio assets on the Asset Store), a fine tool that enables you to do some great stuff which would take a lot of time to code. I highly recommend it since it really saves a lot of time.
It allows you to set (code-free) number of voices per sound, which is very important as you need to strike a fine balance between a sound being cut by another sound played or (more prominent today) a complete cacophony of sounds clashing together. Another useful perk is making of sound variations which i use profusely in the game, mostly by changing pitch and volume of most of the sounds lower or higher by a very small amount, so no sound played is exactly the same. They don’t differ that much, you can easily hear a bullet is fired from the same gun, but you won’t get ear fatigue from listening the same pitched sound of the same volume over and over.
Modern technology enabled us to add more and use more of everything – almost unlimited number of channels and effects, but my experience and experiences of many other, more advanced audio producers and musicians say that less is more. It’s about the same as in game development: cut, cut, cut again.