Build a Bullet Time Shooter in UE5

Build a third-person shooter with slow-motion bullet time and combo scoring.

Introduction

30 Second Summary

You know that feeling in action games when you hit slow motion and suddenly every shot feels perfectly timed? That cinematic power fantasy is called bullet time, and it's one of the most satisfying mechanics in gaming.

In this project, you will build a Total Overdose-inspired third-person shooter prototype in Unreal Engine 5 where you can activate slow motion, line up shots while the world crawls around you, and rack up combo multipliers for stylish kills.

What You'll Build

A playable bullet time shooter prototype built entirely in Blueprints, featuring hitscan shooting, slow-motion combat, enemy ragdolls, and a combo scoring HUD.

By the end of this project, you'll have:

  • A line trace shooting system with impact particles and fire rate control.
  • A bullet time system using Global Time Dilation and Custom Time Dilation so the world slows while your character stays responsive.
  • Enemy target Blueprints with a health system and ragdoll death physics.
  • A UMG HUD widget displaying score with a bullet time combo multiplier.
  • Secret Mission: Add a forward dive that launches your character through the air while automatically triggering bullet time for cinematic mid-air kills.

Are there any prerequisites?

This project assumes basic familiarity with UE5 editor navigation, the Third Person template, and Blueprint visual scripting. You should know how to navigate the Content Browser, open Blueprints, and connect nodes.

Set Up the Project and Input Actions

Every shooter needs a way to detect player intent. Before you can fire bullets or trigger slow motion, the engine has to know which buttons map to which actions.

In this step, you'll create a fresh project from the Third Person template and configure the Enhanced Input system with two new actions: one for shooting and one for activating bullet time.

In this step, get ready to:
  • Create a new project from the Third Person template.
  • Create Input Action assets for shooting and bullet time activation.
  • Verify the new inputs fire correctly in the Blueprint Event Graph.
Create a new Third Person project

The Third Person template gives you a movable character, a follow camera, and the Enhanced Input system already wired up. This saves you from building basic movement from scratch.

  • In the Epic Games Launcher, click Launch next to Unreal Engine 5.7.4.
  • In the Unreal Project Browser, select the Games category.
  • Select the Third Person template.
  • Set the project name to BulletTimeShooter (or any name you prefer).
  • Uncheck Starter Content if it is enabled. You won't need it for this project.
  • Click Create.

The editor opens with your new project. The viewport shows the default level with a platform, ramps, and the third-person character.

  • Click the green Play button in the top toolbar (or press Alt+P).
  • Move around with WASD and look around with the mouse.
  • Press Esc to stop the Play session.

You should see the character running around the level with the camera smoothly following behind.

Character not moving?

Make sure you clicked inside the viewport after pressing Play. The game window needs focus to receive keyboard input.

If the camera doesn't follow, confirm you selected the Third Person template (not First Person or Basic).

Help me troubleshoot my Third Person character not moving in Play mode.

Create and map the Input Actions

The Enhanced Input system works in two layers. Input Actions define what the player can do (shoot, activate bullet time). An Input Mapping Context connects those actions to physical keys.

  • In the Content Browser, navigate to Content/ThirdPerson/Input/Actions. This is where the template stores its existing Input Actions.
  • Right-click in the folder, hover over Input, and select Input Action.
  • Name it IA_Shoot.
  • Double-click IA_Shoot to open it. Confirm the Value Type is set to Digital (bool). Close the tab.
  • Right-click again in the same folder, select Input then Input Action.
  • Name this one IA_BulletTime.
  • Double-click IA_BulletTime to open it. Confirm the Value Type is set to Digital (bool). Close the tab.

Why Digital (bool)?

A Digital (bool) value type means the action is either happening or not. The player is either pressing the shoot button or they aren't. Movement uses Axis2D because it captures direction and magnitude, but our actions only need on/off.

Now you need to tell the engine which physical keys trigger these actions.

  • In the Content Browser, navigate up one level to Content/ThirdPerson/Input.
  • Double-click IMC_Default to open the Input Mapping Context.
  • Click the + button next to Mappings to add a new entry.
  • In the new mapping row, set the Input Action to IA_Shoot and the key to Left Mouse Button.
  • Click + again to add another mapping.
  • Set this mapping's Input Action to IA_BulletTime and the key to Q.
  • Save IMC_Default with Ctrl+S.

What is an Input Mapping Context?

An Input Mapping Context is a container that binds Input Actions to physical keys. The Third Person template already has IMC_Default loaded at runtime, which is why your existing WASD movement works. By adding your new actions here, they automatically become active when the game starts.

Can't find IMC_Default?

Make sure you're in Content/ThirdPerson/Input (the parent folder, not the Actions subfolder). If you still don't see it, use the Content Browser search bar and type IMC_Default.

Help me find the IMC_Default Input Mapping Context in my Third Person project.

Verify Input Actions in the Event Graph

The Input Actions exist and are mapped, but you need to confirm they actually fire when you press the keys. You'll wire up temporary debug messages in the character Blueprint to test this.

  • In the Content Browser, navigate to Content/ThirdPerson/Blueprints.
  • Double-click BP_ThirdPersonCharacter to open the Blueprint Editor.
  • Click the Event Graph tab to open the Event Graph.
  • Right-click on empty space in the graph and search for Enhanced Input Action.
  • Select IA_Shoot from the list. This creates an EnhancedInputAction node with Triggered and other execution pins.
  • Drag from the Triggered pin and add a Print String node. Set the string to Shoot Fired.
  • Right-click again in empty space and add another Enhanced Input Action node, this time selecting IA_BulletTime.
  • Drag from the Started pin and add a Print String node. Set the string to Bullet Time ON.
  • Drag from the Completed pin on the same node and add another Print String with the text Bullet Time OFF.
  • Click Compile (top-left of the Blueprint Editor) then Save.

What are Started, Triggered, and Completed?

