This last semester, I took a course that focused on game development in Unity. I mentioned a bit in my previous post, but it consisted mostly of a series of smaller assignments that showed how to use features like animation, scripting, and other game engine offerings.
This course also required a final project, something that demonstrated our ability to put together a game from the ground up, including the planning and design. My goal for this project was to emulate a genre that I loved as a kid, so I decided to create a 2D bullet hell inspired by games like Raiden Trad.
The hardest part of these patterns was determining a directional vector from a 360 degree function input. I ended up falling back on trigonometry to calculate relative x and y values for each vector. A lot of time was spent getting this right, and it wasn't originally apparent that the Math library functions expected radians.
The same design pattern applied to the enemy movement. I had programmed many different movement patterns, such as slow and steady movement to quick, angled directional changes. These smooth movements were accomplished using the Vector.Lerp function, but I didn't quite get the original feel I wanted. At first, it seemed the enemies were just moving too uniformly. It didn't feel like they were flying. After playing with the Lerp function in a bit of an unorthodox way, I eventually found a happy setup where the enemies had a bit of acceleration.
For the background, I used the game Cities: Skylines. By building a city that roughly resembled the background I wanted, I could just stitch together multiple screenshots and edit the result to add some additional features.
For the boss, I wanted a finale that showed off a little bit of everything. Each of his four attacks were designed with some form of telegraphing in mind, so the player knew when they were coming. If the boss's sound effect sounds familiar, you might be a Pokemon fan.
He has a large health pool, but the explosions that go off upon his defeat provide a great sendoff to the player. There was something very satisfying about seeing all the pieces come together for this enemy, and I think it was just the ending that the level needed.
To make this feel like an actual console game, I included a splash screen at the beginning. There are no options, but it was an experiment with game scene changes that we didn't touch much in class. There is also now some score information that challenges the player to do a little better each time.
To change up the player's experience, I added some power ups that change the player's firing pattern. Just like Raiden Trad, one power up gives the ability to shoot a spread, while the other focuses their shots into a powerful beam. Without these power ups, the game gets much harder.
This took a lot of work. I definitely put in way more time than the instructor expected of me, but I wanted this project to be polished. Here's where I get to brag about how some parts work.
I already talked about the systems for aiming, but there are some enemies that aim directly at the player. Most items in the game are loosely-coupled, so enemies, for example, don't actually have any knowledge of the player. In order to aim at them, the game manager broadcasts the player's location at frequent intervals. Using this player coordinate, I can then calculate the difference in the x and y positions between an enemy and the player to get a relative angle. I was super proud of this solution. It has been a while since I actually needed this kind of math, and it was nice to see I haven't forgotten it all.
How are these broadcasts taking place? This was a messenger system component that I reused from class. By adding listeners for specific events, any game object can then pick up on that event. This is great for keeping components on a need-to-know basis about other components. I used this everywhere I could. The audio manager listens for many events to know when to play sound effects or new music. The game manager listens for events like the player's death. The cat makes heavy use of the messenger system by using heard messages to select which phases it plays. It was a really great concept that I hope to use in other projects going forwards.
As always, follow this link to see the GitHub repository. The Unity version is 2022.1.13f if you want to load up the project.
If you want to try the game, please see this link here for a compiled version. It is a little large, around 128MB when unzipped, but it should be runnable on any 32 or 64-bit system. Just unzip the file and find the executable named FinalProject.exe.
I have also recorded this video if you would just like to see the game in action. A single playthrough is about 4-5 minutes depending on how long it takes to kill the boss.
I hope you enjoyed this extra-long post. The next big project is already underway.