This final tutorial step shows you how to improve your code while teaching some important Verse concepts as you go.
Improve Your Verse Code
This page guides you step by step through the code changes, but if you want to check your work, review the Complete Code section for the final result.
Refactoring is a process in which you restructure existing code to improve the design or implementation without changing its behavior. The following are the most common goals when refactoring your code:
Improving readability with better variable naming, better spacing or overall code structure.
Improving performance with simpler or more efficient implementation of behavior.
Reducing repetition and code bloat (large, unnecessary or overly complex code) by condensing similar functions into one or gathering multiple variables of similar type and purpose into containers like arrays.
Refactoring by following these goals should help you write code that is maintainable, easy to read and revisit, and extensible, easy to extend the capabilities of for future enhancements to the behavior. Making your games really level up!
GetFirstPlayer()
Writing readable code is a great programming practice. For example, GetFirstPlayer() is clearer than GetPlayspace().GetPlayers()[0]. Additionally, this approach is a best practice for programming common operations as it clearly states the operation's intent.
Open the
shooting_range_manager_device.versefile.Add the
GetFirstPlayermethod.Notice the
GetFirstPlayermethod has the <decides><transacts> effect specifiers because it can fail and rollback. Read Failure in Verse for more details about failable expressions and failure contexts.Verse# Returns the first player in the playspace. GetFirstPlayer()<decides><transacts>:player= return GetPlayspace().GetPlayers()[0]Modify the
AdjustScoremethod to use the newGetFirstPlayermethod.Notice that the
GetFirstPlayermethod is called with brackets instead of parentheses because it is failable.Verse# Adjusts the player's score by the provided value. AdjustScore(Value:int):void= # Start the timer if it hasn't started yet. if (not IsTimerStarted?): StartTimer() # Sets the score award to the base value of the target multiplied by the current weapon level. ScoreManager.SetScoreAward(Value * CurrentWeaponLevel) <# --- New Code Start --- #>Modify the
IncreaseWeaponLevelmethod to use the newGetFirstPlayermethod.Verse# Increases the player's weapon level by one (up to the maximum value). IncreaseWeaponLevel():void= if: # If able to retrieve the first player and current weapon level isn't maxed, then... <# --- New Code Start --- #> Player:player = GetFirstPlayer[] <# --- New Code End --- #>
Target Class Wrappers and Arrays
Another key goal when cleaning up code is minimizing duplication. In the current implementation, each Good and Bad Target defines its own callback and hit flag, making the code repetitive.
A better approach is to create a wrapper class that contains everything an individual target needs. The shooting range manager can then manage these target wrappers in an array, rather than defining each component individually.
This not only reduces duplication but also improves scalability. You can add as many targets as you like without writing additional code.
Define the
good_target_wrapperclass. You can put this above yourshooting_range_manager_deviceclass definition.Verse# A wrapper class for the good targets to support array storage with a self-contained event callback. good_target_wrapper := class: @editable Target:shooting_range_target_track_device = shooting_range_target_track_device{} @editable Score:int = 100 # A circular reference to the shooting range manager device.Define the
bad_target_wrapperclass. You can put this above yourshooting_range_manager_deviceclass definition.Verse# A wrapper class for the bad targets to support array storage with a self-contained event callback. bad_target_wrapper := class: @editable Target:shooting_range_target_device = shooting_range_target_device{} @editable Score:int = -100 # A circular reference to the shooting range manager device.Add the following array properties to your shooting range manager device.
Verse@editable: GoodTargets:[]good_target_wrapper = array{} @editable BadTargets:[]bad_target_wrapper = array{}Remove the following from your shooting range manager device. These are handled by the wrapper classes now.
GoodTarget1-3
GoodTargetScore
BadTarget1-3
BadTargetScore
HitGoodTarget1-3
OnGoodTarget1-3Hit()
OnBadTarget1-3Hit()
Modify the
OnBeginmethod to initialize the Good and Bad Targets by looping through the array.Verse# Runs when the device is started in a running game. OnBegin<override>()<suspends>:void= <# --- New Code Start --- #> # Initialize GoodTargets. for (GoodTarget : GoodTargets): GoodTarget.Init(Self) # Initialize BadTargets.Modify the
CheckCombomethod to check for combo completion by looping through the Good Target array.Verse# If the combo is complete, enable the ComboTarget. CheckCombo():void= <# --- New Code Start --- #> # If any of the good targets are not hit, exit the function. for (GoodTarget : GoodTargets): if (not GoodTarget.IsHit?): returnUpdate the
ResetCombomethod to loop through the Good Target array.Verse# Resets the combo tracking variables, re-enables all GoodTargets, and disables the ComboTarget. ResetCombo():void= <# --- New Code Start --- #> for (GoodTarget : GoodTargets): GoodTarget.Reset() <# --- New Code End --- #>Save and build your Verse code.
Complete Code
using { /Fortnite.com/Devices }
using { /Verse.org/Random }
using { /Verse.org/Simulation }
<#>
Utility Classes
<#>
# A wrapper class for the good targets to support array storage with a self-contained event callback.
good_target_wrapper := class:
Bring It Together
You must set new values for the changed editable properties on your Verse device.
Select the shooting_range_manager_device in the viewport or Outliner panel.
In the Details panel, set the following parameters:
Add three elements to the GoodTargets array and set each to their respective targets. Optionally, you can also change the score value of an individual target now.
Add three elements to the BadTargets array and set each to their respective targets. You can also optionally change the score value of an individual target now.
Verify all other properties are set as expected.
On Your Own
This section is over, but you don't have to be. For more Verse functionality and gameplay, see the documentation in Learn Game Mechanics.