These are trigger events on the Enhanced Input Action node. Started fires once when the key is first pressed. Triggered fires continuously while the key is held (for Digital actions, it fires each frame). Completed fires once when the key is released.

For shooting, you'll use Triggered because you want a response every time the button is pressed. For bullet time, Started/Completed lets you toggle the effect on and off with key press/release.

Time to test your work.

  • Click Play in the top toolbar.
  • Click the Left Mouse Button. You should see Shoot Fired appear in the top-left corner of the viewport.
  • Press and hold Q. You should see Bullet Time ON appear.
  • Release Q. You should see Bullet Time OFF appear.
  • Confirm the character still moves with WASD and the camera follows the mouse.
  • Press Esc to stop the Play session.

No debug text appearing?

Make sure you clicked Compile before pressing Play. Uncompiled Blueprints won't reflect your latest changes.

Check that your Enhanced Input Action nodes are connected to the Print String nodes. Look for a white wire running from the execution pin (Triggered/Started) to the Print String input pin.

Also verify that your mappings in IMC_Default are pointing to the correct actions and keys.

Help me debug why my Enhanced Input Actions aren't firing in UE5.

Once you've confirmed both actions fire correctly, remove the Print String nodes from the Event Graph. They were only for testing.

  • In BP_ThirdPersonCharacter, select each Print String node and press Delete.
  • Leave the Enhanced Input Action nodes in place. You'll connect real logic to them in the next steps.
  • Click Compile and Save.

✔️ Awesome, I've got everything!

Great. Make sure you've saved your Blueprint after removing the Print String nodes.

ⓧ I'd like to double check my setup

Here's what your project should look like at this point:

  • IA_Shoot exists in Content/ThirdPerson/Input/Actions with Value Type set to Digital (bool).
  • IA_BulletTime exists in the same folder with Value Type set to Digital (bool).
  • IMC_Default in Content/ThirdPerson/Input has two new mappings: IA_Shoot on Left Mouse Button and IA_BulletTime on Q. The original WASD and mouse-look mappings are still there.
  • BP_ThirdPersonCharacter Event Graph has Enhanced Input Action nodes for IA_Shoot (Triggered) and IA_BulletTime (Started/Completed). No Print String nodes remain.

Your input system is configured and ready. Next up, you'll connect real shooting logic to that IA_Shoot action using a line trace that detects what the camera is pointing at.

Implement Line Trace Shooting

Your inputs are wired up and ready to fire. Now it's time to make those button presses do something dangerous.

In this step, you'll build a shooting system using line trace hit detection. A line trace fires an invisible ray from the camera into the world and reports back what it hits. Think of it as an instant laser beam that checks for collisions along its path.

In this step, get ready to:
  • Set up a line trace from the camera that extends 10000 units into the world.
  • Spawn impact particles and apply physics impulses on hit.
  • Add a fire rate cooldown to prevent shot spamming.
Set up the line trace from the camera

A hitscan weapon (like a pistol) doesn't spawn a physical bullet. Instead, it checks instantly whether the aim direction hits anything. The LineTraceByChannel node does exactly this. It traces along the Visibility channel so it detects any object that blocks line of sight.

  • Open BP_ThirdPersonCharacter in the Blueprint Editor by double-clicking it in the Content Browser.
  • In the Event Graph, locate your IA_Shoot Triggered event node.
  • Drag in the Follow Camera component from the Components panel on the left. Hold Ctrl while dragging to create a reference node.
  • Drag off the Follow Camera node and add a Get World Location node. This gives you the camera's position in 3D space and serves as the trace start.
  • Drag off the Follow Camera node again and add a Get World Rotation node.
  • Drag off Get World Rotation and add a Get Forward Vector node. This returns the direction the camera is facing.
  • Drag off Get Forward Vector and add a Vector * Float node. Set the float value to 10000. This defines how far the trace extends (10000 units is roughly 100 meters).
  • Drag off the Get World Location return value and add a Vector + Vector node. Connect the output of the Vector * Float node into the second input. The result is your trace end point.
  • Right-click in the graph and search for LineTraceByChannel. Add it to the graph.
  • Connect the Get World Location output to the Start pin of LineTraceByChannel.
  • Connect the Vector + Vector output to the End pin.
  • Leave the Trace Channel set to Visibility (the default).
  • On the LineTraceByChannel node, click the Draw Debug Type dropdown and set it to For Duration. Set the duration to 0.5 seconds. This draws a visible red line in the viewport during testing.
  • Connect the IA_Shoot Triggered execution pin to the LineTraceByChannel execution input.

What does this setup do?

Every time you click the left mouse button, the Blueprint fires an invisible ray from the camera's position straight ahead for 10000 units.

The Visibility channel means the trace hits any object that blocks line of sight. The debug line (For Duration) lets you see exactly where the ray goes during testing so you can verify your aim.

  • Click Compile in the top-left toolbar of the Blueprint Editor, then click Save.
  • Press Play in the main editor toolbar. Click the left mouse button and look for a red debug line extending from the camera into the world.

Don't see a debug line?

Make sure the execution wire from IA_Shoot Triggered connects directly to the LineTraceByChannel node. A missing wire means the trace never fires.

Double-check that Draw Debug Type is set to For Duration and not None. With None selected, no visual line appears.

Help me debug why my line trace isn't showing a debug line.

Add impact effects on hit

