BadBot
Short gameplay cinematic for the project 🎥
Play BadBot (Windows)
How to install & play
- Download the ZIP file using the button below.
- Right-click the file and choose “Extract All…”.
- Open the extracted folder and run BadBotLauncher.exe.
- If Windows shows a warning, click “More info” → “Run anyway”.
What is BadBot?
The game is simple. Score points by flying through rings and destroying enemies. Make it to the finish without dying and win the game.
Initially BadBot was part of a course I took to learn more about working with Blueprints in Unreal Engine.
I decided to take the foundation the course laid and build on it.
This took the form of implementing new features and improving existing ones.


Game Logic
All the logic in BadBot is done using the visual scripting tool in Unreal Engine called Blueprints.
I have chosen to do this because the project is simple in scope.
However, even with the simplicity of the project, I learned a valuable lesson about how rapidly small features can spaghettify everything when you attempt to expand upon them.
The player (bad bot)
The bad bot (player) is a sphere mesh with guns, a texture for the body and a texture for the glass.
A camera has been attached with a spring arm. Camera lag has been enabled in order to provide more of a flying sensation when controlling the pawn.
A FloatingPawnMovement-component is used to control the speed of the player pawn.


Player input
All responses to player input are handled via the enhanced input system.
The player is able to move and look using the mouse and keyboard. Because it is a flying shooter game, it utilizes all three axes. This allows for continuous vertical and horizontal movement.
Additionally, the player can fire the drone’s guns by holding down or repeatedly pressing the left mouse button.
These input actions are all bound to a mapping context, which, via custom events, fires the logic when they are pressed.
IMMA FIRIN MAH LAZOR
The projectile used by both the player and enemy is a separate blueprint. It consists of a static mesh (beam mesh) and a projectile movement component.
When fired by the player, it performs a line trace as seen in the image.
The line trace starts from the center of the camera (the crosshair) and follows its forward vector until a blocking hit or the end of the trace distance.
The trace distance has been set in order to avoid projectiles flying infinitely, should they be fired on a trajectory where no blocking objects exist.


Enemy drones
Based on the player mesh, the original enemy is an identical drone with different logic.
To find the player it stores all actors of the pawn class, in a variable called targetPawn.
Since BadBot is a prototype and only one pawn exists in the level, this works. If I were to expand the game, I would create a unique class for the player which the enemy would then track.
After storing the target pawn the enemy then rotates, moves and starts firing towards the player after a random delay set by a variable. This delay is set to avoid all the enemies firing in the same rhythm when they spawn in.
Variation
Introducing variation to the game, I have created child blueprint classes from the original enemy and blaster beam.
I have made use of material instances to tweak the body, emissive, and glass color of the enemy variants as well as the blaster beams they fire.
Being an avid gamer myself, I have experienced how some studios think a recolor is enough variation in gameplay, which is frustrating as a player. Therefore all the enemy variants have different behaviors and methods of combat that the player must deal with.
For example the light grey bot is a sniper bot. It slowly charges up its shots, but the projectile speed is faster, meaning it can hit the player from further away. Its damage is also significantly higher.


Spawning enemies
Initially I created a spawner that used an array of target points to spawn a specific class at the locations of the target points when the player overlaps the spawner.
However, while making enemy variants, I ran into the issue of not being able to spawn more than one class per spawner.
I solved this problem by making a struct. In this struct were references to bot class, target point and number of enemies. The spawner logic then looped through the array of items, which could be set per instance of bot spawner.
This resulted in the ability to add as many target points as needed per bot spawner, as well as deciding which target points should spawn what type of enemy and how many.
Score Ring
As with the enemy spawner in the section above, the score ring also works with an overlap event.
The score ring in the GIF is just one example. A box collision is attached to the ring. When the player overlaps with that box a custom event casts to from the ring to the player to increase the score.
It then plays a sound and a particle effect, after which it destroys itself and disables the collision on the box to avoid repeat performances.
Sinusoidal movement was added for aesthetic flair.


Damage
For dealing damage I used an interface, as I was familiar with it from a previous project.
The interface is utilized in three classes; the blaster beam, the enemy and the player.
When the blaster beam hits an actor, it informs the interface of the amount of damage it dealt, as well as which actor it hit.
If an enemy is hit by a blaster beam, it utilizes the interface event from which it reads the damage to the hit actor and then reduces the enemy’s health by that amount. If the enemy health reaches 0, it explodes and is destroyed.
The same goes for the player, except the level restarts when the player dies.
Player HUD
For the player HUD I used a widget blueprint. It consists of three parts; the score, the health bar and the pause button.
The score updates with enemy kills and ring-fly-throughs. It does so with an animation of the score amount floating up towards the score text and then adding itself to the total. Additionally it plays different sounds based on the source from which the score originates.
The health bar decreases when taking damage and increases when gaining health. It is clamped between 0 and 100 health. For better user experience it flashes and shakes slightly when taking damage.
I built a pause menu, which the player can access by pressing “Escape”. This menu displays the controls and allows for restarting the level or quitting the game.


Additional UI’s
Along with the player HUD, I created some additional UIs that appear at different times for a better player experience.
When the game starts, the player is informed of the controls with a UI that disappears once they press one of the control keys.
At the first enemy spawn, the game pauses and tells the player to fire by either holding down and or clicking the left mouse button. This is also shown with a mouse, where the LMB is highlighted. When the player presses the button, the UI disappears, and the player starts firing.
The pause menu is opened and closed by pressing “Escape” and displays controls, as well as allowing for restarting or quitting the game.
Finally, the finish screen displays when the player completes the level. It shows the total score, plays different music, and allows for restarting or quitting of the game.
