Environmental hazards play a big role in shaping gameplay. By using hazards and traps, you add consequences for the player and escalate the difficulty and tension as they progress through a puzzle or level.
In this part of the tutorial series, you’ll create a spike trap and a fire trap that can damage the player. Then you’ll connect your fire trap and switch gameplay objects to create a new gameplay mechanic and puzzle.
Now that the player can take damage and lose all their health, you’ll also set up a fail condition that ends and restarts the game, giving players the chance to try again.
Before You Begin
Make sure you understand these topics covered in previous sections of Design a Puzzle Adventure:
Blueprint basics like variables, functions, event graphs, and adding nodes.
Using blueprint interface events to make a switch toggle another gameplay object.
You’ll need the following assets from Create a Key and Puzzles: Switches and Cubes:
M_BasicColorMaterial andM_BasicColor_RedMaterial InstanceBPI_InteractionBlueprint InterfaceBP_SwitchBlueprint Class
Build a Set of Related Blueprint Classes
Throughout this tutorial series, you’ve encountered Unreal Engine assets that use parent-child relationships and inheritance. Inheritance means creating a new child class that reuses and extends the features of an existing parent class. The child class can expand upon those features without altering the parent. Inheritance saves you time by reusing useful features across many assets instead of manually adding them to each new asset.
Your Material Instance assets inherit features from their parent Materials. In many of your blueprints, you created components that inherit transform data from a parent component.
Games use different types of hazards, but they often share the same core features. A parent trap blueprint can define those shared features, while each child trap blueprint extends those features, adding different visuals and behaviors.
Your base (parent) trap needs to detect player overlap and use the damage game mechanic to decrease player health over time. Then, you’ll create (or subclass) child traps to extend the base trap’s features and add additional visuals or behaviors. The spike trap adds additional static meshes to its appearance, and the fire trap adds a fire effect and behavior that makes it toggle on and off.
Your level is still in the blockout stage, so focus on creating a simplified version of each trap that still informs the future visual design.
Create the Base Trap Blueprint
First, create the base trap blueprint class as a parent of and foundation for your specialized traps.
To create a blueprint that defines common trap features, follow these steps:
In the Content Browser, go to the Content > AdventureGame > Designer > Blueprints folder, and create a new folder named
Traps.In the Traps folder, right-click or click Add, and create a new Blueprint Class.
In the
Pick Parent Classwindow, click Actor.Name this class
BP_TrapBaseand open it.
Add Components
For the base trap, you’ll create a blockout-style static mesh to show the trap’s boundaries. All traps also need a collision volume to know when the player steps on them.
To create the physical components of the base trap, follow these steps:
In the Components tab, click Add, and search for and add a Cube static mesh shape.
Name the mesh component
TrapBase.In the Details panel under Transform, change the cube’s Scale to
2,2,0.1to create a flat square base.In the Components tab, with TrapBase selected, click Add, and search for and select a Box Collision component.
Name the collision component
TrapTrigger. This is the collision volume you’ll use to detect when the player is standing on the trap.Just like with
BP_Switch, you’re attaching the collision component to the mesh, so if you want to change the size of the trap, the trigger area automatically adjusts.In the Details panel under Transform, change the following properties to create a large collision box above the base mesh:
Set Location to
0,0,400.Set Scale to
1.5,1.5,12.
Add Variables
All traps also need editable properties that let you customize:
If the hazard is active or inactive.
The damage the trap does to the player.
The damage interval, or time between hits.
And, the trap needs to know who collided with it.
To add common properties to the base trap, follow these steps:
In the My Blueprint tab, create the following variables:
Variable Name
Type
Category
Default Value
Active
Boolean
Setup
True
BaseDamage
Float
Setup
5.0
DamageInterval
Float
Setup
1.0
After creating a variable, compile your blueprint to add a default value.
Click each variable’s eye icon so the eye is open, making all three variables editable and public.
Add a variable named
OtherActorand change the type to Actor (Object Reference).
Create a Function to Apply Damage
Now that your trap has its base properties, you can start creating the trap’s behavior. All traps should lower the player’s hit points (HP) at a regular interval when the player overlaps the collision volume.
Unreal Engine has built-in solutions for many common gameplay mechanics, including applying and receiving damage.
For the trap, you’ll use the built-in Apply Damage function node. To organize the damage-handling logic, you’ll create your own function that calls Apply Damage on all characters touching the trap if the trap is active.
To create a function that applies trap damage to the player, follow these steps:
In the Functions section, click Add. Name this function
fnApplyDamageToTargetsand open its graph.You only want to apply damage if the trap is turned on and active, so add a Branch node where the Condition is a reference (Get) to the Active variable.
Later in this tutorial, you’ll add some NPC enemies, so it’s possible that many actors could be on the trap at once. So, when the trap is active, loop through an array of all actors touching the trap:
Connect the Branch node’s True pin to a For Each Loop node.
For the loop’s Array input, you need to create an array of all overlapping actors. Unreal Engine does this for you — add a Get Overlapping Actors (TrapTrigger) node. The node comes with a reference to TrapTrigger as its Target.
In the Get Overlapping Actors node, change the Class Filter to Character so player and NPC characters can be added to the array.
For each array element, or each iteration of the loop, apply the amount of damage set in the BaseDamage variable to the actor in that array element. To do this, connect an Apply Damage node to the Loop Body.
The Apply Damage function comes from the Unreal Engine Game Statics library. The icon in the top-right corner means the function can be used in networked games and can run on the server.
Set up the Apply Damage node:
For the Damaged Actor pin, connect the loop’s Array Element.
For the Base Damage pin, connect a reference to the BaseDamage variable.
6. Save and Compile your blueprint.
Your complete fnApplyDamageToTarget function should look like the following:
If you copy and paste this snippet into the corresponding graph in your project, connect the function entry node to the Branch node.
Create a Timer That Applies Damage Over Time
Next, you need to make the trap call the apply-damage function at regular time intervals. To do this, you’ll use one of Unreal Engine’s timer functions to create a timer.
In this blueprint, you’ll use Set Timer by Function Name:
This node creates a timer and binds a function to that timer so that when the timer expires, the node calls the function, executing all the actions in that function.
To set up a timer when the game starts, follow these steps:
Go to
BP_TrapBase’s EventGraph tab. Delete the provided Event ActorBeginOverlap and Event Tick nodes.Before the trap performs any actions, you want to check if it’s active. From the Event BeginPlay node, add a Branch node where the Condition is a reference to the Active variable.
From the Branch node’s True pin, create a Set Timer by Function Name node.
Set up the timer node:
For the Time pin, connect a reference to the DamageInterval variable.
Click the text box next to Function Name, and enter
fnApplyDamageToTarget.Ensure you’ve spelled the function name correctly or the logic won’t execute properly.
Enable Looping.
Set Timer nodes output a return value called a Timer Handle that acts like a tracking number or controller for the timer. To stop, pause, or resume the timer, you’ll reference this timer handle, so save it in a new variable:
In the My Blueprint panel, create a new variable named
TimerHandler. Change its type to Timer Handle.Add a Set Timer Handler node and connect it to Set Timer by Event’s return value and exec pins.
When Unreal Engine creates a timer, it starts running immediately, so you need to pause the timer until a character steps on the trap. Connect a Pause Timer by Handle node and give it your TimerHandler.
Save and Compile your blueprint.
You can also create timers with a Set Timer by Event node. Here, you’d use the node actions list to Add Custom Event and use it as a delegate to bind actions to the timer.
Custom events are reusable, named blocks of logic similar to functions. Unlike functions, they can contain delays, timeline nodes, and other latent actions — so you may need to use this method as your game grows in complexity.
Connect an event’s square delegate pin to pass a reference of that event to the timer node. This isn’t triggering the event, but instead storing the event and its actions for later (when the time interval expires).
Start and Stop Damage
You’ve created and paused the damage timer so it’s ready and waiting. Now, make the damage resume when a character steps on the trap’s collision volume, and pause the damage when characters stop overlapping the volume.
To add logic that starts the damage, follow these steps:
In the Components panel, right-click the TrapTrigger component, go to Add Event, and select Add OnComponentBeginOverlap.
After the event, connect a Set Other Actor node to save the overlapping actor in the variable.
Connect the event and Set node’s Other Actor pins.
Connect an fnApplyDamageToTarget node so the character receives damage immediately when touching the trap.
Connect an Unpause Timer by Handle node to resume the timer and damage intervals. For its Handle input, connect a reference to the TimerHandler variable.
To add logic that stops the damage over time, follow these steps:
Right-click the TrapTrigger component, go to Add Event > On Component End Overlap.
After the event, connect a Pause Timer by Handle node, again giving it a reference to TimerHandler.
Save and Compile your blueprint.
The trap now creates, starts, and pauses a damage timer.
The finished BP_TrapBase event graph should look like the following:
For more information about timers and timer management, see Gameplay Timers.
Test the Base Trap
To test the trap, add a Print String message that reports on-screen when the trap applies damage.
To print a message on screen that shows the trap is working as intended, follow these steps:
In
BP_TrapBase, go to the fnApplyDamageToTarget tab.In the function’s graph, connect a Print String node after the Apply Damage node.
Change the In String to
Player hit!Click the arrow at the bottom of the Print String node to show more options, and change the Duration to
5. This makes it easier to see the damage hits over time.Compile and Save the blueprint. In the Content Browser, drag an instance of
BP_TrapBaseinto your level.Play the level and step on the trap. A new “Player hit!” message should appear every second.
Subclass a Spike Trap
Now that you’ve completed your parent class, it’s time to start subclassing!
First, you’ll create a spike trap that modifies the base trap’s appearance, adding some shape language. A plain flat trap doesn’t look dangerous, but the player will interpret a spikey object as something that could hurt them.
To create a spike trap, follow these steps:
In the Content Browser, in the Traps folder, right-click
BP_TrapBaseand select Create Child Blueprint Class.Name the blueprint class
BP_TrapSpikesand open it.In the Components tab, with DefaultSceneRoot selected, click Add, and search for and select Cone.
You’ll resize and position the cones to fit four rows of four cones each (or 16 in total).
In the cone’s Details panel, in the Transform section, change the following properties:
Change the Location to
-75,-75,25.Change the Scale to
0.5,0.5,0.4.
Now there’s a smaller spike in the corner of the base mesh.
For some visual contrast, in the Materials section, use the dropdown menu to change the cone’s material to
M_BasicColor_Red.Select and duplicate (Ctrl + D) the cone three times, translating each cone over by 50 units so they line up in a row across one side of the base mesh.
Hold Ctrl to select all four cones and duplicate them. In the Components panel, select the four new cones (they’ll have the largest number suffixes), and move them over 50 units. Repeat this two more times to create a 4x4 grid of cones.
The slopes and angles in the spikes could make it awkward for the player to move off the trap. To prevent the player from landing between the spikes, add an invisible floor at the top of the spikes:
In the Components tab, duplicate the TrapBase mesh and name it
InvisFloor.Move the floor up so only the tips of the spikes are visible above the floor.
In the Details panel, in the Collision section, ensure Collision Presets is set to BlockAllDynamic. This blocks all actors from passing through the mesh.
In the Rendering section, disable Visible. This hides the mesh in the viewports and during gameplay.
In the Components tab, select the TrapBase mesh. In the Details panel, in the Rendering section, enable Hidden in Game. This keeps the mesh visible in viewports, but hides it during gameplay, so you’ll only see the spikes.
Save and Compile your blueprint.
The spike trap subclass has all the behavior of your base trap, so it also prints the “Player hit!” messages when the trap is working. Drag an instance of BP_TrapSpikes into your level and test it out!
Subclass a Fire Trap
Next, you’ll create a trap that extends the base trap’s behavior. A fire trap adds a hazard that the player can turn off with a switch, which is a gameplay mechanic you can turn into a new puzzle.
In Puzzles: Switches and Cubes, you created the BPI_Interaction blueprint interface that a switch can use to turn other gameplay objects on and off. You can also use this interface in a trap blueprint so a switch can change the trap’s Active variable during gameplay.
First, you’ll need a new material to use when the trap is deactivated.
To create a black material for the fire trap, follow these steps:
In the Content Browser, go to the AdventureGame > Designer > Materials folder.
Right-click
M_BasicColorand select Create Material Instance.Name the material instance
M_BasicColor_Blackand open it.Expand Global Vector Parameter Values, enable Color, and click the color swatch to change it to dark grey (Hex sRGB =
3D3B3BFF). This looks better in-game than pure black.Save and close the material instance.
To subclass a fire trap, follow these steps:
In the Content Browser, right-click
BP_TrapBaseand select Create Child Blueprint Class.Name the blueprint
BP_TrapFireand open it.Change the base mesh's color to make it represent a fire trap. Select the TrapBase component and, in the Details panel, in the Materials section, change the material to
M_BasicColor_Red.Above the viewport, click Class Settings.
In the Details panel, in the Interfaces section, next to Implemented Interfaces, click Add, and search for and select
BPI_Interaction.In the My Blueprint panel, the fnBPISwitchOff and fnBPISwitchOn event functions appear in the Interfaces section.
Just like with
BP_Switch, set up customizable materials for the fire trap:In the Variables section of the My Blueprint panel, create two variables named
OffMaterialandOnMaterial.Change their type to Material Interface (Object Reference).
Click their eye icons to make them public and editable.
Change their Category to Setup.
Compile and set the following default values:
OffMaterial:
M_BaseColor_BlackOnMaterial:
M_BaseColor_Red
Save and Compile the blueprint so you can use the interface events in the trap’s event graph.
Extend the Trap's Behavior
Just like when you made the moving platform in Puzzles: Moving Platforms, you need to set up the trap’s event graph to take the following actions when a switch calls fnBPISwitchOn and fnBPISwitchOff:
Activate or deactivate the trap.
Change the trap’s material.
With the moving platform, you needed the platform to start moving when the player activates the switch. For the trap, you need the opposite — the trap is active when the level starts and should turn off when the player activates the switch.
To add logic that deactivates fire traps when the player presses a switch, follow these steps:
Go to the fire trap’s EventGraph tab. In the My Blueprint panel, in the Interfaces list, double-click fnBPIButtonOn to add an event node to the graph.
BP_TrapBasevariables don’t appear in the My Blueprint panel, but you can access them with the node actions list. Drag off the Event fnBPISwitchOn node’s exec pin, search foractive variable, and select Set Active. Keep Active disabled.After the Set node, connect a Set Material (TrapBase) node (in the Rendering > Material section of the actions list).
In the Set Material node, connect a reference to the OffMaterial variable to the Material pin.
To add logic that activates fire traps if a switch is deactivated, follow these steps:
In the Interfaces section, double-click Event fnBPISwitchOff to add that node.
After the event, connect a Set Active variable node, but this time enable Active.
After the Set node, connect a Set Material (TrapBase) node and connect a reference to OnMaterial.
Save and Compile your blueprint.
Your complete fire trap event graph should look like the following:
Add an instance of BP_TrapFire to your level and give it a try!
Update the HUD With Player HP
Time to replace those Print String nodes with some real feedback for the player. You’ll change your HUD to report the player’s HP in real time.
Add an HP Variable to the HUD
To add dynamic player health to your HUD, follow these steps:
In the Content Browser, open your
WBP_PlayerHUDwidget blueprint. Ensure you’re in Designer view.In the Hierarchy, click the txtHP widget. In the Details panel, enable Is Variable and delete 100 from the Text property.
Go to the Graph view and set up a new function that sets the value of txtHP:
In the Functions section, add a new function named fnSetHP.
With the function selected, in the Details panel, click + next to Inputs.
Name the input
NewHPand change its type to Float.Later, you’ll change the player character to call this function when they take damage.
In the fnSetHP function’s graph, after the function entry node, connect a SetText (Text) node.
If you can’t find a node in the node actions list, disable Context Sensitive.
Set up the SetText (Text) node:
For the Target, connect a reference to the txtHP variable. This is the text widget that displays the player’s health.
For the In Text, connect the function entry node’s New HP input pin. Unreal Engine automatically adds a To Text (Float) node to convert the value.
Save and Compile the widget blueprint.
The complete fnSetHP function’s graph looks like the following:
If you copy this blueprint snippet into your graph, you need to connect the function entry node to the SetText and To Text nodes.
Display the Player’s Starting HP
Set up any available HUD variables before displaying them. In this case, you know the player’s starting HP, so you can display that information when the game starts.
To update the player character blueprint to display their HP on the HUD, follow these steps:
In the Content Browser, open your
BP_AdventureCharacterblueprint. In the event graph, find the Event Possessed logic.In the My Blueprint panel, expand Graphs > EventGraph and double-click Event Possessed to focus on it in the graph.
In between the Set node and Add to Viewport node, connect a fnSetHP node:
For the Target, use the Set node’s output pin to make the HUD the target.
For New HP, connect a reference to the player’s Health variable.
Ensure the Add to Viewport node’s Target pin also connects to a HUD variable node.
In the My Blueprint panel, click the Health variable. In the Details panel, change (or keep) the default value. This tutorial uses 100 starting hit points.
Save and Compile.
The player’s new Event Possessed logic should look like the following:
If copying this logic into your project, first delete the existing Event Possessed logic group.
Now, the HUD displays the player’s health when the game starts. The last piece of logic you need is to update the HUD when the player is damaged. To do this, you’ll modify the character’s existing damage-handling logic to work with your HUD.
Update the Player’s HP After Taking Damage
To handle damage to the player, follow these steps:
In the bottom-left corner of
BP_AdventureCharacter’s event graph, find the section of logic labelled “Damage and death handling” that starts with an Event AnyDamage node. You’re going to modify this section to execute your own logic instead.Delete all nodes that come after the Branch node. Keep the Branch node.
This section of logic uses operator nodes to perform calculations. When the character receives damage, the Event AnyDamage node triggers, passing information about the damage dealt, the type of damage, and the controller and actor that instigated the damage. Next, the damage is subtracted from the character’s Health variable. Once the health is subtracted, the Branch node checks if the player’s health has reached 0.
For now, you want to build logic that updates the HUD when the player’s health is greater than 0. So, from the False pin, connect an FnSetHP node to send the new health value to the HUD.
Set up the fnSetHP node:
For the Target, connect a reference to the character’s HUD variable.
For the New HP input, connect a reference to the Health variable.
Save and Compile your blueprint.
Now the HUD displays the player’s current health and updates that health value when the player takes damage.
Go back to your BP_TrapBase blueprint and delete any Print String nodes you added to the base trap’s event graph.
Play your game again and test it out!
Create a Fail and Respawn Condition
When the player runs out of health and is eliminated, you’ll want to stop the game and give them a chance to try again. In this tutorial, you’ll disable the player’s controls, communicate to the player that they’ve lost the game, and load the level.
First, you’ll create a game-over widget blueprint that tells the player they have been eliminated.
Add a Game-Over Screen
To create a widget blueprint for your game-over screen, follow these steps:
In the Content Browser, in the AdventureGame > Designer > Blueprints > Widgets folder, right-click, go to User Interface, and select Widget Blueprint.
In the Pick Parent Class window, click User Widget.
Name the widget blueprint
WBP_EliminatedScreenand open it.
To set up the game-over UI, follow these steps:
In the Palette tab, search for canvas and drag a Canvas Panel onto [WBP_EliminatedScreen] in the Hierarchy. Just like with your HUD, the canvas is your root widget.
The canvas will have a game-over message layered over a blur effect that makes the text easier to read. From the Palette tab, drag an Overlay to become a child of the canvas.
With the overlay selected, in the Details panel, in the Slot (Canvas Panel Slot) section, expand Anchors, and change both Maximum values (X and Y) to
1.The other Slot properties (below Anchors) change to Offset settings.
When you built the HUD, you kept all anchor points in one corner so if the screen size changed, those objects stay anchored to the anchor point. Now, the overlay is anchored to the entire canvas bounding box, so the overlay shrinks or stretches to match the screen size.
When you changed the anchor settings, the editor changed some offset values to maintain the overlay panel’s default shape. To remove this, change Offset Right and Offset Bottom to
0. Now the overlay fills the screen.From the Palette tab, drag a Background Blur widget to become a child of the Overlay panel.
With the blur effect selected, in the Details panel, in the Slot (Overlay Slot) section, change:
Horizontal Alignment to Fill Horizontally.
Vertical Alignment to Fill Vertically.
In the Appearance section, change Blur Strength to
5.From the Palette tab, add a Text widget as a child of the Overlay.
With the Text widget selected, in the Details panel, in the Slot (Overlay Slot) section, change:
Horizontal Alignment to Center Align Horizontally.
Vertical Alignment to Center Align Vertically.
In the Content section, change the Text to
You are eliminated…restarting the level.In the Appearance section, make the text larger and easier to read by configuring the following properties:
Click the color swatch next to Color and Opacity, and pick a color for your text. This tutorial uses pink (Color Hex sRGB =
FF4D7AFF).Expand the Font header, and change Size to
60.Expand Font > Outline Settings, and change Outline Size to
1.
12. Save and Compile your blueprint.
Build Logic for a Fail Condition
Now that you have a game-over screen, you can modify the character class to display it when the player runs out of HP. When this happens, execution passes through the True result of that Branch node you were working with earlier.
To handle player defeat, you’ll need to:
Disable player input so the player can’t move.
Show the game-over screen.
Restart the level after a set amount of time.
To stop and load the game when the player is eliminated, follow these steps:
In
BP_AdventurePlayer, go back to the damage-handling logic (beginning with Event AnyDamage) in your character blueprint.After the Branch node’s True execution pin, connect a Do Once node and Disable Input node.
The player can continue to get hit after they run out of health, so the Do Once node ensures that the logic after it only executes once.
For the Disable Input node’s Player Controller pin, connect a Get Player Controller node (in the Game > Player section of the node actions list).
There are a few nodes named Get Player Controller. Ensure the node has a Player Index input pin. An index of 0 is the default index for the first player character spawned into the level.
After disabling the player controller, create and display the game-over screen:
Connect a Create Widget node. In the node, change the Class to
WBP_EliminatedScreen.Connect the widget node’s exec and Return Value pins to an Add to Viewport node.
Add a time delay, get the current level name, and then load that level:
After the Add to Viewport node, connect a Delay node and change the Duration to
5seconds.After the Delay, connect a Get Current Level Name node.
After Get Current Level Name, connect an Open Level (by Name) node.
Connect the Return Value pin to the Level Name pin. The editor automatically adds a string-to-name conversion node.
Save and Compile your player blueprint.
This section of the BP_AdventureCharacter event graph should now look like the following:
If copying this logic into your project, delete the existing Damage handling group of nodes (including Event AnyDamage and Event Destroyed logic) first.
Play your level to test it out. Step on a trap, let your character lose all their HP, and make sure the game resets as intended.
Add Hazards to Your Puzzles
In Puzzles: Switches and Cubes, you learned about designing gameplay mechanics that add difficulty, tension, consequences, and risk-reward decisions. Environmental hazards that damage the player are one mechanic that introduces these consequences. You can use the spike traps to add danger and additional consequences to earlier puzzles and obstacles in the level, and switch-powered fire traps can create more dynamic puzzles that make the player interact with the environment to reveal safe paths.
When designing games, a key part of reducing overhead and improving development speed is finding multiple different ways to use and combine gameplay objects. In a previous section of this tutorial series, the switch powered platforms to create a path forward. Here, the same switch can disable fire traps to reveal a path for the player. This adds variety to the level without needing an endless number of unique systems.
Similar to the door-and-key game mechanic you created earlier in this tutorial series, your fire trap becomes another mechanic to manage the player's pacing and access to the environment.
Create a Maze Puzzle with Fire Traps
In Room 2, you’ll combine switches and fire traps to build a maze puzzle where the player must carefully disable hazards to discover and collect the last key.
It often helps to sketch puzzles on paper first. Since the traps are 1m x 1m, our sample Room 2 can fit a 7 x 9 grid of traps. Start by drawing a path through the grid that ends at the key. Then, divide the path up into segments and place switches to control each segment.
To add difficulty and create more reveals and surprises, add architectural features that block sightlines. For example, place switches behind walls or pillars so the player has to discover them along the path.
This looping path gives the player a glance at the key so they discover the goal while traversing the first segment of the path.
With your plan complete, start blocking out the puzzle in the level editor.
Once you create the path to the key and new blockout shapes, fill in the rest of the room with fire traps to obscure the correct route.
Rename your level objects in the Outliner so it’s clear which fire traps each switch controls. For example, if BP_Switch1 turns off three traps, name them BP_FireTrap_S1_0, BP_FireTrap_S1_1, and BP_FireTrap_S1_2. Rename the extra fire traps something like BP_FireTrap_Extra to show they aren’t part of the puzzle.
If desired, you can help the player exit when they complete the puzzle by adding a final switch under the key that disables some traps along the way out.
Test your puzzle often, paying attention to sightlines, frustration points, and possible shortcuts. Recruit a friend to help; they may find loopholes you didn’t expect. During playtesting, you may realize you need to make adjustments to stop or deter the player from skipping parts of the puzzle.
If you do discover an exploit, you have a couple of options:
Rearrange the path or puzzle.
Add more architectural blockers.
Increase the fire damage so straying off the path has harsher consequences.
Leaving an exploit but increasing the cost gives the player a choice and autonomy. They can choose between spending more time to reveal the safe path or sacrificing their HP to rush to the key.
In the sample level’s puzzle, we added some rubble under the archway to the key so the player can see the key, but can’t skip directly to it. We also hid the switches not only for some rewarding reveals, but also to prevent skipping that part of the path.
Add Spikes to Past Obstacles
Let’s add spikes to past puzzles to add consequences for falling
Start with Room 1’s puzzle. For the first moving platform, keep the stakes low so if the player falls, they just climb back up and try again. When you introduce a new mechanic, give the player room to learn in a safe space so they can focus on learning
Similarly, in the Start Room, you can add some spikes to the pit under the first key. The player can practice jumping on the first two platforms to prepare them for the final, riskier jump over to the key. Now, grabbing the first key unscathed becomes a bit more exciting.
Once the player understands the basics and has some practice moving blocks on platforms and switches, it’s time to add consequences. Under the second platform or third button, place some spike traps. Now you’ve raised the tension since the player takes damage if they fall, but they can quickly move off the trap to minimize that damage and continue.
Finally, for the last platform and switch, keep raising the danger. Cover the area below with spikes so they have to run further to get out of the spikes and therefore take more damage. At this point, the player should be more competent with the mechanic, and the consequence for mistakes feels fairer because they’ve already practiced.
This design follows this popular structure for introducing gameplay mechanics to players:
Introduce: The first platform teaches the game mechanic safely.
Develop: The second platform and cube tests the player’s growing skill with moderate risk.
Twist: The final platform escalates the danger and adds a new direction of movement, turning the mechanic into a tense challenge.
Like you learned in the Gameplay Design lesson in Puzzles: Moving Platforms, by ramping up the consequences across the puzzle, you balance fairness and excitement.
Change a Trap’s Damage
You may decide to change the difficulty level by increasing or decreasing the damage of one type of trap. You could do this in one of two ways:
In the Outliner, search for “spike” or “fire”, and select all traps of that type. In the Details panel, change Setup > Base Damage as desired. With this method, you’d need to remember to also change the Base Damage of any new instances of that trap you add to your level. Or, add new trap instances to the level by duplicating existing traps to avoid having to edit each new instance.
OR
Open one of your child trap blueprints and go to its Construction Script tab. You can’t edit inherited variables in the My Blueprint panel, but you can set variables in the graph. After the two Construction Script nodes, connect a Set Base Damage node. In the node, change the Base Damage value as desired.
To ensure your gameplay objects are predictable for the player, ensure all traps of one type deal the same damage.
In the tutorial’s sample level, fire traps do 5 damage per second, and spike trap instances are modified to do 10 damage per second.
Try the Sample Level
If you’d like to use pieces of the room designed in this part of the tutorial instead of creating your own, copy the snippets below.
Room 2’s Blockout
This text snippet contains Room 2’s floor, walls, and the new blockout shapes added to create this room’s puzzle. In the Outliner, all shapes are in a folder named Room2.
Begin Map
Begin Level
Begin Actor Class=/Script/Engine.TextRenderActor Name=TextRenderActor_19 Archetype="/Script/Engine.TextRenderActor'/Script/Engine.Default__TextRenderActor'" ExportPath="/Script/Engine.TextRenderActor'/Game/AdventureGame/Designer/Lvl_Adventure.Lvl_Adventure:PersistentLevel.TextRenderActor_19'"
Begin Object Class=/Script/Engine.TextRenderComponent Name="NewTextRenderComponent" Archetype="/Script/Engine.TextRenderComponent'/Script/Engine.Default__TextRenderActor:NewTextRenderComponent'" ExportPath="/Script/Engine.TextRenderComponent'/Game/AdventureGame/Designer/Lvl_Adventure.Lvl_Adventure:PersistentLevel.TextRenderActor_19.NewTextRenderComponent'"
End Object
Begin Object Class=/Script/Engine.BillboardComponent Name="Sprite" Archetype="/Script/Engine.BillboardComponent'/Script/Engine.Default__TextRenderActor:Sprite'" ExportPath="/Script/Engine.BillboardComponent'/Game/AdventureGame/Designer/Lvl_Adventure.Lvl_Adventure:PersistentLevel.TextRenderActor_19.Sprite'"
End Object
Begin Object Name="NewTextRenderComponent" ExportPath="/Script/Engine.TextRenderComponent'/Game/AdventureGame/Designer/Lvl_Adventure.Lvl_Adventure:PersistentLevel.TextRenderActor_19.NewTextRenderComponent'"
Text=NSLOCTEXT("[3C535F7772EB3B3657484B5E2D5B925D]", "2347F80B407C68C27836E990A20143CF", "Room 2")
HorizontalAlignment=EHTA_Center
To copy all of Room 2’s blockout, follow these steps:
Remove anything already in Room 2 (or anything at the end of Hallway 2):
Use the Outliner to select the existing contents of Room 2: Right-click the
Room2folder, and select Select > Immediate Children. Press Delete.Or, switch the viewport to Top orthographic view to select and delete the existing room manually.
Click Copy Full Snippet.
In Unreal Editor, ensure the viewport is the active panel (click anywhere in the viewport or Outliner and press Esc), and then press Ctrl + V.
Your level and Outliner should look like the following:
Room 2’s Switches, Traps, and Key
This text snippet contains the puzzle’s switches, traps, and red key. In the Outliner, all objects are in a folder named Room2.
To copy blueprint instances between projects, the parent blueprint assets must be completely identical and have the same file names and locations. If you’ve changed the blueprint’s components, variable names, or properties in your project, the snippet may not copy as expected, and you’ll need to set up these level objects manually.
Begin Map
Begin Level
Begin Actor Class=/Game/AdventureGame/Designer/Blueprints/Traps/BP_TrapFire.BP_TrapFire_C Name=BP_FireTrap_C_261 Archetype="/Game/AdventureGame/Designer/Blueprints/Traps/BP_TrapFire.BP_TrapFire_C'/Game/AdventureGame/Designer/Blueprints/Traps/BP_TrapFire.Default__BP_TrapFire_C'" ExportPath="/Game/AdventureGame/Designer/Blueprints/Traps/BP_TrapFire.BP_TrapFire_C'/Game/AdventureGame/Designer/Lvl_Adventure.Lvl_Adventure:PersistentLevel.BP_FireTrap_C_261'"
Begin Object Class=/Script/Engine.SceneComponent Name="DefaultSceneRoot" Archetype="/Script/Engine.SceneComponent'/Game/AdventureGame/Designer/Blueprints/Traps/BP_TrapFire.BP_TrapFire_C:ICH-DefaultSceneRoot_GEN_VARIABLE'" ExportPath="/Script/Engine.SceneComponent'/Game/AdventureGame/Designer/Lvl_Adventure.Lvl_Adventure:PersistentLevel.BP_FireTrap_C_261.DefaultSceneRoot'"
End Object
Begin Object Class=/Script/Engine.StaticMeshComponent Name="TrapBase" Archetype="/Script/Engine.StaticMeshComponent'/Game/AdventureGame/Designer/Blueprints/Traps/BP_TrapFire.BP_TrapFire_C:TrapBase_GEN_VARIABLE'" ExportPath="/Script/Engine.StaticMeshComponent'/Game/AdventureGame/Designer/Lvl_Adventure.Lvl_Adventure:PersistentLevel.BP_FireTrap_C_261.TrapBase'"
End Object
Begin Object Class=/Script/Engine.BoxComponent Name="TrapTrigger" Archetype="/Script/Engine.BoxComponent'/Game/AdventureGame/Designer/Blueprints/Traps/BP_TrapFire.BP_TrapFire_C:TrapTrigger_GEN_VARIABLE'" ExportPath="/Script/Engine.BoxComponent'/Game/AdventureGame/Designer/Lvl_Adventure.Lvl_Adventure:PersistentLevel.BP_FireTrap_C_261.TrapTrigger'"
End Object
Begin Object Name="DefaultSceneRoot" ExportPath="/Script/Engine.SceneComponent'/Game/AdventureGame/Designer/Lvl_Adventure.Lvl_Adventure:PersistentLevel.BP_FireTrap_C_261.DefaultSceneRoot'"
To set up the puzzle’s blueprint pieces, follow these steps:
Click Copy Full Snippet.
In Unreal Editor, ensure the viewport or Outliner is the active panel, and press Ctrl + V.
Check each switch's Setup properties and, if necessary, reconnect each switch to its fire traps:
In the Outliner, in the
Room2folder, clickBP_Switch4.In the Details panel, in the Setup section, expand the Interact Object List.
For each element in the list, click the dropdown, search for
S4, and select one of theS4-labelled fire traps.Repeat these steps for each switch:
BP_Switch5triggersBP_FireTrap_S5_0-7BP_Switch6triggersBP_FireTrap_S6_0-3BP_Switch7triggersBP_FireTrap_S7_0-4BP_Switch8triggersBP_FireTrap_S8_0-3BP_Switch9, under the key, triggersBP_FireTrap_S9_0-4
Your level and Outliner should look like the following:
Next Up
Next, you’ll learn how to add another popular hazard to your game — enemy NPCs! Learn how to create an AI enemy character and add Navigation Mesh to your level so the enemies can find and damage the player.
Create an Enemy
Build game logic to create Enemy Characters that deal and receive damage.