The line trace tells you where the ray hits, but the player can't see that yet. You need visual feedback at the impact point and a physics push so objects react to being shot.

  • Drag off the Out Hit pin of the LineTraceByChannel node and add a Break Hit Result node.
  • From the LineTraceByChannel node, drag off the Return Value (boolean) pin and add a Branch node. Connect the execution output of LineTraceByChannel to the Branch input. The True pin fires only when the trace hits something.
  • From the True execution pin of the Branch, right-click and search for Spawn System at Location (under Niagara). Add it to the graph.
  • For the System Template input, select a spark or impact particle from the engine's built-in Niagara content. You can search for any basic impact system available in your project's content.
  • Connect the Impact Point output from the Break Hit Result node to the Location input of the Spawn System at Location node. This ensures the particle appears exactly where the bullet hits.
  • After the Spawn System at Location node, add an Add Impulse at Location node. This pushes physics objects when they get shot.
  • From the Break Hit Result node, drag the Hit Component output and connect it to the Target input of Add Impulse at Location.
  • Connect Impact Point from Break Hit Result to the Location input.
  • For the Impulse input, use the Get Forward Vector of the camera multiplied by a value between 500 and 1000. This determines how hard objects get pushed.

What does this do?

The Break Hit Result node gives you detailed collision data. Impact Point is the exact world-space location where the ray hit a surface.

Spawning particles at that point gives the player immediate visual feedback. The impulse force pushes physics-simulating objects away from the shot, making the world feel reactive.

  • Click Compile and Save.
  • Press Play and shoot at objects in the scene. You should see a spark particle spawn at the impact point. Any physics-enabled objects should get pushed by the impulse.

Particles not appearing on hit?

Confirm the Branch node's True pin connects to the Spawn System at Location node. If you connected to the False pin, particles only spawn when you miss.

If the particle system shows as None in the System Template dropdown, you may not have any Niagara systems in your project content. Right-click in the Content Browser, select FX > Niagara System, and create a basic system from a template.

Help me figure out why my impact particles aren't spawning on hit.

Add a fire rate cooldown

Without a cooldown, the weapon fires every single frame while the button is held. You need a gate that blocks shooting for a brief period after each shot.

  • In the My Blueprint panel on the left side of the Blueprint Editor, click the + button next to Variables to create a new variable.
  • Name the variable bCanShoot. Set its type to Boolean.
  • Click Compile so the variable initializes. Then in the Details panel on the right, check the Default Value checkbox to set it to true.
  • Between the IA_Shoot Triggered event and the LineTraceByChannel node, insert a Branch node. Drag bCanShoot from the Variables list into the graph and connect it to the Branch's Condition input.
  • Connect the IA_Shoot Triggered execution pin to this new Branch. Connect the True pin to your existing LineTraceByChannel logic.
  • Right after the Branch True pin fires (before or in parallel with the trace), add a Set bCanShoot node and set it to false. This blocks the next shot immediately.
  • After all your shooting logic completes (after the Spawn System and Add Impulse nodes), add a Delay node. Set the Duration to 0.15 seconds.
  • After the Delay node, add another Set bCanShoot node and set it to true. This re-enables shooting after the cooldown.

Why use a boolean gate with Delay?

The Delay node pauses execution for a set time without freezing the rest of your game. During that 0.15 seconds, bCanShoot stays false, so any additional clicks during the cooldown get blocked by the Branch node.

This gives you roughly 6-7 shots per second. Adjusting the delay value lets you tune the weapon's fire rate to feel right.

  • Click Compile and Save.
  • Press Play and rapidly click the left mouse button. You should notice the shots are spaced out evenly instead of firing every frame. The debug lines should appear at a steady rhythm.

Weapon only fires once and stops?

This means bCanShoot is being set to false but never back to true. Check that the Delay node connects to a second Set bCanShoot node that is checked (true). A missing final wire keeps the gate permanently closed.

Also verify the Delay node's Duration is 0.15 and not 0. A zero-second delay can sometimes behave unexpectedly in Blueprints.

Help me figure out why my weapon only fires once.

✔️ Awesome, I've got everything!

Great. Double check you've compiled and saved your Blueprint before moving on.

ⓧ I'd like to double check the full Blueprint

Here is the complete state of BP_ThirdPersonCharacter at the end of this step:

  • Variables: bCanShoot (Boolean, default true).
  • IA_Shoot Triggered event fires into a Branch node checking bCanShoot is true.
  • True path: Set bCanShoot to false.
  • LineTraceByChannel from the Follow Camera's world location. End = camera location + (Forward Vector * 10000). Trace Channel = Visibility. Draw Debug Type = For Duration (0.5 seconds).
  • Break Hit Result from the Out Hit pin.
  • Branch on the Return Value (hit = true).
  • On hit: Spawn Niagara impact particle at Impact Point. Add Impulse at Location on Hit Component (strength 500-1000).
  • Delay node (0.15 seconds) then Set bCanShoot back to true.
  • IA_BulletTime Started and Completed event nodes are present but have no logic yet.

Your weapon now fires instant rays, shows impact sparks, and respects a fire rate. Next up, you'll make time itself your weapon by building the bullet time system.

Build the Bullet Time System

Your shooting mechanic works. Click, trace, hit. But a bullet time shooter needs the moment between pulling the trigger and watching the bullet connect to feel like an eternity.

In this step, you'll build the signature slow-motion system. The trick is combining two time dilation values: one that slows the entire world to a crawl, and another that keeps your player moving at near-normal speed. The result is that cinematic feeling where you're a step ahead of everything around you.

In this step, get ready to:
  • Activate and deactivate bullet time using Global and Custom Time Dilation.
  • Build an energy meter that drains during slow motion and recharges when inactive.
  • Add a visual FOV indicator so you always know when bullet time is on.
Wire up the time dilation activation

Bullet time works by manipulating how fast time passes for different actors. Setting Global Time Dilation to 0.2 slows the entire world to 20% speed. Setting Custom Time Dilation on the player to 5.0 compensates: 0.2 multiplied by 5.0 equals 1.0 effective speed for your character.

  • Open BP_ThirdPersonCharacter in the Event Graph. Create a new boolean variable called bBulletTimeActive (default false).
  • Find the IA_BulletTime Started event node that already exists in your graph.
  • Drag off the Started execution pin and add a Set Global Time Dilation node. Set its Time Dilation value to 0.2.
  • From the Set Global Time Dilation output pin, add a Set Custom Time Dilation node. Set Target to Self and New Custom Time Dilation to 5.0.
  • After that, add a Set bBulletTimeActive node and check the box to set it to true.
  • Now find the IA_BulletTime Completed event node.
  • From the Completed pin, add a Set Global Time Dilation node with the value set to 1.0.
  • Chain a Set Custom Time Dilation node targeting Self with the value 1.0.
  • Add a Set bBulletTimeActive node and leave it unchecked (false).

