sexta-feira, 25 de agosto de 2023

UEFN Verse: Programando um rotacionador de Props com spawn

Neste artigo vamos programar um rotacionador de Props. Props são itens  que podem ser adicionados a um nível do Fortnite. Os Props são muito utilizados na montagem do cenário e a maioria deles podem ser destruídos para fornecer materiais para o jogador.

É um exemplo simples mas que será útil para mostrar alguns recursos interessantes da linguagem Verse em ação.

Em qualquer projeto UEFN, abra o Verse Explorer, clique com o botão-direito no nome do projeto e escolha a opção Add new Verse file to project.

Em Device Name coloque props_rotator e clique no botão Create para usar o código do template.

No início do arquivo adicione o módulo SpatialMath e crie uma constante com o nome TimeRot180 do tipo float com valor default de 2.0, como mostra o código abaixo:

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath}

props_rotator := class(creative_device):

    @editable
    TimeRot180 : float = 2.0

O módulo SpatialMath é necessário porque usaremos uma função chamada ApplyYaw() que modifica a rotação ao redor do eixo Z.

A constante TimeRot180 armazena o tempo em segundos que um Prop levará para dar meia volta (180 graus).

Vamos criar uma função chamada RotateProp que receberá um creative_prop como parâmetro e irá manter este Prop rotacionando.

Esta função precisa ser assíncrona, por isso usaremos o especificador suspends.

O código da função RotateProp é este:

    RotateProp(Prop : creative_prop)<suspends>:void=

        loop:
            PropTransform := Prop.GetTransform()
            PropLocation  := PropTransform.Translation
            PropRotation  := PropTransform.Rotation

            NewRotation := PropRotation.ApplyYaw(180.0)

            Prop.MoveTo(PropLocation, NewRotation, TimeRot180)

A função RotateProp obtém a estrutura transform do Prop para ter acesso à localização e rotação atual do Prop. É usada a função ApplyYaw para criar uma nova rotação que modifica a rotação atual do Prop em 180 graus ao redor do eixo Z.

Usaremos a função MoveTo da classe creative_prop para que o Prop modifique a sua rotação ao longo do tempo que está armazenado na constante TimeRot180. Quando o Prop completar a rotação, a expressão loop executará o bloco de código novamente fazendo com que o Prop rotacione continuamente.

Observe que a expressão loop que repete o bloco de código responsável pela rotação não tem nenhuma expressão break ou return para encerrar o loop, ou seja, é um loop infinito.

Um código assim em outras linguagens de programação que não possui contexto assíncrono provavelmente irá travar seu computador ao ser executado. Mas como veremos na linguagem Verse é muito simples criar um contexto assíncrono independente para executar esta função sem interromper o fluxo de execução do jogo. 

Para completar o código do dispositivo props_rotator, defina um array de creative_prop e modifique a função OnBegin para ficar desta forma:

    @editable
    PropsToRotate : []creative_prop = array{}

    OnBegin<override>()<suspends>:void=
       
        for (PropInstance : PropsToRotate):
            spawn{ RotateProp(PropInstance) }

Na função OnBegin temos a expressão for que irá repetir o bloco de código abaixo dela para cada elemento do array.

A expressão spawn inicia uma expressão assíncrona (a função RotateProp) e continua a execução do fluxo principal. Para cada um dos Props que forem adicionados ao array haverá um contexto assíncrono executando a função RotateProp.

A expressão spawn é um tipo de concorrência não estruturada. A recomendação na linguagem Verse é a de tentar usar as expressões de concorrência estruturadas como sync, race, rush e branch. O spawn deve ser usado como último recurso em alguns casos específicos.

O código Verse completo do dispositivo props_rotator fica assim:

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath}

props_rotator := class(creative_device):

    @editable
    TimeRot180 : float = 2.0

    @editable
    PropsToRotate : []creative_prop = array{}

    OnBegin<override>()<suspends>:void=
       
        for (PropInstance : PropsToRotate):
            spawn{ RotateProp(PropInstance) }  
                
    RotateProp(Prop : creative_prop)<suspends>:void=

        loop:
            PropTransform := Prop.GetTransform()
            PropLocation  := PropTransform.Translation
            PropRotation  := PropTransform.Rotation

            NewRotation := PropRotation.ApplyYaw(180.0)

            Prop.MoveTo(PropLocation, NewRotation, TimeRot180)  

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

Adicione o props_rotator e alguns Props no nível para serem rotacionados pelo nosso dispositivo. Uma boa opção para visualizar a rotação é o Prop com nome Farm_WeatherVane_01.

Selecione o props_rotator no nível e na aba Details adicione algumas referências de Props no array PropsToRotate. Você também pode alterar o tempo de rotação na propriedade TimeRot180.



Salve o nível e inicie a sessão. Observe a rotação dos Props que foram adicionados ao PropsToRotate



Sumário Verse