BadBot

Short gameplay cinematic for the project 🎥

Play BadBot (Windows)

How to install & play

  1. Download the ZIP file using the button below.
  2. Right-click the file and choose “Extract All…”.
  3. Open the extracted folder and run BadBotLauncher.exe.
  4. 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.

futuristic drone fighting other drones in a canyon
image of blueprints almost spaghetty'ing in UE5

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.

drone controlled by the player being edited
photo of blueprint logic in ue5 controlling enhanced input

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.

image showcasing a line trace in editor
image of one futuristic drone facing down another

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.

image showcasing both enemy and blasterbeam variants in badbot
image divided in 4 pieces showing blueprint logic for spawning enemies

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.

robot flying through ring, scoring points
image divided in 4 pieces showing blueprint logic for dealing damage

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.

image showing player hud in badbot
image divided in 4 pieces showing different UI's

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.