Why two time dilation values?

Set Global Time Dilation affects every single actor in the world. If you only used that, your player would also move in slow motion and the controls would feel sluggish.

Custom Time Dilation is a per-actor multiplier applied on top of the global value. Setting it to 5.0 on the player means their effective speed is 0.2 x 5.0 = 1.0. The world crawls while you stay responsive.

  • Click Compile in the toolbar to save the Blueprint.
  • Press Play. Hold Q and watch particles or any moving objects slow dramatically. Your character should still move and aim at near-normal speed. Release Q and everything snaps back to full speed.

World doesn't slow down when you press Q?

  • Check that IA_BulletTime is mapped to the Q key in IMC_Default. Open the Input Mapping Context and verify the entry exists.
  • Make sure your Set Global Time Dilation node has the value 0.2, not 0. Setting it to 0 breaks engine logic and will not produce a visible slowdown.
  • Verify the execution wire goes from Started (not Completed) into the 0.2 node.

Help me debug my bullet time activation in UE5

Add the bullet time energy meter

Unlimited slow motion would be overpowered. A draining energy meter forces the player to use bullet time strategically, creating tension and rewarding precise timing.

  • In BP_ThirdPersonCharacter, create a new float variable called BulletTimeEnergy. Set its default value to 100.0.
  • In the Event Graph, find or add an Event Tick node.
  • From Event Tick, add a Branch node. Connect the Condition pin to a Get bBulletTimeActive node.
  • On the True branch (bullet time is active), calculate the drain amount: add a Get World Delta Seconds node, then divide it by a Get Global Time Dilation node. Multiply the result by 30.0 (the drain rate per real second).
  • Subtract that drain amount from BulletTimeEnergy using a Set BulletTimeEnergy node.
  • After the Set node, add another Branch that checks if BulletTimeEnergy is less than or equal to 0.
  • On True (energy depleted): duplicate the same deactivation logic from your Completed event. Set Global Time Dilation to 1.0, Set Custom Time Dilation on Self to 1.0, and Set bBulletTimeActive to false.
  • Back on the original Branch's False pin (bullet time not active): add a Get World Delta Seconds node, multiply by 15.0 (recharge rate per second), add that to BulletTimeEnergy, and clamp the result to a maximum of 100.0 using a Clamp (float) node before setting the variable.

Why divide by Global Time Dilation?

Get World Delta Seconds returns the dilated frame time. During bullet time at 0.2, each frame's delta is also scaled to 20% of real time. Dividing by the current Global Time Dilation (0.2) converts it back to real-world seconds.

This ensures energy drains at a consistent 30 units per real second regardless of whether bullet time is active. Without this correction, the meter would drain 5x slower during slow motion.

  • Click Compile to save the Blueprint.
  • Press Play. Hold Q and keep it held. After a few seconds, bullet time should automatically deactivate as the energy runs out. Release Q, wait a moment, then hold it again. The meter recharges and you can re-enter slow motion.

Bullet time never runs out?

  • Check that your Event Tick's True branch actually connects to the drain logic. A disconnected wire means the subtraction never happens.
  • Verify the division node divides Get World Delta Seconds by Get Global Time Dilation, not the other way around. Reversing them produces a tiny drain value.
  • Make sure the force-deactivation Branch checks <= 0, not == 0. Float subtraction rarely lands on exactly zero.

Help me debug my bullet time energy drain

Add a visual slow-motion indicator

Players need instant visual feedback that bullet time is on. A subtle camera FOV reduction creates a tunnel-vision effect that sells the slow-motion intensity.

  • In your IA_BulletTime Started chain (after setting bBulletTimeActive to true), get a reference to the Follow Camera component.
  • Add a Set Field of View node on the Follow Camera. For the value, get the current Field of View and subtract 5.0 from it.
  • In your IA_BulletTime Completed chain (after setting bBulletTimeActive to false), add a Set Field of View node that lerps the camera FOV back to its default value.
  • Do the same in the force-deactivation branch (when energy hits 0). The FOV should restore there as well.

What does reducing FOV do?

Lowering the field of view by 5 degrees narrows the camera slightly, creating a subtle zoom-in tunnel effect. It signals to the player that something is different without being distracting.

Lerping back on deactivation means the camera smoothly returns to normal rather than snapping, which feels more polished.

  • Click Compile to save the Blueprint.
  • Press Play. Hold Q and notice the camera narrows slightly. Release Q and watch it smoothly widen back to normal. Combine this with shooting: the world slows, the camera tightens, and your shots land with dramatic timing.

Don't see the FOV change?

  • Verify the Set Field of View node targets the Follow Camera component specifically, not the character or another component.
  • Make sure the subtraction is current FOV minus 5, not 5 minus current FOV. Reversing the operands gives a negative FOV which the engine ignores.
  • The 5-degree change is subtle. Try temporarily using 20.0 to confirm the logic works, then set it back to 5.0.

Help me debug my bullet time FOV effect

✔️ Awesome, I've got everything!

Great. Make sure you've compiled the Blueprint and all three systems (activation, energy drain, FOV indicator) are working together in Play mode.

ⓧ I'd like to double check the full Blueprint

Here is the complete state of BP_ThirdPersonCharacter at the end of this step:

Third Person Character Blueprint.

Variables:
- bCanShoot (bool, default true)
- BulletTimeEnergy (float, default 100.0, max 100.0)
- bBulletTimeActive (bool, default false)

Event Graph:

