Wow… so I’ve just started following the tutorial properly and its actually not that great is it. It’s outdated, missing references/devices, inconsistant formatting in the code snippets. Not great for new people trying to learn, which is pretty much everyone…
First of all, the tutorial creates a logger but doesn’t declare the indentifier for it.
# Unknown identifier `log_search_and_destroy`.
Logger: log = log { Channel := log_search_and_destroy }
So it needs this before the creative device
class declaration.
log_search_and_destroy := class(log_channel){}
The next thing is on the OnBegin
method, the race conditions will error for 3 reasons.
The first being that TimedObjectiveA
and TimedObjectiveB
are both trying to call StartedEvent
, which doesn’t exist on the timed_objective_device
, it’s BeganEvent
.
ArmingPlayer := TimedObjectiveA.StartedEvent.Await()
# Unknown member `StartedEvent` in `timed_objective_device`.
The same goes for the StoppedEvent
, that should be EndedEvent
instead.
DisarmingPlayer := TimedObjectiveA.StoppedEvent.Await()
# Unknown member `StoppedEvent` in `timed_objective_device`.
Which that then also caused the race
condition to be invalid as no Async method was expressed in the condition.
Expected async expression(s) (such as a coroutine or concurrency primitive) and only found immediate expression(s) (such as an immediate function call).
The next thing is the tutorial doesn’t even mention to add beacon_devices
to the world for the BombABeaconArm
, BombABeaconDisarm
, BombBBeaconArm
and BombBBeaconDisarm
.
They are included in the Verse Detonation Template
that comes with UEFN, but the tutorial only tells you to reference them within the Verse device, it doesn’t have a section on setting them up. It doesn’t even mention them in the list of devices you’re going to use at the start of the tutorial.
This tutorial uses the following devices:
8 x Explosive
2 x Timed Objectives
4 x Map Indicators
1 x End Game
~ x Player Spawn Pad
1 x Verse
So it’s not very helpful if you’re not using the template, which why would you if the tutorial tells you not too.
So you have to add those yourself, and it doesn’t even tell you how to configure them properly so you’ll need to copy them over from the Verse Detonation Template
and paste them into your project and place them above their respective bomb sites.
But after following the tutorial, and making all those changes above, I’ve got a working game with the following script:
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Logs
log_search_and_destroy := class (log_channel) {}
# Types
bomb_state<public> := enum { AllUnarmed, BombAArmed, BombBArmed }
# Creative device
search_and_destroy := class (creative_device) {
Logger: log = log { Channel := log_search_and_destroy }
@editable
BombAMapIndicators: []map_indicator_device = array {}
@editable
BombABeaconArm: beacon_device = beacon_device {}
@editable
BombABeaconDisarm: beacon_device = beacon_device {}
@editable
BombBMapIndicators: []map_indicator_device = array {}
@editable
BombBBeaconArm: beacon_device = beacon_device {}
@editable
BombBBeaconDisarm: beacon_device = beacon_device {}
@editable
ExplosiveBarrelsA: []explosive_device = array {}
@editable
ExplosiveBarrelsB: []explosive_device = array {}
@editable
TimedObjectiveA: timed_objective_device = timed_objective_device {}
@editable
TimedObjectiveB: timed_objective_device = timed_objective_device {}
@editable
EndGameDevice: end_game_device = end_game_device {}
# Set the initial bomb state to all bombs unarmed
var BombState: bomb_state = bomb_state.AllUnarmed
# Runs when the device is started in a running game
# @return {void}
OnBegin<override>()<suspends>: void = {
# Start a race to check which bomb is armed first
race {
# Wait for bomb a to be armed
block {
# Set the player who armed bomb a
ArmingPlayer := TimedObjectiveA.BeganEvent.Await()
Print("Bomb A Armed", ?Duration := 5.0)
# Set the bomb state to bomb a armed
set BombState = bomb_state.BombAArmed
# Disable the other timed objective
TimedObjectiveB.Disable(ArmingPlayer)
# Iterate through all of the map indicators for bomb b
for (MapIndicator: BombBMapIndicators) {
# Disable map indicator for bomb b
MapIndicator.Disable()
}
}
# Wait for bomb b to be armed
block {
# Set the player who armed bomb b
ArmingPlayer := TimedObjectiveB.BeganEvent.Await()
Print("Bomb B Armed", ?Duration := 5.0)
# Set the bomb state to bomb b armed
set BombState = bomb_state.BombBArmed
# Disable the other timed objective
TimedObjectiveA.Disable(ArmingPlayer)
# Iterate through all of the map indicators for bomb a
for (MapIndicator: BombAMapIndicators) {
# Disable map indicator for bomb a
MapIndicator.Disable()
}
}
}
# Set the correct beacons to be enabled
UpdateBeacons()
# Start a race to check if a timed objective is completed or stopped
race {
# Wait for bomb a to be detonated
block {
# Detonate bomb a
BombDetonated(TimedObjectiveA.CompletedEvent.Await())
}
# Wait for bomb b to be detonated
block {
# Detonate bomb b
BombDetonated(TimedObjectiveB.CompletedEvent.Await())
}
# Wait for bomb a to be disarmed
block {
# Set the player who disarmed bomb a
DisarmingPlayer := TimedObjectiveA.EndedEvent.Await()
Print("Bomb Disarmed", ?Duration := 5.0)
# Activate the end game
EndGameDevice.Activate(DisarmingPlayer)
}
# Wait for bomb b to be disarmed
block {
# Set the player who disarmed bomb b
DisarmingPlayer := TimedObjectiveB.EndedEvent.Await()
Print("Bomb Disarmed", ?Duration := 5.0)
# Activate the end game
EndGameDevice.Activate(DisarmingPlayer)
}
}
}
# Called when a bomb is detonated.
# @param {agent} Agent The agent that detonated the bomb.
# @return {void}
BombDetonated(Agent: agent): void = {
Print("Bomb Detonated", ?Duration := 5.0)
# Check if bomb a was armed
if (BombState = bomb_state.BombAArmed) {
# Explode barrels for bomb a
ExplodeBarrels(ExplosiveBarrelsA, Agent)
} else {
# Explode barrels for bomb b
ExplodeBarrels(ExplosiveBarrelsB, Agent)
}
# Activate the end game
EndGameDevice.Activate(Agent)
}
# Explode all the barrels.
# @param {[]explosive_device} Barrels The barrels to explode.
# @param {agent} Agent The agent that detonated the bomb.
# @return {void}
ExplodeBarrels(Barrels: []explosive_device, Agent: agent): void = {
# Iterate through all of the barrels
for (Barrel: Barrels) {
# Explode the barrel
Barrel.Explode(Agent)
}
}
# Set the correct beacons to be enabled.
# @return {void}
UpdateBeacons(): void = {
# Disable all arm beacons
BombABeaconArm.Disable()
BombBBeaconArm.Disable()
# Check if bomb a was armed
if (BombState = bomb_state.BombAArmed) {
# Enable the bomb a disarm beacon
BombABeaconDisarm.Enable()
} else {
# Enable the bomb b disarm beacon
BombBBeaconDisarm.Enable()
}
}
}