> For the complete documentation index, see [llms.txt](https://docs.allout.game/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.allout.game/all-out-docs/ru/ui/fundamentals.md).

# Основы UI

***

Добавление UI в вашу игру требует написания кода, но как только вы освоите несколько шаблонов, вы сможете быстро создавать чистые, масштабируемые интерфейсы. Это руководство проведет вас по пошаговому туториалу, который заканчивается полным примером диалога.

{% hint style="info" %}
Весь UI для игрока должен рисоваться внутри `ao_late_update` стека вызовов этого игрока и оборачиваться в `is_local_or_server()`. Это предотвращает появление UI не у того клиента. Не рисуйте UI игрока из глобальных или неигровых callback-компонентов.
{% endhint %}

В любой момент вы можете перейти к [Справочник UI](/all-out-docs/ru/ui/ui-reference.md) для большего количества шаблонов и более подробной информации.

### Шаг 1: Создайте точку входа UI

Весь интерактивный UI должен рисоваться из `ao_late_update`:

```go
Player :: class : Player_Base {
    ao_late_update :: method(dt: float) {
        if this.is_local_or_server() {
            draw_ui(this);
        }
    }
}
```

### Шаг 2: Начните с экранного прямоугольника

Экранный UI всегда должен выводиться из `UI.get_safe_screen_rect()` или `UI.get_screen_rect()`. Помните: (0, 0) — это левый нижний угол, а Y увеличивается вверх.

Размеры в экранном пространстве, передаваемые обычным вспомогательным функциям rect, **точки** определяются на эталонном холсте высотой 1080 пунктов. Движок масштабирует эти пункты до фактических пикселей устройства, поэтому одна и та же компоновка сохраняет одинаковый относительный размер при любых разрешениях.

```go
draw_ui :: proc(player: Player) {
    screen := UI.get_safe_screen_rect();

    // Простой центрированный панель
    panel := screen.center_rect().grow(120, 200, 120, 200);
    UI.quad(panel, core_globals.white_sprite, {0, 0, 0, 0.7});
}
```

### Шаг 3: Используйте cut для компоновки

При размещении нескольких элементов вырезайте пространство из прямоугольника вместо того, чтобы позиционировать все от одного и того же начала.

```go
draw_panel_layout :: proc() {
    panel := UI.get_safe_screen_rect().center_rect().grow(140, 220, 140, 220);

    header := panel.cut_top(80);
    footer := panel.cut_bottom(70);
    body := panel;

    UI.quad(header, core_globals.white_sprite, {0.1, 0.1, 0.1, 0.8});
    UI.quad(body, core_globals.white_sprite, {0.05, 0.05, 0.05, 0.8});
    UI.quad(footer, core_globals.white_sprite, {0.1, 0.1, 0.1, 0.8});
}
```

### Шаг 4: Добавьте текст

Используйте настройки текста для управления размером, цветом и выравниванием.

```go
draw_header_text :: proc(rect: Rect) {
    ts := UI.default_text_settings();
    ts.size = 52;
    ts.color = {1, 1, 1, 1};
    ts.halign = .CENTER;
    ts.valign = .CENTER;

    UI.text(rect, ts, "Новое задание!");
}
```

### Шаг 5: Добавьте кнопки

Кнопки объединяют компоновку и взаимодействие. Используйте спрайт кнопки из ассетов, предоставляемых движком (см. [Справочник UI](/all-out-docs/ru/ui/ui-reference.md) для большего).

```go
draw_button :: proc(rect: Rect) {
    bs := UI.default_button_settings();
    ts := UI.default_text_settings();

    bs.sprite = get_asset(Texture_Asset, "$AO/new/modal/buttons_2/button_2.png");
    bs.press_scaling = 0.35;

    if UI.button(rect, bs, ts, "Принять").clicked {
        log_info("Принято!");
    }
}
```

### Шаг 6: Создайте диалог

Теперь объедините все шаги в повторно используемую компоновку диалога.

```go
draw_dialog :: proc(title: string, body: string) {
    screen := UI.get_safe_screen_rect();
    dialog := screen.center_rect().grow(200, 300, 200, 300);

    UI.quad(dialog, core_globals.white_sprite, {0, 0, 0, 0.85});

    content := dialog.inset(30);
    header := content.cut_top(80);
    buttons := content.cut_bottom(90);
    body_rect := content;

    ts := UI.default_text_settings();
    ts.halign = .CENTER;
    ts.valign = .CENTER;

    ts.size = 52;
    UI.text(header, ts, title);

    ts.size = 36;
    UI.text(body_rect, ts, body);

    bs := UI.default_button_settings();
    bs.sprite = get_asset(Texture_Asset, "$AO/new/modal/buttons_2/button_2.png");
    bs.press_scaling = 0.35;

    left := buttons.cut_left(210);
    buttons.cut_left(20);
    right := buttons.cut_left(210);

    if UI.button(left, bs, ts, "Отмена").clicked {
        log_info("Отменено");
    }
    if UI.button(right, bs, ts, "Подтвердить").clicked {
        log_info("Подтверждено");
    }
}
```
