quarta-feira, 25 de outubro de 2023

UEFN Verse: 2nd version of round_based_device

In this article we will modify the round_based_device Verse code to configure each round in a different way.

Click the Verse button on the UEFN toolbar to open Visual Studio Code.

Add two integer variables named NumberOfAreasCaptured and CurrentRound. Initialize these variables with the value 0. These two variables do not have the @editable attribute because they will only be used in the Verse code.

Let's create constants to reference each of the Round Settings devices that are in the level. The round_based_device variables and constants will look like this:

round_based_device := class(creative_device):

    @editable
    EndGameDevice : end_game_device = end_game_device{}

    @editable 
    CaptureAreas: []capture_area_device = array{}

    var NumberOfAreasCaptured : int = 0

    var CurrentRound : int = 0

    @editable
    Round1Device : round_settings_device = round_settings_device{}

    @editable
    Round2Device : round_settings_device = round_settings_device{}

    @editable
    Round3Device : round_settings_device = round_settings_device{}

    @editable
    Round4Device : round_settings_device = round_settings_device{}

    @editable
    Round5Device : round_settings_device = round_settings_device{}


The Round Settings device has an event called RoundBeginEvent. Only the Round Settings device that is active in the current round will trigger this event at the start of the round.

Let's create a function for each of the Round Settings devices with the name pattern Round1Setup, Round2Setup... These functions are subscribed in the event in the OnBegin function, which should look like this:

    OnBegin<override>()<suspends>:void=
        Round1Device.RoundBeginEvent.Subscribe(Round1Setup)
        Round2Device.RoundBeginEvent.Subscribe(Round2Setup)
        Round3Device.RoundBeginEvent.Subscribe(Round3Setup)
        Round4Device.RoundBeginEvent.Subscribe(Round4Setup)
        Round5Device.RoundBeginEvent.Subscribe(Round5Setup)


The AreaCaptured function needs to be modified. This function is executed when the player captures an area. In this new version, the round will only end when the number of areas captured is equal to the number of the current round. For example, in the third round the player needs to capture 3 areas. 

    AreaCaptured(Agent:agent):void=
        set NumberOfAreasCaptured += 1

        if( NumberOfAreasCaptured = CurrentRound):
            EndGameDevice.Activate(Agent)


Create a function named EnableCaptureAreas. This function receives as a parameter the number of Capture Areas that must be enabled. The function enables the areas and subscribes the AreaCaptured function in the AreaIsScoredEvent event. 

   EnableCaptureAreas(NumberOfAreas:int):void=        
        MaxIndex := NumberOfAreas - 1

        for (Index := 0..MaxIndex):
            if(Area := CaptureAreas[Index]):
                Area.Enable()
                Area.AreaIsScoredEvent.Subscribe(AreaCaptured)

The expression 0..MaxIndex in the for loop is of Range type which represents a series of integers. For example, if MaxIndex has the value 3 then the generated series will be 0, 1, 2 and 3. The for loop will iterate using each of these values which will be stored in the Index constant during the current iteration.

The Index is used in the CaptureAreas array to get the reference of one of the level's Capture Areas. The first element of an array has index 0.

The next step is to create setup functions for each of the rounds. It is in these functions that you will make the specific settings for each round. Create the functions below at the end of the round_based_device file.

    Round1Setup():void=
        set CurrentRound = 1
        
        EnableCaptureAreas(CurrentRound)
                            
    Round2Setup():void=
        set CurrentRound = 2
        
        EnableCaptureAreas(CurrentRound)

    Round3Setup():void=
        set CurrentRound = 3
        
        EnableCaptureAreas(CurrentRound)
             
    Round4Setup():void=
        set CurrentRound = 4
        
        EnableCaptureAreas(CurrentRound)

    Round5Setup():void=
        set CurrentRound = 5
        
        EnableCaptureAreas(CurrentRound)


In this example project, the difference between the rounds is simple, as it only changes the number of enabled areas. In your projects you can define many things in these round setup functions. You can add different devices to the level and make them inactive and invisible. In a specific round you can activate and move them to the game area.

Another option is to create a large island with several different scenarios for each of the rounds. In the round setup you can teleport the player to one of the scenarios.

The Verse code for the 2nd version of round_based_device looks like this:

# v0.2
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

round_based_device := class(creative_device):

    @editable
    EndGameDevice : end_game_device = end_game_device{}

    @editable 
    CaptureAreas: []capture_area_device = array{}

    var NumberOfAreasCaptured : int = 0

    var CurrentRound : int = 0

    @editable
    Round1Device : round_settings_device = round_settings_device{}

    @editable
    Round2Device : round_settings_device = round_settings_device{}

    @editable
    Round3Device : round_settings_device = round_settings_device{}

    @editable
    Round4Device : round_settings_device = round_settings_device{}

    @editable
    Round5Device : round_settings_device = round_settings_device{}

    OnBegin<override>()<suspends>:void=
        Round1Device.RoundBeginEvent.Subscribe(Round1Setup)
        Round2Device.RoundBeginEvent.Subscribe(Round2Setup)
        Round3Device.RoundBeginEvent.Subscribe(Round3Setup)
        Round4Device.RoundBeginEvent.Subscribe(Round4Setup)
        Round5Device.RoundBeginEvent.Subscribe(Round5Setup)

    AreaCaptured(Agent:agent):void=
        set NumberOfAreasCaptured += 1

        if( NumberOfAreasCaptured = CurrentRound):
            EndGameDevice.Activate(Agent)

    EnableCaptureAreas(NumberOfAreas:int):void=        
        MaxIndex := NumberOfAreas - 1

        for (Index := 0..MaxIndex):
            if(Area := CaptureAreas[Index]):
                Area.Enable()
                Area.AreaIsScoredEvent.Subscribe(AreaCaptured)

    Round1Setup():void=
        set CurrentRound = 1
        
        EnableCaptureAreas(CurrentRound)
                            
    Round2Setup():void=
        set CurrentRound = 2
        
        EnableCaptureAreas(CurrentRound)

    Round3Setup():void=
        set CurrentRound = 3
        
        EnableCaptureAreas(CurrentRound)
             
    Round4Setup():void=
        set CurrentRound = 4
        
        EnableCaptureAreas(CurrentRound)

    Round5Setup():void=
        set CurrentRound = 5
        
        EnableCaptureAreas(CurrentRound)


Save the file and compile the Verse code using the Verse > Build Verse Code option from the UEFN menu.

Select the round_based_device in the level. In the Details tab, select the references of the 5 Round Settings devices:



We need to disable all Capture Areas in the level. In the Outliner tab, select the 5 Capture Areas:


The Details tab displays the common properties of the selected objects. Any changes will affect all selected objects. Search for enable and change the value of Enable During Phase to None:



Save the level and start the session. Note that the number of Capture Areas enabled is equivalent to the current round. The round will only end when the player captures all enabled areas.


In the next article we will use the Class Designer device to define the player's starting equipment.


Table of Contents Verse