sexta-feira, 25 de agosto de 2023

UEFN Verse: Programming a Props Rotator with spawn

I'm still programming the example project I'll be using in Part 2 of my Verse programming tutorials. Because of that I decided to share a quick Verse tip with you.

In this article we are going to program a Props rotator. Props are items that can be added to a Fortnite level. Props are used a lot to set up the scene and most of them can be destroyed to provide materials for the player.

It's a simple example but it will be useful to show some interesting features of the Verse language in action.

In any UEFN project, open the Verse Explorer, right-click on the project name and choose Add new Verse file to project.

In Device Name put props_rotator and click on Create button to use the template code.

At the beginning of the file add the SpatialMath module and create a constant named TimeRot180 of type float with a default value of 2.0, as shown in the code below:

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

The SpatialMath module is needed because we are going to use a function called ApplyYaw() that modifies the rotation around the Z axis.

The TimeRot180 constant stores the time in seconds it takes a Prop to turn around (180 degrees).

Let's create a function named RotateProp that will receive a creative_prop as a parameter and will keep this Prop rotating.

This function needs to be asynchronous, so we'll use the suspends specifier.

The RotateProp function code is this:

    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)

The RotateProp function gets the transform structure of the Prop to get access to the Prop's current location and rotation. The ApplyYaw function is used to create a new rotation that modifies the current Prop rotation by 180 degrees around the Z axis.

We will use the MoveTo function of the creative_prop class so that the Prop changes its rotation over the time that is stored in the TimeRot180 constant. When the Prop completes the rotation, the loop expression will execute the block of code again causing the Prop to continuously rotate.

Note that the loop expression that repeats the block of code responsible for the rotation has no break or return expression to terminate the loop, so it is an infinite loop.

Code like this in other programming languages that doesn't have an asynchronous context will likely crash your computer when executed. But as we'll see in the Verse language, it's very simple to create an independent asynchronous context to execute this function without interrupting the game's execution flow.

To complete the props_rotator device code, define an array of creative_prop and modify the OnBegin function to look like this:

    @editable
    PropsToRotate : []creative_prop = array{}

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

In the OnBegin function we have the for expression that will repeat the code block below it for each element of the array.

The spawn expression starts an asynchronous expression (the RotateProp function) and continues the execution of the main flow. For each of the Props that are added to the array there will be an asynchronous context executing the RotateProp function.

The spawn expression is a type of unstructured concurrency. The recommendation in the Verse language is to try to use structured concurrency expressions like sync, race, rush, and branch. The spawn should be used as a last resort in some specific cases.

The complete Verse code of the props_rotator device looks like this:

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)  

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

Add the props_rotator and some Props in the level to be rotated by our device. A good option for viewing the rotation is the Prop named Farm_WeatherVane_01.

Select the props_rotator at the level and in the Details tab add some Props references in the PropsToRotate array. You can also change the rotation time in the TimeRot180 property.



Save the level and start the session. Look at the rotation of the Props that were added to PropsToRotate. 



Table of Contents Verse