--- Shooting logic (unchanged from Step 2) ---
IA_Shoot Triggered → Branch (bCanShoot is true) → Set bCanShoot false →
LineTraceByChannel from camera (Visibility, ForDuration 0.5s debug) →
Break Hit Result → Branch (Return Value) →
On hit: spawn impact Niagara particle at Impact Point,
Add Impulse at Location on hit component (500-1000 strength) →
Delay (0.15s) → Set bCanShoot true.

--- Bullet Time Activation ---
IA_BulletTime Started → Set Global Time Dilation (0.2) →
Set Custom Time Dilation on Self (5.0) →
Set bBulletTimeActive true →
Reduce camera FOV by 5 degrees.

--- Bullet Time Deactivation ---
IA_BulletTime Completed → Set Global Time Dilation (1.0) →
Set Custom Time Dilation on Self (1.0) →
Set bBulletTimeActive false →
Lerp camera FOV back to default.

--- Energy System (Event Tick) ---
Event Tick → Branch (bBulletTimeActive)
  True: subtract 30 * (Get World Delta Seconds / Global Time Dilation)
         from BulletTimeEnergy;
         if BulletTimeEnergy <= 0, force-deactivate bullet time
         (same as Completed logic).
  False: add 15 * Get World Delta Seconds to BulletTimeEnergy
         (clamped to 100).

Your bullet time system is fully operational. You can slow the world to a crawl, stay responsive, and the energy meter keeps it balanced. Next up, you'll create enemies to actually shoot at during all this dramatic slow motion.

Create Enemy Targets with Ragdoll Death

You have a shooting system and a bullet time mechanic, but nothing to shoot at yet.

In this step, you'll create enemy target Blueprints that react to your shots. When an enemy's health hits zero, they'll ragdoll to the ground in satisfying physics-driven death. This is where the bullet time system really pays off. Watching enemies crumple in slow motion is what makes bullet time shooters feel cinematic.

In this step, get ready to:
  • Create an enemy Blueprint with a health system and damage event.
  • Add ragdoll death physics that trigger when health reaches zero.
  • Connect the shooting logic to deal damage to enemies and place targets in the level.
Create the BP_Enemy Blueprint with health

Every enemy in your game needs a health pool and a way to receive damage. You'll create a dedicated Character Blueprint that holds this logic.

  • In the Content Browser, right-click in an empty area.
  • Select Blueprint Class.
  • In the class picker, choose Character as the parent class.
  • Name the new Blueprint BP_Enemy.
  • Double-click BP_Enemy to open it in the Blueprint Editor.

Now add a visible body for the enemy using one of the built-in mannequin meshes.

  • In the Components panel, click Add and search for Skeletal Mesh.
  • Add a Skeletal Mesh component to the Blueprint.
  • With the Skeletal Mesh component selected, go to the Details panel.
  • Under Mesh, set the Skeletal Mesh Asset to SKM_Manny (or SKM_Quinn if you prefer).
  • Adjust the mesh's Z position so it aligns properly with the capsule component (feet at the bottom of the capsule).

What are SKM_Manny and SKM_Quinn?

These are the UE5 Mannequin skeletal meshes included with the Third Person template. SKM_Manny is the male variant and SKM_Quinn is the female variant.

They come with a full skeleton and Physics Asset already assigned, which is essential for the ragdoll system you'll add next.

Next, add the health variable and damage event.

  • In the My Blueprint panel on the left, click the + next to Variables.
  • Create a new variable named Health.
  • Set its type to Float in the Details panel.
  • Set the Default Value to 100.0 (click Compile first if the default value field is grayed out).

Now create the custom event that other Blueprints can call to deal damage.

  • Open the Event Graph tab.
  • Right-click in the graph and search for Add Custom Event.
  • Name the event ReceiveDamage.
  • In the Details panel for this event, click the + next to Inputs to add a parameter.
  • Name the input DamageAmount and set its type to Float.
  • From the ReceiveDamage event node, drag off and add a Set Health node.
  • For the value, subtract DamageAmount from the current Health using a Float subtraction node (Health - DamageAmount).
  • After Set Health, add a Branch node.
  • For the Branch condition, use a <= (less than or equal) node comparing Health to 0.

What does this event do?

The ReceiveDamage custom event is a function that any other Blueprint can call to hurt this enemy. It subtracts the incoming damage from the enemy's health pool.

The Branch checks if the enemy should die. You'll wire up the True pin (death logic) in the next substep.

  • Click Compile and Save the Blueprint.

Compile showing errors?

Make sure the Health variable type is set to Float, not Integer or Boolean. Check that the subtraction node's output is wired into the Set Health input pin, not directly into the Branch condition.

If the default value field for Health is grayed out, click Compile first, then set the default to 100.0.

Help me fix compile errors in my BP_Enemy Blueprint.

Add ragdoll death and the OnEnemyKilled dispatcher

Ragdoll physics make death feel physical and satisfying. When health hits zero, you'll enable physics simulation on the mesh so it collapses naturally under gravity.

  • In BP_Enemy's Event Graph, find the Branch node's True pin (this fires when Health <= 0).
  • Drag from True and add a Set Simulate Physics node.
  • Set the Target to your Skeletal Mesh component (drag it from the Components panel into the graph).
  • Check the Simulate checkbox to set it to true.
  • After Set Simulate Physics, add a Set Collision Enabled node targeting the same Skeletal Mesh component.
  • Set the New Type dropdown to Physics Only.
  • Add a Detach from Component node targeting the Skeletal Mesh component to detach it from the capsule.

Why detach the mesh from the capsule?

The Character class uses a capsule for movement collision. If you enable physics on the mesh without detaching it, the ragdoll will fight against the capsule's position and jitter instead of falling naturally.

Detaching lets the mesh collapse freely under gravity while the invisible capsule stays put.

