01. Creating a Basic UI

In this tutorial, we'll be covering the basics steps to create a user interface using the C# framework. This tutorial will explain:

  • Creating a Canvas for the UI
  • Adding Text to the UI
  • Adding an Image to the UI
  • Adding a Button to the UI and handling Button events.

Initial Setup

Create a new project from a blank template and open the Game.cs. The Game class is the entry point of the application in both the GameLauncher and the Sandbox. When the application is started the OnInitialize method will be called. This will construct a new instance of Game which can be used to start setting up the UI. The Shutdown method will be called while ending playback in the editor which can be used to cleanup the UI.

private Canvas _canvas;
 
private Game()
{
  // The server doesn't support rendering UI and receiving input, so initializing those system is not required.
  if(Engine.IsDedicatedServer)
  {
    return;
  }
  
  // Used to set up a new UI.
  CreateUI ();
  Mouse.ShowCursor();
}
 
private void CreateUI()
{
  
}

Adding a Canvas and Text

Next, a Canvas will be added to the Application which will draw a Text component. Every UIElement and UIComponent should be a child of a Canvas which is responsible for updating and managing every child UIElement.

The Canvas and the Text are added in the CreateUI by adding the following code.

private void CreateUI()
{
  _canvas = SceneObject.Instantiate<Canvas>(null);
 
  var text = _canvas.AddComponent<Text>();
  text.Alignment = Alignment.Center;
  text.Height = 24;
  text.Content = "Basic UI Example";
  text.Offset = new Point(0f, 120f);
}

After compiling the project and running the game (in the GameLauncher or Sandbox), the text will appear slightly below the center of the screen.

Adding an Image

Next up, an image will be added. First off, right-click and save into your 'Asset/libs/ui/' folder. Due to the transparency the image may appear as a blank image but when you import it into your project you can view the difference.

To access the image in-game, we'll need to use the ResourceManager and the ImageFromFile method. This loads a resource from the specified path as an image.

If the image at the specified path has already been loaded before, the ResourceManager will return the cached version.

Expand the CreateUI method with the following code:

private void CreateUI()
{
  // ...
  
  // Create a UIElement for our image.
  var logoElement = SceneObject.Instantiate<UIElement>(_canvas);
  logoElement.RectTransform.Size = new Point(300f, 300f);
  logoElement.RectTransform.Alignment = Alignment.Center;

  // Add an Image component for the image itself.
  var logoImage = logoElement.AddComponent<Image>();

  // Load our 'logo' image from 'Assets/libs/ui/'.
  logoImage.Source = ResourceManager.ImageFromFile(UIElement.DataDirectory + "/cryengine_logo.png", true);
}

The ResourceManager is part of the Resources namespace. To include this namespace in your code add the line using CryEngine.Resources; at the start of the Game.cs file.

After recompiling and running the game, it will show the following:

Adding a Button

The final component to be added in this tutorial is a button that will quit the game when running the game. A Button is a UIElement which has a ButtonCtrl. The Button is responsible for handling the visual representation of the button, while the ButtonCtrl is responsible for handling input events, the state of the Button and the content of the button. The ButtonCtrl also contains several callbacks to handle input.

  • OnPressed - Called when the button is pressed down and let up again without losing focus.
  • OnEnterMouse - Called when the mouse enters the rectangle area of the button.
  • OnLeaveMouse - Called when the mouse leaves the rectangle area of the button.
  • OnFocusEnter - Called when this button is focused, for example with the keyboard or a controller.
  • OnFocusLost - Called when this button lost focus.

These are normal C# events and can be hooked into as with any other type of event.

To instantiate a Button in our Canvas and assign a callback to the OnPressed event the following code needs to be added to the CreateUI method:

private void CreateUI()
{
  // ...

  // Create a quit button.
  var quitButton = SceneObject.Instantiate<Button>(_canvas);
  quitButton.RectTransform.Alignment = Alignment.Bottom;
  quitButton.RectTransform.Padding = new Padding(0f, -160f);
  quitButton.RectTransform.Size = new Point(300f, 30f);
  quitButton.Ctrl.Text.Content = "Quit";
  quitButton.Ctrl.Text.Height = 18;
  quitButton.Ctrl.Text.DropsShadow = true;
  quitButton.Ctrl.Text.Alignment = Alignment.Center;

  // Assign a callback to respond to the quit button being pressed.
  quitButton.Ctrl.OnPressed += OnQuitButtonPressed;
}

Finally add the corresponding OnQuitButtonPressed method that will quit the game.

private void OnQuitButtonPressed()
{
  Engine.Shutdown();
}

Recompile and play the game. Now you'll see a Quit button that will exit the game upon being pressed.

Final Code

using System;
using CryEngine.UI;
using CryEngine.UI.Components;
using CryEngine.Resources;

namespace CryEngine.Game
{
  /// <summary>
  /// Basic sample of running a Mono Application.
  /// </summary>
  public class Game : IDisposable
  {
    private static Game _instance;

    private Canvas _canvas;
    
    private Game()
    {
      // The server doesn't support rendering UI and receiving input, so initializing those system is not required.
      if(Engine.IsDedicatedServer)
      {
        return;
      }
      CreateUI ();
      Mouse.ShowCursor();
    }

    public static void Initialize()
    {
      if(_instance == null)
      {
        _instance = new Game();
      }
    }

    public static void Shutdown()
    {
      _instance?.Dispose();
      _instance = null;
    }

    private void CreateUI()
    {
      _canvas = SceneObject.Instantiate<Canvas>(null);

      var text = _canvas.AddComponent<Text>();
      text.Alignment = Alignment.Center;
      text.Height = 24;
      text.Content = "Basic UI Example";
      text.Offset = new Point(0f, 120f);

      // Create a UIElement for our image.
      var logoElement = SceneObject.Instantiate<UIElement>(_canvas);
      logoElement.RectTransform.Size = new Point(300f, 300f);
      logoElement.RectTransform.Alignment = Alignment.Center;

      // Add an Image component for the image itself.
      var logoImage = logoElement.AddComponent<Image>();

      // Load our 'logo' image from 'Assets/libs/ui/'.
      logoImage.Source = ResourceManager.ImageFromFile(UIElement.DataDirectory + "/cryengine_logo.png", true);

      // Create a quit button.
      var quitButton = SceneObject.Instantiate<Button>(_canvas);
      quitButton.RectTransform.Alignment = Alignment.Bottom;
      quitButton.RectTransform.Padding = new Padding(0f, -160f);
      quitButton.RectTransform.Size = new Point(300f, 30f);
      quitButton.Ctrl.Text.Content = "Quit";
      quitButton.Ctrl.Text.Height = 18;
      quitButton.Ctrl.Text.DropsShadow = true;
      quitButton.Ctrl.Text.Alignment = Alignment.Center;
      
      // Assign a callback to respond to the quit button being pressed.
      quitButton.Ctrl.OnPressed += OnQuitButtonPressed;
    }

    private void OnQuitButtonPressed()
    {
      Engine.Shutdown();
    }

    public void Dispose()
    {
      if(Engine.IsDedicatedServer)
      {
        return;
      }
      
      _canvas.Destroy();
    }
  }
}