Create a simple user interface with Valkyrie

In this tutorial, you will learn how to position your UI elements on the screen.
We recommend for you to be familiar with setting up interactions in Valkyrie.

Depending on the look and feel you are seeking, you may want to design your GUI in the image editor of your choice.

What you will need:

  • Valkyrie Engine
  • (Optional) GUI images in PNG, TGA or JPG format
  • 30 minutes

You can play with the final result in the GUI template included in the Valkyrie Engine launcher. img

Now without further ado, let’s get started!

Target User Interface in Valkyrie

We will reproduce the GUI featured in the concept art below: img

Notice the 5 UI sections in the design: img

Let’s first learn how to build the Bottom center bar element (UI Section 3), and then we will take a closer look at the Right side collapsible menu (UI Section 5).

Setup UI Layer

Create a new application in Valkyrie Engine or use an existing one.

Copy your assets in the ./data folder of your application. img

The image assets associated with each section must be imported in either JPG, TGA or PNG format.

Create a new layer by drag & dropping the Layer entity from the library to your scene. layer

You can assign a name to this layer if you wish to. In this case, we will name it GUI. layer%20name%20input

We need to enable the following flags:

  • PainterDrawSet: This flag allows Valkyrie Engine to know which layer should be displayed first depending on its position in the scene’s hierarchy.
  • Camera: This flag specifies that the layer contains its own camera. Otherwise the camera of the parent layer will be used.
  • ViewportStrech: This flag enables the aspect ratio of the Viewport to be changed without affecting the position of the UI elements.
  • ViewportCenterH: Center the viewport horizontally on the screen.
  • ViewportCenterV: Center the viewport vertically on the screen.

layout_flags

Now that we’ve got that out of the way, let’s proceed to create a Camera of the GUI layer. Drag & drop the camera entity from the library to your GUI layer. We will call this camera GUI-Cam. img

All assets entering the field of view of this camera will be visible in the GUI layer.

Bottom center bar element (UI Section 3)

Create a primitive by drag & dropping the Primitive entity into your GUI layer and position it within the field of view of your GUI-Cam. img

The primitive you create is a box by default, let’s make it into a plane. Select your primitive and navigate into its properties, in the Primitive type, select PlaneHz. img

Your level should look like this: img

To add more context, let’s add a texture to the primitive. Navigate to your asset library and select one of the bitmaps you saved in the ./data folder. You will have to drag & drop it into the primitive’s diffuse channel. img

Our UI element is now textured, but the texture appears distorted. That’s because the primitive’s aspect ratio doesn’t match the texture’s aspect ratio. To fix this, select your primitive and scale it accordingly to match your texture resolution. img

Don’t forget to enable the transparency flag in the material editor if your bitmap features an alpha channel. img

The bottom UI element from section 3 is now displayed on the screen. However, we must now anchor it correctly in the viewport.

To do so, we will use dummies. Drag & drop a dummy entity from the library to your GUI layer. We will name it UI-Bottom-Anchor. img

Drag your primitive into the dummy and make sure they have the same position on the Z axis. img

Set your primitive relative to the dummy with its Base Flag. This means that the transformations applied to the dummy will also affect the assets contained within it. img

We will now create the anchor. Navigate to the actions library and drag & drop the ViewportAnchor action on your dummy. You can select the horizontal & vertical anchor settings by clicking on the ViewportAnchor action in your timeline. In this case, we want the UI-Bottom-Anchor to be centered horizontally and anchored at the bottom of the screen: img

Press ALT+SPACE to return to the camera view and press CTRL+SPACE to play the scene. The UI element is now centered horizontally & anchored at the bottom of the screen vertically. img

You can tweak the primitive’s position if there is a gap between the asset and the screen’s limit. img

Our UI element is now correctly anchored in the viewport. img

Top Left UI element (UI Section 1)

We will repeat this process for all UI elements. img

img

UI Sections 2 and 4 are skipped in this tutorial as there is little added value to show it.

Right side collapsible menu (UI Section 5)

One of the UI elements is partially hidden. So let’s see how to handle this kind of exception.

Duplicate one of your UI dummies and change the settings of the ViewportAnchor accordingly. In this case Horizontally right and vertically centered. img

Assign the correct bitmap in your material editor and scale your primitive to match the texture’s aspect ratio. img

As you may have noticed, the ViewportAnchor action is active on the dummy. The dummy’s position will be updated depending on the ViewportAnchor settings. That being said, the primitive relative to the dummy can be moved. Its anchor point is the dummy’s position. This allows you to handle exceptions easily and we’ll demonstrate that in a moment.

Let’s pretend that when clicked, the inventory menu we just created should be revealed completely. We will need to create 2 additional dummies to specify the start and end positions of our UI element.

Disable your primitive’s relative flag for the moment. img

Create a new dummy and position it at the exact location of your primitive. Let’s name this dummy Start. Tick the relative flag in the dummy’s settings. Drag your primitive into the Start primitive and enable its relative flag. img

Duplicate the Start dummy and drag it to the left before renaming it to End. This will be the destination of our UI element when it is revealed. img

Now create 2 AnimMoveTo actions and drag them onto your primitive. We will create 2 animations. One when the UI element is revealed and another for when it collapses into its initial state. img

Press CTRL+SPACE to play your scene. You will now see the UI element expand and collapse as the timeline plays.

Naturally, we want to trigger this animation only when the user interacts with the UI element. To do so, let’s add constraints to the timeline.

Drag & Drop 2 TimelineJumpTo actions on your primitive. Adjust their lengths so that they are active after the AnimMoveTo actions. img

When the TimelineJumpTo action is triggered, you can move the current time to a specific time. It is useful to create state machines.

In this case, every time the action is triggered, we want to the move the current time to the beginning of the last AnimMoveTo animation.

In order to make this work, we need to select our primitive and tick the LocalTimeline flag as well as setting ticking the Loop checkbox and make sure that the Playback is set to Playing. img

Play your scene and notice that the constraints are now in place! But there is still no way for the user to reveal the UI so we’ll have to create an interaction for that.

Navigate to the events library and drag & drop a Finger event in your GUI layer.

Navigate to the actions library and drag & drop an InputRayCast action onto the Finger event. img

User clicks and finger taps are now detected in the scene.

Now let’s create 2 EnterRayHit events in our primitive. img

As we didn’t create specific hitboxes for our UI element, its entire surface can receive clicks. By using 2 EnterRayHit events we can specify what happens when the UI element is clicked regardless of its status.

Let’s add a TimelineJumpTo action to both EnterRayHit events and set the time accordingly. img

Behold, your UI is now complete! Clicking on the UI element reveals and collapses it. Notice also how the UI elements are anchored to the right side of the screen. img

Conclusion

With what you’ve learned, you can add more granularity to your own UI elements and create sophisticated user interfaces. The interactions you create in your UI layer can affect elements in the 3D layers underneath, so go ahead and try.