---
description: >-
  In this section, we took the time to add a UI to our game to start the game,
  pause the game, view stats, and play game over/victory screens.
---

# Section 7: Game Interface

## Section Intro - Game Interface

There are no notes for this lecture.

## Setting Up the Start Menu

In this lecture, we designed an interface with Godot's nodes. There are no notes for this lecture.

## Grabbing UI Containers

In this lecture, we applied a class to our containers. Containers are nodes used for storing and arranging additional UI nodes. We'll be storing most of interfaces in containers. Since that's the case, it'll be easier to select them with a class attched to them. So, we added a class called `UIContainer`.&#x20;

In this class, we exported a property with an enum.

```csharp
public partial class UIContainer : VBoxContainer
{
    [Export] public ContainerType container { get; private set; }
}
```

Here's the enum definition.

```csharp
public enum ContainerType
{
    Start,
    Pause,
    Victory,
    Defeat,
    Stats,
    Reward
}
```

It contains a list of the type of UI elements we'll be creating in our game.

To select a container, we created a dictionary called `containers`. Dictionaries are a feature in C# for storing a collection of data. The main difference between a dictionary and array is that a dictionary allows developers to configure the index for each item in an array. You don't have to use numeric indexes.

We can define a dictionary by importing the following namespace:

```csharp
using System.Collections.Generic;
```

Next, we can use the `Dictionary` type with the data type for the key and value, respectively.

```csharp
private Dictionary<ContainerType, UIContainer> containers;
```

For the value, we're initializing the field from the `_Ready()` method.

```csharp
containers = GetChildren()
    .Where((element) => element is UIContainer)
    .Cast<UIContainer>()
    .ToDictionary((element) => element.container);
```

We're using Linq to help us create the dictionary. Firstly, we're using the `GetChildren()` method, which is available on nodes for grabbing a list of child nodes in the current node. Since this script is applied to the root node of the UI scene, we'll grab all the nodes directly under it.

Next, we're filtering the nodes to check if they have the `UIContainer` class attached to it. The result is an array of nodes, but we want to cast the results into the `UIContainer` class, which is what we're doing with the `Cast` method. Lastly, we're converting the array into a dictionary with the `ToDictionary()` method, which accepts a lambda function for specifying the key for each item in the array.

Lastly, we toggled the visibility of a node by setting the `Visible` property.

```csharp
containers[ContainerType.Start].Visible = true;
```

To access an item from a dictionary, we can use the enum inside the square brackets instead of a numeric index.

### Resources

