quarta-feira, 25 de outubro de 2023

UEFN Verse: 2ª versão do round_based_device

Neste artigo vamos modificar o código Verse do round_based_device para configurar cada um dos round de uma forma diferente.

Clique no botão Verse da barra de ferramenta do UEFN para abrir o Visual Studio Code.

Adicione duas variáveis do tipo inteiro com os nomes NumberOfAreasCaptured e CurrentRound. Inicie essas variáveis com o valor 0. Estas duas variáveis não tem o atributo @editable porque elas serão usadas apenas no código Verse.

Vamos criar constantes para referenciar cada um dos dispositivos Round Settings que estão no nível. As variáveis e constantes do round_based_device vão ficar assim:

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{}


O dispositivo Round Settings possui um evento chamado RoundBeginEvent. Somente o dispositivo Round Settings que está ativo no round atual irá acionar este evento no início do round.

Vamos criar uma função para cada um dos dispositivos Round Settings com o padrão de nome Round1Setup, Round2Setup... O registro destas funções no evento é feito na função OnBegin que deve ficar assim:

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


A função AreaCaptured precisa ser modificada. Esta função é executada quando o jogador captura uma área. Nesta nova versão, o round só será finalizado quando o número de áreas capturadas for igual ao número do round atual. Por exemplo, no terceiro round o jogador precisa capturar 3 áreas. 

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

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


Crie uma função com o nome EnableCaptureAreas. Esta função recebe como parâmetro o número de Capture Areas que devem ser habilitadas. A função habilita as áreas e registra a função AreaCaptured no evento  AreaIsScoredEvent

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

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

A expressão 0..MaxIndex no loop for é do tipo Range que representa uma série de inteiros. Por exemplo, se MaxIndex tiver o valor 3 então a série gerada será 0, 1, 2 e 3.  O loop for irá iterar usando cada um desses valores que ficará armazenado na constante Index durante a iteração corrente.

O Index é usado no array CaptureAreas para obter a referência de uma das Capture Areas do nível. O primeiro elemento de um array tem o índice 0.

O próximo passo é criar funções de setup para cada um dos rounds.  São nestas funções que você fará as configurações específicas de cada round. Crie as funções abaixo no final do arquivo round_based_device.

    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)


Neste projeto de exemplo, a diferença entre os rounds é simples, pois muda apenas a quantidade de áreas habilitadas. Em seus projetos você pode definir muitas coisas nestas funções de setup dos rounds. Você pode adicionar diversos dispositivos no nível e deixá-los inativos e invisíveis. Em um round específico você pode ativá-los e movê-los para a área do jogo.

Outra opção é criar uma ilha grande com vários cenários diferentes para cada um dos rounds.  No setup do round você pode teleportar o jogador para um dos cenários.

O código Verse da 2ª versão do round_based_device fica assim:
# 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)


Salve o arquivo e compile o código Verse usando a opção Verse > Build Verse Code do menu do UEFN.

Selecione o round_based_device no nível. Na aba Details selecione as referências dos 5 dispositivos Round Settings:



Precisamos desabilitar todas as Capture Areas do nível. Na aba Outliner, selecione as 5 Capture Areas:


A aba Details exibe as propriedades em comum dos objetos selecionados. Qualquer alteração afetará todos os objetos selecionados. Pesquise por enable e mude o valor de Enable During Phase para None:



Salve o nível e inicie a sessão. Observe que o número de Capture Areas habilitadas é equivalente ao round atual. O round só será encerrado quando o jogador capturar todas as áreas habilitadas.


No próximo artigo vamos usar o dispositivo Class Designer para definir o equipamento inicial do jogador.


Sumário Verse