# UI System

## How to use

Add **`using Game.UI;`** to use UI System API in code.

### Scene setup

1. Add prefab UI;
2. Find [***SceneSettuper***](https://reddycat.gitbook.io/base-project-cube-doc/fundamentals/scene-setup) object. If you don't see it -> [***create it***](https://reddycat.gitbook.io/base-project-cube-doc/scene-setup#how-to-add-it-to-new-scene)*.* \
   \&#xNAN;*In **SceneSettuper*** find ***SceneUI*** as child object;
3. <mark style="color:red;">**Replace all UIControllers**</mark> (GameCanvas and etc) <mark style="color:red;">**under SceneUI object;**</mark>

You will end up with this:

<div align="center"><figure><img src="https://1613353771-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fygjewtla1W7kzTTIpGWq%2Fuploads%2FWje4ew46mhVMuM8hxudT%2Fimage.png?alt=media&#x26;token=6e2909a1-56e8-427d-9397-ed969592777d" alt=""><figcaption><p>Scene objects for UI</p></figcaption></figure></div>

4. Set in SceneUI object reference to active canvas by default;

<figure><img src="https://1613353771-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fygjewtla1W7kzTTIpGWq%2Fuploads%2FlBpMjEGHwhPXP6T1cKa7%2Fimage.png?alt=media&#x26;token=ab885980-b254-4870-bc78-88231bde6fe7" alt=""><figcaption><p>Scene UI Controller in inspector</p></figcaption></figure>

You can add more UIControllers under SceneUI object. SceneUIContainer will setup [**UICanvasContainer**](#uicanvascontroller) references. You can leave field null if you want manualy set active canvas on start.

## How it works

**UIManager.cs** is main script that you will refer to get canvases and switch them.\
Each canvas must be inherited from UICanvasController.cs. All main prefab canvases are referenced in UICanvasContainer and UIManager requests their instances. Here is diagram:

**UICanvasContainer.cs** holds references to all UICanvasControllers in scene. By UIManager you can get target canvases.\ <mark style="color:red;">**As soon as scene starts -> all canvases will automaticaly parented to UI object by SceneUIContainer. Each time you load new scene -> all old UI objects will be destroyed by SceneSetupper;**</mark>

**Basic look of UIManager in the inspector:**

<figure><img src="https://1613353771-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fygjewtla1W7kzTTIpGWq%2Fuploads%2Ft1MocXepyozbeSYVXRFU%2Fimage.png?alt=media&#x26;token=4007fb08-ae73-428d-b879-a8b96031cf72" alt=""><figcaption></figcaption></figure>

As you can see it has reference resolution that is used to compare user and reference resolutions in other scripts. EventSystem prefab will be created automaticaly if there is no active in scene.

### UICanvasController

This is base of all canvases. You need to inherit it when implementing any type of canvas.\
It supports states and if you need it -> create UICanvasController that holds other UICanvasControllers as childs in scene hierarchy. It has built in fade in and out logic.

<figure><img src="https://1613353771-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fygjewtla1W7kzTTIpGWq%2Fuploads%2Fpzebhi1UGNIs8uP2lj4q%2Fimage.png?alt=media&#x26;token=375ef807-b497-4d5b-b0be-4a4fd537a2ce" alt=""><figcaption></figcaption></figure>

The above scheme is implemented in GameCanvas by default. It has Main/Win/Lose/Pause states.\
Here it's codea as example:

{% code lineNumbers="true" %}

```csharp
public class GameCanvas : UICanvasController {

    public MainState MainState; // UICanvasController 
    public WinState WinState;   // implementations
    public LoseState LoseState; // ..

    [SerializeField] private PauseState _pauseState; // Pause UICanvasController
    private UICanvasController _lastActiveState;     // private because used by PauseGame function only

    protected override void Awake() {
        base.Awake();
        _lastActiveState = _activeState;
    }

    public void PauseGame(bool active, float fadeDuration = 0.25f) {
        if (active) {
            SetState(_pauseState, fadeDuration);
        }
        else {
            SetState(_lastActiveState, fadeDuration);
        }
    }
}
```

{% endcode %}

And here is example how you can switch states of GameCanvas:

{% code lineNumbers="true" %}

```csharp
// get GameCanvas
var UI = UIManager.instance.GetCanvas<GameCanvas>();
// change state to Lose
UI.SetState(UI.LoseState);
```

{% endcode %}

{% hint style="warning" %}
UICanvasController has "activeState" field in inspector. Our GameCanvas is state-driven so you can set activeState reference to first level child canvas -> it will be enabled automaticaly when GameCanvas will be enabled too. Or leave "activeState" NULL -> so you need to set state manualy runtime.
{% endhint %}

{% hint style="danger" %}
If UICanvasController doesn't have states and acts as single canvas -> leave "activeState" NULL.
{% endhint %}

{% hint style="success" %} <mark style="color:green;">**Ready to use Canvas Transitions!**</mark>

[More information about transitions.](https://reddycat.gitbook.io/base-project-cube-doc/fundamentals/singletons/ui-system/canvas-transitions)
{% endhint %}

## API UIManager

{% code lineNumbers="true" %}

```csharp
/// <summary>
/// Manager for all ingame canvases except loaders
/// </summary>
[RequireComponent(typeof(UICanvasContainer))]
public class UIManager : MonoBehaviour {
    public static UIManager instance;
    
    /// <summary>
    /// Reference screen resolution, used to compare it with player's screen
    /// </summary>
    public Vector2 ReferenceResolution => _refResolution;
    /// <summary>
    /// Vector2 where x and y are refWidth/UserScreenWidth and refHeight/UserScreenHight
    /// </summary>
    public Vector2 RefAndUserWidthHightCoefs => _refAndUserWidthHightCoefs;
		
    public float ReferenceAspectRatio => _refResolution.x / _refResolution.y;
    public float UserAspectRatio => (float)Screen.width / Screen.height;
    public float UserAndRefAspectRatioCoef => UserAspectRatio / ReferenceAspectRatio;

    /// <summary>
    /// Visibility of UI by canvas group, returns true if it's visible.<br>
    /// If not visible then canvasGroup alpha = 0f</br>
    /// </summary>
    public bool IsVisibleUI;

    public UICanvasController ActiveCanvas => _activeCanvasController;

    /// <summary>
    /// Returns target non-custom canvas with casted type
    /// </summary>
    public T GetCanvas<T>() where T : UICanvasController;

    /// <summary>
    /// Smooth switch canvas to new instance <br>
    /// Note that child canvases you must switch in holder/parent canvas by SetState() </br>
    /// </summary>
    /// <param name="fadeOut">fade out time in seconds</param>
    /// <param name="fadeIn">fade in time in seconds</param>
    /// <returns>new canvas controller</returns>
    public void SwitchCanvasTo(UICanvasController canvas, float fadeOut = 0f, float fadeIn = 0f);

    /// <summary>
    /// Smooth switch canvas to new one by canvas type <br>
    /// Note that child canvases you must switch in holder/parent canvas by SetState() </br>
    /// </summary>
    /// <param name="fadeOut">fade out time in seconds</param>
    /// <param name="fadeIn">fade in time in seconds</param>
    /// <returns>new canvas controller</returns>
    public T SwitchCanvasTo<T>(float fadeOut = 0.25f, float fadeIn = 0.25f);

    public void DisableAllCanvases();

    public void DisableActiveCanvas();

    /// <param name="fadeOut">fade out duration in seconds</param>
    public void DisableActiveCanvas(float fadeOut);
```

{% endcode %}

## API UICanvasController

{% code lineNumbers="true" %}

```csharp
public class UICanvasController : MonoBehaviour {
    public static UnityEvent<UICanvasController> OnCreated = new UnityEvent<UICanvasController>();

    /// <summary>
    /// Child-canvases keep belong to their parent canvases!
    /// </summary>
    public bool IsChildCanvas => _isChildCanvas;

    /// Set it to false - no input will be handled <br>
    /// Set it to true - buttons will work, input handled</br>
    public bool RaycasterEnabled;
    
    /// <summary>
    /// For canvas holder/parent it's visibility status <br>
    /// For child canvases - will they be activated on holder/parent and visibility status too </br>
    /// </summary>
    public bool IsActive => _isActive;
    
    /// Does this canvas will have transition animation on enable / disable?
    public bool HasTransitionComponent;

    [Tooltip("Leave it null if it's single canvas.\n" +
        "If it's state-driven -> chose active state by default!")]
    [SerializeField] protected UICanvasController _activeState;

    protected virtual void Awake();

    /// <summary>
    /// Enables/Disables controller, and also it's child if state-driven and activeState != null <br>
    /// Makes it instantly </br>
    /// </summary>
    /// <param name="active">true - enable, false - disable</param>
    public void EnableCanvas(bool active);

    /// <summary>
    /// Enables/Disables controller, and also it's child if state-driven and activeState != null <br>
    /// Makes it smoothly if <paramref name="fadeDuration"/> > 0 </br>
    /// </summary>
    /// <param name="active">true - enable, false - disable</param>
    /// <param name="fadeDuration">time to fade canvas in or out (alpha change)</param>
    public virtual void EnableCanvas(bool active, float fadeDuration);

    /// <summary>
    /// Set new state of UICanvasController that is child of canvas where it's called
    /// </summary>
    /// <param name="state">Child state (don't set child of child)</param>
    /// <param name="fadeDuration">Smooth fade state change with value > 0f, or instant</param>
    public void SetState(UICanvasController state, float fadeDuration = 0f);

    /// <summary>
    /// Override it to init references as soon as possible
    /// </summary>
    internal virtual void InitReferences();
```

{% endcode %}

More examples you can find in **Assets/\_Main/\_Examples/UI System.**