* Commonly Used Collection Types - [https://learn.microsoft.com/en-us/dotnet/standard/collections/commonly-used-collection-types](https://learn.microsoft.com/en-us/dotnet/standard/collections/commonly-used-collection-types)

## Starting the Game

In this lecture, we learned how to pause and unpause the game. Games in Godot can be paused by grabbing the scene tree and setting the `Paused` property to `true`.

```csharp
GetTree().Paused = true;
```

Not everything in Godot will be paused, but you can expect most of Godot's behavior to be paused from physics process to input methods.&#x20;

To unpause the game, we listened for a button press on the button node. Every button node has a signal called `Paused`, which we can listen to like so:

```csharp
containers[ContainerType.Start].ButtonNode.Pressed += HandleStartPressed;
```

## Reparenting Nodes

In this lecture, we learned how to reparent nodes. First, we created a custom event by defining a class for storing our events called `GameEvents`.

```csharp
using System;

public class GameEvents
{
    public static Action OnStartGame;

    public static void RaiseStartGame() => OnStartGame?.Invoke();
}
```

We're using the `static` keyword so that we can access the event outside the class without needing an instance. Static members are similar to constants except that their values can change.&#x20;

As a naming convention we'll be following in this course, event names always start with the word `On<Name>`. Event handlers will be called `Handle<Name>` and raisers will be called `Raise<Name>`.

After creating this event, we can subscribe to it like so:

```csharp
GameEvents.OnStartGame += HandleStartGame;
```

This event will be raised when the game starts. Once it does, we'll reparent the camera node. Reparenting is the process of moving a child node to a completely different parent node. Every node has access to a method called `Reparent`. This method accepts an instance of a `Node` class to move a node. We exported a field for storing the target.

```csharp
[Export] private Node target;
```

Next, we called the `Reparent` method with the target like so:

```csharp
Reparent(target);
```

## The event Keyword

In this lecture, we learned about the `event` keyword to prevent us from causing errors in our game. When we define custom events, we have the option of adding the `event` keyword like so:

```csharp
public static event Action OnStartGame;
```

If we add this keyword, we'll only be able to register and unregister methods. We're not allowed to completely override the field. For example, we can't do the following:

```csharp
GameEvents.OnStartGame = HandleStartGame;
```

We can only use the `+=` operator when assigning a method.

## Handling the End Game Event

In this lecture, we updated our games events to include an event for when the game ends. First, we added the event and method for raising the event in the `GameEvents` class.

```csharp
public class GameEvents
{
    public static event Action OnStartGame;
    public static event Action OnEndGame;

    public static void RaiseStartGame() => OnStartGame?.Invoke();
    public static void RaiseEndGame() => OnEndGame?.Invoke();
}
```

Afterward, we raised this event from the `PlayerDeathState` class.

```csharp
GameEvents.RaiseEndGame();
```

Lastly, we subscribed to this event. During this event, we reparented the `Camera` node in our game.

```csharp
public override void _Ready()
{
    GameEvents.OnStartGame += HandleStartGame;
    GameEvents.OnEndGame += HandleEndGame;
}

private void HandleEndGame()
{
    Reparent(GetTree().CurrentScene);
}

```

Once again, we're using the `Reparent` method. In this method, we're passing on the `GetTree().CurrentScene` property, which contains the root node of the current scene in our game.&#x20;

## Stats UI

In this lecture, we created a UI for displaying the player's stats. There are no notes for this lecture.

## Dynamically Updating Labels

In this lecture, we updated the labels for displaying the player's stats. We used the resource to help us perform this task. The great thing about resources is that they're independent from a node. They can be applied to multiple nodes and share data. So, in the `StatResource` class, we added an event called `OnUpdate` and then raised it from the `set` accessor.

```csharp
public partial class StatResource : Resource
{
    public event Action OnZero;
    public event Action OnUpdate;

    [Export] public Stat StatType { get; private set; }

    private float _statValue;

    [Export]
    public float StatValue
    {
        get => _statValue;
        set
        {
            _statValue = Mathf.Clamp(value, 0, Mathf.Inf);

            OnUpdate?.Invoke();

            if (_statValue == 0)
            {
                OnZero?.Invoke();
            }
        }
    }
}
```

Next, we subscribed to this event from a custom class attached to a node called `StatLabel`. In this class, we're setting the `Text` property to the new value.

```csharp
Text = statResource.StatValue.ToString();
```

It's important to note that we are using the `ToString()` method to convert the value into a string since the `Text` property only accepts strings.

## Counting the Enemies

In this lecture, we counted the enemies in our game, kept track of this information, and then updated the label in the stats UI to display this information. Firstly, to grab the number of enemies, we stored the enemies in a node and attached a script to it. From this script, we used the `GetChildCount` method to count the number of child nodes.

```csharp
int totalEnemies = GetChildCount();
```

Next, we raised an event to allow other nodes to gather this data. Godot has a signal that we can subscribe to when a child node is deleted. Since we're deleting our enemies from the game, we decided to use it to update the count. The signal is called `ChildExitingTree`.

```csharp
ChildExitingTree += HandleChildExitingTree;
```

Here's the method handler.

```csharp
private void HandleChildExitingTree(Node node)
{
    int totalEnemies = GetChildCount() - 1;

    GameEvents.RaiseNewEnemyCount(totalEnemies);
}
```

In this method, we're grabbing the count again and subtracting one. It's important to subtract 1 since this signal gets called _before_ the enemy is deleted.&#x20;

For the `OnNewEnemyCount` event, we defined the event with a generic.

```csharp
public static event Action<int> OnNewEnemyCount;
```

If you plan on sending data with an event, you must add a generic to describe the type of data you plan on sending. Whenever you subscribe to this event, the method must accept the argument. Otherwise, C# will complain.

```csharp
public partial class EnemyCountLabel : Label
{
    public override void _Ready()
    {
        GameEvents.OnNewEnemyCount += HandleNewEnemyCount;
    }

    private void HandleNewEnemyCount(int count)
    {
        Text = count.ToString();
    }
}
```

## Defeat UI

In this lecture, we designed and coded a UI for the defeat screen. When the player is defeated, we raised an event from their `PlayerDeathState` class. Specifically, we decided to raise this event when the animation is finished.

```csharp
private void HandleAnimationFinished(StringName animName)
{
    GameEvents.RaiseEndGame();

    characterNode.QueueFree();
}
```

When the event is raised, we're subscribing to this event and then reparenting the node so that it doesn't get deleted.

```csharp
private void HandleEndGame()
{
    Reparent(GetTree().CurrentScene);
}
```

## Victory UI

In this lecture, we worked on the victory UI. When the player wins the game, the game should pause to prevent them from performing any other actions. Instead, we decided to display a victory screen to let the player know they've defeatd all enemies. The most important step in this process pausing the game when the event was raised.

```csharp
private void HandleVictory()
{
    containers[ContainerType.Stats].Visible = false;
    containers[ContainerType.Victory].Visible = true;

    GetTree().Paused = true;
}
```

In this method, we hid the stats UI and displayed the victory UI before pausing the game.

## Pause UI

In this lecture, we worked on creating a pause UI. We didn't really learn anything new in this lecture aside from learning how to toggle a boolean value. In the `_Input` method, we performed a few steps.

```csharp
public override void _Input(InputEvent inputEvent)
{
    if (!canPause) { return; }

    if (!Input.IsActionJustPressed(GameConstants.INPUT_PAUSE)) { return; }

    containers[ContainerType.Stats].Visible = GetTree().Paused;
    GetTree().Paused = !GetTree().Paused;
    containers[ContainerType.Pause].Visible = GetTree().Paused;
}
```

Firstly, we checked if the player can pause. If another UI element is visible, such as the defeat, start, or victory screen are displaying, the player shouldn't be able to pause. Next, we're checking the `Pause` action for a key press. If it wasn't pressed, we didn't bother running the rest of the method.&#x20;

Lastly, we toggled the stats,  `Paused` property, and pause UI. The order does matter since we don't want to use the `Paused` property twice for setting a property on a container.&#x20;