Now add the Event Dispatcher and cleanup logic.

  • In the My Blueprint panel, click the + next to Event Dispatchers.
  • Name the new dispatcher OnEnemyKilled.
  • Back in the Event Graph, after the Detach node, drag OnEnemyKilled from the My Blueprint panel into the graph and select Call.
  • After the Call node, add a Delay node and set the duration to 3.0 seconds.
  • After the Delay, add a Destroy Actor node (targeting Self).

What is an Event Dispatcher?

An Event Dispatcher is a broadcast signal that other Blueprints can listen for. When you call OnEnemyKilled, any Blueprint that has bound to this dispatcher will receive the notification.

You'll use this in the next step to award combo points when an enemy dies during bullet time.

  • Click Compile and Save the Blueprint.

Your death sequence should flow: Set Simulate Physics > Set Collision Enabled (Physics Only) > Detach from Component > Call OnEnemyKilled > Delay (3s) > Destroy Actor.

Ragdoll not working in testing later?

Make sure the Skeletal Mesh has a valid Physics Asset assigned. The UE5 Mannequin meshes (SKM_Manny/SKM_Quinn) come with one by default, but if you see the mesh freeze in a T-pose instead of collapsing, check the Physics Asset field in the mesh component's Details panel.

Also confirm that Set Simulate Physics targets the Skeletal Mesh component specifically, not the Capsule Component.

Help me debug why my enemy ragdoll isn't working.

Connect shooting to enemies and place targets in the level

Your line trace currently hits anything in the world. You need it to recognize when it hits an enemy specifically, so it can call the damage event instead of just spawning a particle.

  • Open BP_ThirdPersonCharacter in the Blueprint Editor.
  • In the Event Graph, find your shooting logic after the line trace's Branch node (the one that checks Return Value = true, meaning something was hit).
  • From the Break Hit Result, drag off the Hit Actor pin.
  • Search for and add a Cast To BP_Enemy node.
  • Connect the hit Branch's True execution pin to the Cast To BP_Enemy node.

What does Cast To do?

A Cast node checks if an actor is a specific class. If the hit actor is a BP_Enemy, the cast succeeds and you get access to that enemy's variables and events.

If the hit actor is something else (a wall, a prop), the cast fails and execution flows through the Cast Failed pin instead.

  • From the Cast To BP_Enemy's success pin (As BP Enemy output), drag off and search for ReceiveDamage.
  • Add the ReceiveDamage call node.
  • Set the DamageAmount input to 50.0 (this means it takes 2 shots to kill an enemy with 100 health).
  • From the Cast's Cast Failed pin, connect your existing impact particle spawn and physics impulse logic.

Why move particles to Cast Failed?

Non-enemy objects (walls, props) should still show impact effects when shot. By putting the particle and impulse logic on the Cast Failed path, only non-enemy hits produce visual sparks.

Enemy hits go through the ReceiveDamage path instead, where death and ragdoll provide their own visual feedback.

  • Click Compile and Save BP_ThirdPersonCharacter.

Now place enemies around the level for target practice.

  • In the Content Browser, find BP_Enemy.
  • Drag 5 or 6 instances of BP_Enemy into the level viewport.
  • Spread them around the environment at different positions and distances from the player start.
  • Make sure each enemy is placed on the ground (hold End while the actor is selected to snap it to the floor).
  • Press Play to test.

Shoot an enemy twice with Left Mouse Button. It should ragdoll to the ground, then disappear after 3 seconds.

Shoot a non-enemy object (like a wall or prop) and you should still see the impact particle and physics impulse from before.

Test with bullet time for the full effect

Hold Q to activate bullet time, then shoot an enemy. Watch the ragdoll unfold in slow motion. This is where the cinematic feel of your prototype really comes through.

Enemies not taking damage?

Verify the Cast To BP_Enemy node is connected to the hit Branch's True pin, not to the Return Value pin directly. Also check that the Hit Actor pin from Break Hit Result is wired into the Cast's Object input.

If the line trace is hitting the enemy's capsule but the cast still fails, make sure you dragged BP_Enemy from the Content Browser as a Character Blueprint, not as a plain Actor.

Help me figure out why my Cast To BP_Enemy is failing.

✔️ Enemies ragdoll and disappear

Your combat system is working. Enemies take damage, ragdoll on death, and clean themselves up after 3 seconds.

ⓧ Something isn't working

Double-check the full node flow in both Blueprints below.

BP_Enemy Event Graph should flow:

  • ReceiveDamage (DamageAmount float input) > Set Health (Health - DamageAmount) > Branch (Health <= 0).
  • Branch True > Set Simulate Physics (Mesh, true) > Set Collision Enabled (Physics Only) > Detach from Component > Call OnEnemyKilled > Delay (3.0) > Destroy Actor.

BP_ThirdPersonCharacter shooting logic should flow:

  • LineTraceByChannel > Break Hit Result > Branch (Return Value true) > Cast To BP_Enemy (Object = Hit Actor).
  • Cast success > Call ReceiveDamage (DamageAmount = 50.0).
  • Cast Failed > Spawn impact particle and Apply Impulse (existing logic).

Your enemies now crumple satisfyingly when shot, especially in slow motion. Next up, you'll build a scoring system that rewards kills during bullet time with combo multipliers, displayed through a HUD widget.

Build the Combo Scoring HUD

You have enemies that ragdoll, bullets that impact, and a world that slows on command. The one missing piece is feedback.

Without a score on screen, the player has no reason to aim for stylish kills during slow motion. In this step, you'll build a UMG Widget HUD that displays a live score, a combo multiplier that rewards bullet time kills at 3x points, and an energy meter so the player knows how much slow motion they have left.

In this step, get ready to:
  • Create a UMG Widget Blueprint with Score, Combo Multiplier, and Energy text blocks.
  • Add scoring variables and integrate them with bullet time activation and enemy kills.
  • Bind the HUD text blocks to live gameplay data from the character Blueprint.
Create the WBP_HUD Widget Blueprint

