This section will show you how to add custom heartbeat VFX (visual effect) to your gameplay that gives away an unmoving prop’s location.
When players of the prop team are idle for too long, a heartbeat visual effect plays on that player, notifying the hunter team. This visual effect is registered to each player of the prop team as they spawn into the game.
You’ll use VFX Spawner devices along with Verse to implement the heartbeat functionality. This includes:
Activating the visual effects.
Teleporting the VFX Spawner to the players.
Creating a UI showing members of the prop team how long they have left to move before the heartbeat goes off.
This tutorial includes Verse snippets that show how to execute gameplay mechanics needed in this game. Follow the steps below and copy the full script on step 6 of this tutorial.
Before You Begin
It’s good practice to keep assets and devices organized in folders to make locating them easier. You can group devices by purpose, location, type, or however else you would like.
You can move placed assets to folders and actors you create.
In the gif above, the VFX Spawner device is being dragged into the prop team’s HeartBeatVFX folder for organization purposes. You can also right-click and select Move To to choose the folder you want the asset moved to.
Devices used:
~ 16 x VFX Spawners
VFX Spawner Device
Create a VFX spawner for each player. When a player needs the VFX, it will be teleported to the player's location. When no longer needed, it will be hidden until it is needed again.
The VFX Spawners in this template use Niagara VFX to make custom assets that show during gameplay. The VFX assets used in this tutorial are set to display a heartbeat to reveal unmoving players on the prop team. This VFX will appear over props that have been static for at least 15 seconds.
You can visit our documentation’s Visual Effects section for many tutorials on how to create heartbeat VFX. You can then use the custom heartbeat you created with the VFX Spawner.
You can try this when you place a VFX Spawner. From the Details panel, select your custom effect from the Custom Visual Effect dropdown menu. Make sure to enable Custom Visual Effect Override for the selected VFX to appear in the viewport.
From here, you can further customize your effect from the Details panel by adding color and deciding when the VFX will play and who it will be seen by.
Place this device in a location unseen by players and configure the User Options to match the table below. Then, copy and paste this device to match the number of players your gameplay allows.
| Option | Value | Explanation |
|---|---|---|
Custom Visual Effect | HeartBeatVFX | Defines a custom particle to use rather than one from the preset list. |
Custom Visual Effect Override | True | Determines whether to use developer FX. |
Enabled on Phase | Gameplay Only | Determines the game phases during which the device will be enabled. An enabled VFX Spawner will play its defined particle effect. |
Play Heartbeat Effects at a Location
Follow these steps to move the VFX Spawner device in Verse to play and stop the heartbeat effect on players of the prop team.
Create a new Verse file in your project called heartbeat.verse. This will not be a Verse device, so you can create it as an empty Verse file.
Start by double-clicking the Verse file you created to add the following Verse paths to import.
Verseusing { /Fortnite.com/Characters } using { /Fortnite.com/Devices } using { /Fortnite.com/UI } using { /UnrealEngine.com/Temporary/SpatialMath } using { /UnrealEngine.com/Temporary/Diagnostics } using { /UnrealEngine.com/Temporary/UI } using { /Verse.org/Colors } using { /Verse.org/Simulation }This code creates a class named
heartbeat_vfxin heartbeat.verse. Theheartbeat_vfxclass contains a struct of data to trackvfx_spawner_deviceobjects per player as well as the functions to set the VFX to a position or reset it.Verselog_heart_beat := class(log_channel){} # These messages are used to notify a prop agent with a message (or to hide it) when they need to move to avoid their heartbeat from becoming visible. HeartBeatWarningMessage<localizes>(Time:int):message = "Heart Beat in {Time} Seconds. Move!" HeartBeatWarningClear<localizes>:message = "" # This class exposes the editable properties for the heartbeat to the prop_hunt Verse device. heart_beat := class<concrete>(): Logger:log = log{Channel:=log_heart_beat} @editable # The number of seconds before a prop agent must move before the heartbeat reveals their position. MoveTime:float = 15.0 @editable # The seconds remaining before the heartbeat warning appears. Shouldn't be > than HeartBeatTimer.This code creates an
Activate()method in theheartbeat_vfxclass that takes a transform argument and moves the VFX Spawner device to thattransform.Verse# The heartbeat_vfx class contains a struct of data to track the VFX's root and vfx_spawner_device objects per player as well as the functions to set the VFX to a position or reset it. heartbeat_vfx := class<concrete>: @editable # The VFX device for each heart beat. VFXDevice:vfx_spawner_device = vfx_spawner_device{} # This offset is used to position the heartbeat above a prop agent's head. HeartBeatVFXOffset:vector3 = vector3{X := 0.0, Y := 0.0, Z := 110.0} # Sets the position of the heart beat VFX and then enables the VFX. Activate(Transform:transform):void = VFXPosition := Transform.Translation + HeartBeatVFXOffset if (VFXDevice.TeleportTo[VFXPosition, Transform.Rotation]):This code creates a
Deactivate()method in theheartbeat_vfxclass that disables the VFX Spawner device and therefore hides the heartbeat visuals.Verse# The heartbeat_vfx class contains a struct of data to track the VFX's root and vfx_spawner_device objects per player as well as the functions to set the VFX to a position or reset it. heartbeat_vfx := class<concrete>: @editable # The VFX device for each heart beat. VFXDevice:vfx_spawner_device = vfx_spawner_device{} # This offset is used to position the heartbeat above a prop agent's head. HeartBeatVFXOffset:vector3 = vector3{X := 0.0, Y := 0.0, Z := 110.0} # Sets the position of the heartbeat VFX and then enables the VFX. Activate(Transform:transform):void = VFXPosition := Transform.Translation + HeartBeatVFXOffset if (VFXDevice.TeleportTo[VFXPosition, Transform.Rotation]):
Display Heartbeat Warning to a Player
Follow these steps to set up a custom UI with a text block that will display the heartbeat warning message. See In-Game User Interfaces to learn more about creating custom UI and other Verse UI components.
The two constants below control the text that will be shown to players of the prop team at different times in the game.
The constant
HeartBeatWarningMessageis a function that takes anintand returns the typemessage. This type is used in UI elements because it can be localized. This is the text that players will see when they need to move to avoid their heartbeat effect revealing their position.The constant
HeartBeatWarningClearis an emptymessagethat will be shown so that players no longer see the warning message.Verse# These messages are used to notify a prop agent with a message (or to hide it) when they need to move to avoid their heartbeat from becoming visible. HeartBeatWarningMessage<localizes>(Time:int):message = "Heart Beat in {Time} Seconds. Move!" HeartBeatWarningClear<localizes>:message = ""
Create a new class named
heartbeat_warning_uiin heartbeat.verse. The heartbeat_warning_ui class contains a struct of data to track the UI canvas and text_block per player as well as the function to create a new heartbeat warning UI canvas.Verse# The heartbeat_warning_ui class contains a struct of data to track the UI canvas and text_block per player as well as the function to create a new heartbeat warning UI canvas. heartbeat_warning_ui := class: var Canvas:canvas = canvas{} var Text:text_block = text_block{} # Creates the UI canvas for the warning message. CreateCanvas():void = set Text = text_block{DefaultTextColor := NamedColors.White, DefaultShadowColor := NamedColors.Black} set Canvas = canvas: Slots := array: canvas_slot:
Manage Heartbeat Effects
Follow these steps to create the heartbeat manager.
The code below creates a class named
heart_beatin heartbeat.verse. This class exposes the editable properties for the heartbeat to the prop_hunt device and manages the heartbeat effects.Verselog_heart_beat := class(log_channel){} # This class exposes the editable properties for the heartbeat to the prop_hunt device. heart_beat := class<concrete>(): Logger:log = log{Channel:=log_heart_beat} @editable MoveTime:float = 15.0This code adds the following editable properties to the
heart_beatclass.This code controls the seconds before a prop agent must move before the heartbeat effect reveals its position.
Verse@editable MoveTime:float = 15.0This code controls the seconds remaining before words appear on screen to warn a prop team member and tell them to move before the heartbeat goes off.
Verse@editable WarningTime:float = 5.0This code is an array of heartbeat VFX devices. There is one per player.
Verse@editable AgentVFX:[]heartbeat_vfx = array{}In this code, the Radio Player device is used to play the heartbeat sound effects (SFX).
Verse@editable SFXPlayer:radio_device = radio_device{}
This code maps associates a UI for displaying the heartbeat warning to each prop agent.
Verse# This map associates a UI for displaying the heartbeat warning to each prop agent. var WarningUI:[agent]heartbeat_warning_ui = map{}This code keeps track of how many players have an active heartbeat so we can manage the SFX device.
Verse# Keeps track of how many players have an active heartbeat so we can manage the SFX device. var NumberOfHeartBeats:int = 0This code shows the warning UI for players.
Verse# Sets up heartbeat UI for the agent. SetUpUI(PropAgent:agent):void = if: not WarningUI[PropAgent] AsPlayer := player[PropAgent] PlayerUI := GetPlayerUI[AsPlayer] then: UIData:heartbeat_warning_ui = heartbeat_warning_ui{} UIData.CreateCanvas() PlayerUI.AddWidget(UIData.Canvas, player_ui_slot{ZOrder := 1})This code activates visual effects (VFX) and sound effects (SFX) for the specified player.
Verse# Activates the heartbeat VFX and SFX for the specified player. Enable(PropAgent:agent, HeartBeatVFXData:heartbeat_vfx):void = if: # Get the character, which is used to find the prop agent's position in the scene. Character := PropAgent.GetFortCharacter[] then: # Set the heartbeat VFX's position to the prop agent's position. HeartBeatVFXData.Activate(Character.GetTransform()) # Increment the heartbeat count, and if this is the first heartbeat playing, we need to play the audio to get it started. set NumberOfHeartBeats += 1This code creates a method to disable the VFX and SFX for one player, and another to disable it for all players.
Verse# Clears the heartbeat VFX and SFX for the specified prop agent. Disable(PropAgent:agent, HeartBeatVFXData:heartbeat_vfx):void = Logger.Print("Disabling heart beat.") # Deactivate the VFX visuals. HeartBeatVFXData.Deactivate() # Unregister the prop agent from the audio player device, causing the heartbeat audio to stop. SFXPlayer.Unregister(PropAgent) # Decrement the heartbeat counter. This counter should never drop below 0. set NumberOfHeartBeats -= 1 if (NumberOfHeartBeats < 0) then set NumberOfHeartBeats = 0