UMG (Unreal Motion Graphics) is the engine's built-in UI system. You create a Widget Blueprint, lay out text and images on a 2D canvas, and then tell the game to display it on screen at runtime.

  • In the Content Browser, right-click in an empty area.
  • Select User Interface, then Widget Blueprint.
  • Name it WBP_HUD.
  • Double-click WBP_HUD to open the Widget Designer.

Now add the three text elements that make up your HUD.

  • From the Palette panel on the left, drag a Text widget onto the canvas. Position it in the top-right corner. This is your Score display.
  • In the Details panel, set the font size large (around 36-48) so the score stands out. Name the widget Score in the hierarchy.
  • Drag a second Text widget onto the canvas. Position it centered at the top. This displays the Combo Multiplier (e.g., "x3.0") during bullet time. Name it ComboMultiplier.
  • Drag a third Text widget onto the canvas. Position it in the top-left corner. This shows Bullet Time Energy as a percentage. Name it BulletTimeEnergy.
  • Use the Anchors dropdown for each text block to pin them to their respective corners. This prevents them from drifting at different screen resolutions.

What are anchors?

Anchors lock a widget to a specific spot relative to the screen edges. A text block anchored to the top-right stays in the top-right regardless of whether the player is on a 1080p or 4K monitor.

Next, add this widget to the player's screen at runtime.

  • Open BP_ThirdPersonCharacter and switch to the Event Graph.
  • Find the Event BeginPlay node (or add one if it doesn't exist).
  • Drag off the execution pin and add a Create Widget node. Set the Class dropdown to WBP_HUD.
  • From the Create Widget return value, drag off and add an Add to Viewport node.
  • Compile and save BP_ThirdPersonCharacter.

Press Play. You should see placeholder text in the top-left, top-center, and top-right of your screen. The values won't update yet, but the HUD is displaying.

Don't see the HUD text on screen?

Make sure the Class on your Create Widget node is set to WBP_HUD and not left as None. Also check that the execution wire runs from Event BeginPlay through Create Widget into Add to Viewport in sequence.

If the text exists but is invisible, open WBP_HUD and check each text block's color in the Details panel. White text on a bright scene can be hard to read. Try a darker color temporarily.

Still stuck? Help me troubleshoot why my WBP_HUD widget isn't appearing on screen in UE5.

Add scoring variables and connect them to gameplay

The HUD is on screen, but it needs data to display. You'll create score and multiplier variables in the character Blueprint, then wire them into your existing bullet time and enemy kill logic.

  • In BP_ThirdPersonCharacter, open the My Blueprint panel on the left.
  • Click the + button next to Variables to create a new variable. Name it Score, set its type to Integer, and set the default value to 0.
  • Create another variable called ComboMultiplier, set its type to Float, and set the default value to 1.0.

Why start the multiplier at 1.0?

A multiplier of 1.0 means "normal points" (100 x 1.0 = 100). When bullet time activates, it jumps to 3.0 (100 x 3.0 = 300). This way you never need to check whether the multiplier is active before calculating the score. The math always works.

Now connect the combo multiplier to your bullet time activation logic.

  • Find your IA_BulletTime Started event in the Event Graph (where you set Global Time Dilation to 0.2).
  • After your existing bullet time activation nodes, add a Set ComboMultiplier node with a value of 3.0.
  • Find your IA_BulletTime Completed event (where you set Global Time Dilation back to 1.0).
  • After your existing deactivation nodes, add a Set ComboMultiplier node with a value of 1.0.

Also add Set ComboMultiplier to 1.0 in your energy-depleted auto-deactivation path (where BulletTimeEnergy hits 0). This ensures the multiplier resets no matter how bullet time ends.

Next, bind to the enemy kill event so your score increases when enemies die.

  • In the shooting logic section of your Event Graph, find where you successfully cast to BP_Enemy and call ReceiveDamage.
  • From the Cast To BP_Enemy output (the As BP_Enemy pin), drag off and add a Bind Event to OnEnemyKilled node. This subscribes to the enemy's death event.
  • Create a custom event for the binding (click the + on the red Event pin). Name it something like OnEnemyDied.
  • From your OnEnemyDied custom event: get ComboMultiplier, multiply it by 100 (integer), and add the result to Score using a Set Score node (Score = Score + 100 * ComboMultiplier).

What does binding to an Event Dispatcher do?

An Event Dispatcher is like a radio broadcast. BP_Enemy broadcasts "I died" through OnEnemyKilled. By binding to it, BP_ThirdPersonCharacter is tuning in. Whenever any bound enemy dies, your OnEnemyDied custom event fires automatically.

  • Compile and save BP_ThirdPersonCharacter.

Score not increasing when enemies die?

The most common cause is binding the dispatcher after the enemy is already dead. Make sure the Bind Event to OnEnemyKilled node fires when you first shoot the enemy (on cast success), not after ReceiveDamage. The bind must happen before the kill occurs.

Also check that your custom event (OnEnemyDied) is wired to the score calculation nodes. An unconnected custom event does nothing.

Need help? Help me debug my Event Dispatcher binding for enemy kills.

Bind the HUD text to live gameplay data

The variables exist and update during gameplay, but the HUD text blocks are still showing placeholder values. You need to create bindings so each text block reads the latest value every frame.

  • Open WBP_HUD and switch to the Designer tab.
  • Select the Score text block. In the Details panel, find the Text property and click Bind > Create Binding. This creates a function that runs every frame to supply the text value.
  • Inside the binding function graph: add a Get Player Character node, then a Cast to BP_ThirdPersonCharacter node.
  • From the cast output, get the Score variable. Connect it to a To Text (Int) node, then wire it to the Return Value pin.

Now create the binding for the Combo Multiplier text.

  • Return to the Designer tab. Select the ComboMultiplier text block.
  • Click Bind > Create Binding on the Text property.
  • In the function: Get Player Character, Cast to BP_ThirdPersonCharacter, get the ComboMultiplier variable. Use a Format Text node with the format string x{0} to display it as "x3.0". Wire to the Return Value.
  • For visibility: select the ComboMultiplier text block, find the Visibility property in Details, and click Bind > Create Binding. In this function, get ComboMultiplier from the character. If it is greater than 1.0, return Visible. Otherwise return Hidden.

Finally, bind the energy display.

  • Return to the Designer tab. Select the BulletTimeEnergy text block.
  • Click Bind > Create Binding on the Text property.
  • In the function: Get Player Character, Cast to BP_ThirdPersonCharacter, get BulletTimeEnergy. Divide it by 100 and multiply by 100 to get the percentage (it's already 0-100, so format it as an integer). Use a Format Text node with {0}% to display it with a percent sign. Wire to the Return Value.
  • Compile and save WBP_HUD.

What does Create Binding do under the hood?

Each binding generates a small function that UE5 calls every frame to ask "what should this text show right now?" The function reaches into BP_ThirdPersonCharacter, grabs the latest value, formats it, and returns it as text. It's simple but effective for a HUD with a handful of values.

Press Play and test the full system. You should see the energy percentage in the top-left draining when you hold Q. The combo multiplier text ("x3.0") appears in the top-center only during bullet time. Kill an enemy normally and your score jumps by 100. Kill an enemy during bullet time and it jumps by 300.

HUD shows 0 or doesn't update?

Check that each binding function's Cast to BP_ThirdPersonCharacter node has its execution pin connected. A disconnected cast means the function returns an empty value every frame.

If the score stays at 0 even when killing enemies, verify that the OnEnemyDied custom event's Set Score node uses the formula Score + (100 * ComboMultiplier), not just 100.

Need help? Help me fix my UMG widget bindings that aren't updating.

✔️ Awesome, I've got everything!

Great. Make sure you've compiled and saved both WBP_HUD and BP_ThirdPersonCharacter before moving on.

ⓧ I'd like to double check the full setup

Here is the complete state of each Blueprint at the end of this step.

BP_ThirdPersonCharacter:

  • Variables: bCanShoot (bool, default true), BulletTimeEnergy (float, default 100.0), bBulletTimeActive (bool, default false), Score (int, default 0), ComboMultiplier (float, default 1.0).
  • Bullet time activation (IA_BulletTime Started): sets Global Time Dilation to 0.2, Custom Time Dilation on Self to 5.0, ComboMultiplier to 3.0.
  • Bullet time deactivation (IA_BulletTime Completed or energy depleted): sets Global Time Dilation to 1.0, Custom Time Dilation to 1.0, ComboMultiplier to 1.0.
  • OnEnemyKilled binding: Score += 100 * ComboMultiplier.
  • Begin Play: Create Widget (WBP_HUD) → Add to Viewport.

WBP_HUD:

  • Score text (top-right, large): Text bound to Get Player Character → Cast to BP_ThirdPersonCharacter → Score, formatted as integer.
  • ComboMultiplier text (centered-top): Text bound to ComboMultiplier formatted as "x3.0". Visibility bound to return Hidden when ComboMultiplier is less than or equal to 1.0.
  • BulletTimeEnergy text (top-left): Text bound to BulletTimeEnergy formatted as a percentage with "%" suffix.

BP_Enemy:

  • Unchanged from the previous step. Health (float, default 100.0), ReceiveDamage event, ragdoll death, OnEnemyKilled Event Dispatcher, 3-second Delay then Destroy Actor.

Secret mission

The Signature Dive

Total Overdose's most iconic move was the forward dive. You launch yourself through the air while the world goes into slow motion, lining up shots mid-flight. In this mission, you'll recreate that move by combining Launch Character with automatic bullet time activation and a bonus x5 scoring multiplier for stylish airborne kills.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally on your machine. There are no cloud services, subscriptions, or ongoing costs.

Decide whether to keep your project files, close the editor to free up memory, or delete everything entirely.

Resources you used:

  • Unreal Engine 5 project folder (contains all Blueprints, assets, Input Actions, widget, and level data).

Keep everything running

No action needed. Choose this if you want to keep iterating on your bullet time shooter prototype.

  • Your project folder stays on disk at no cost.
  • You can reopen the project anytime from the Epic Games Launcher or directly from the .uproject file.

Pause - I'll come back to this later

Close the Unreal Engine editor to free up system memory and GPU resources. Your project files remain on disk for when you return.

  • Save all open assets in the editor by pressing Ctrl+Shift+S (Windows) or Cmd+Shift+S (macOS).
  • Close the Unreal Engine editor.
  • Your project folder stays on disk and can be reopened anytime.

Delete - I don't want to use this again

Remove all project files from your machine. This cannot be undone.

  • Close the Unreal Engine editor if it is still open.
  • Open Finder (macOS) or File Explorer (Windows).
  • Navigate to the folder where you saved your UE5 project.
  • Delete the entire project folder (the folder containing the .uproject file and all its subfolders).
  • Empty your Trash (macOS) or Recycle Bin (Windows) to reclaim disk space.

That's a Wrap!

That's a Wrap!

Nice work! You just built a playable bullet time shooter prototype entirely in Blueprints, capturing the cinematic arcade feel of Total Overdose's slow-motion gunplay.

You've learned how to:

  • Build a third-person shooting system using line trace hit detection with impact particles, physics impulse, and fire rate control.
  • Implement a bullet time system combining Set Global Time Dilation (0.2) with Set Custom Time Dilation (5.0) on the player for slow-motion gameplay that keeps the player responsive.
  • Create a combo scoring system with a UMG Widget HUD that displays score, energy, and a 3x multiplier rewarding stylish bullet time kills.
  • Secret Mission: Added the signature dive move that launches the player forward while auto-triggering bullet time for cinematic mid-air kills with a 5x multiplier.

Ready to quiz yourself?