CNN Türk12 EKİM BUGÜN HAVA DURUMU: İSTANBUL, İZMİR, ANKARA | Sıcak ve güneşli hava yerine sağanak geliyor!InquirerITCZ, easterlies to bring rains over parts of PHPunchFRSC mourns ex-corps marshal BiuESPN DeportesBrewers vino de atrás ante Dodgers y abrió con triunfo SCLNBollywood HungamaFIR register against Imran Khan and others over August Kranti Maidan protest: REPORTESPNFalcons QB Penix (rib) exits loss late, doesn't expect injury to be long term한겨레농민들, 전남광주 ‘농어촌기본소득 전면실시’ 방침에 “환영”ZDF heuteEntdecken Sie das ZDF-NachrichtenstudioVanguardCartoon: Petrol discount… offer valid while stock lastObservador DesportoSetembro foi o segundo mais quente de sempre01netMicrosoft intègre les applis Office directement dans CopilotThe Sydney Morning HeraldThe Age Good Food Guide Awards LIVE: All the winners and hats revealed
The Daily Newsstand · Free, Always
Monday, October 12, 2026

SUS для Unity: реактивность, навигация и компоненты в одном файле

Translate

В первой статье я рассказывал, как устроена наша надстройка над UI Toolkit: формат .sharq, генерация C# и темы оформления. Но почти не показал, как с её помощью писать интерфейс. Как обновить текст после нажатия кнопки? Где хранить состояние формы? Как переключать экраны и возвращаться к тому месту, на котором остановился игрок?

За это время SUS вырос из внутреннего инструмента. Ядро и роутер теперь доступны на GitHub с открытым исходным кодом. Их также можно установить бесплатным набором Core из Unity Asset Store. Там же есть Kit — набор с готовыми компонентами интерфейса. В этой статье разберу несколько примеров: от счётчика до навигации между экранами.

Что теперь можно попробовать

Основа SUS — два пакета. sus-core отвечает за компоненты, реактивные данные, генерацию кода и темы. sus-router добавляет переходы между экранами, историю навигации и модальные окна. Оба пакета можно взять на GitHub под MIT.

Если удобнее устанавливать через Asset Store, там уже есть два набора:

  • Sharq UI System Core — бесплатный набор с ядром и роутером.

  • Sharq UI System Kit — ядро, роутер и готовые компоненты: кнопки, поля ввода, таблицы, диалоги и другие элементы интерфейса.

Для пакетов с GitHub действует MIT, для наборов из Asset Store — лицензия Asset Store. Примеры ниже используют ядро, роутер и стандартные элементы UI Toolkit.

На сайте собраны документация и каталог компонентов. Там же можно открыть демо в браузере и посмотреть, как они ведут себя при взаимодействии.

Каталог компонентов SUS

Каталог компонентов SUS

Часть компонентов из Storybook — среды, где мы смотрим их состояния и проверяем поведение.

Счётчик: разметка, логика и стили рядом

Начну с небольшого примера. В .sharq разметка, C# и стили находятся в одном файле. Если вы работали с Vue, структура будет знакомой.

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

Вот как выглядит обычный счётчик:

<!-- Counter.sharq -->
<template>
  <ui:VisualElement $MainElement class="counter">
    <ui:Label :text="Count" class="counter__value" />
    <ui:Button text="+1" @click="OnInc" />
  </ui:VisualElement>
</template>

<script>
public Prop<int> Count = new(0);
private void OnInc() => Count.Value++;
</script>

<style>
.counter { flex-direction: row; align-items: center; }
.counter__value { font-size: 24px; margin-right: 12px; }
</style>

Prop<int> хранит число и сообщает об изменении. Запись :text="Count" связывает его с текстом Label. Кнопка вызывает OnInc(), число увеличивается, подпись обновляется. В обработчике не нужно искать лейбл и присваивать ему новый текст.

Чтобы показать компонент в UIDocument, используем SusApp:

SusApp.Create(uiDocument)
    .UseTheme(SusTheme.Dark)
    .Mount<Counter>();

Здесь uiDocument — ссылка на UIDocument в сцене, а Counter — класс, который редактор сгенерировал из нашего файла.

Реактивный счётчик

Реактивный счётчик

Счётчик в демо: кнопка меняет данные, связанные с ними подписи обновляются автоматически.

Сам .sharq нужен на этапе разработки. В редакторе Unity он превращается в C# и USS. В сгенерированном коде есть обычные вызовы, которые создают элементы и подключают биндинги. При запуске игры разбирать разметку заново не требуется.

Компиляция .sharq в C# и USS

Компиляция .sharq в C# и USS

Разметка и логика проходят через генератор в редакторе. В сборку попадает результат.

Форма: когда одно значение зависит от других

Со счётчиком всё просто. В форме обычно больше связей: подсказка зависит от введённых данных, а кнопка должна стать доступной только после проверки полей.

Для таких значений есть Computed<T>. Он запоминает результат и пересчитывает его при следующем чтении после изменения зависимостей. Зависимости определяются по обращениям к .Value внутри вычисления.

Ниже учебная форма регистрации. Проверка email намеренно упрощена; для настоящей регистрации понадобятся серверная проверка и обработка ошибок.

<!-- SignupForm.sharq -->
<template>
  <ui:VisualElement $MainElement class="form">
    <ui:TextField name="email" label="Email" @change="OnEmail" />
    <ui:TextField name="password" label="Password" @change="OnPassword" />
    <ui:Label :text="Hint" />
    <ui:Button name="submit" text="Sign up" @click="OnSubmit" />
  </ui:VisualElement>
</template>

<script>
public Prop<string> Email = new("");
public Prop<string> Password = new("");
public Computed<bool> CanSubmit;
public Computed<string> Hint;

protected override void Created()
{
    CanSubmit = C(() =>
        Email.Value.Contains("@") && Password.Value.Length >= 8);
    Hint = C(() => CanSubmit.Value
        ? "Можно отправлять"
        : "Укажите email и пароль от 8 символов");
}

protected override void Mounted()
{
    this.Q<TextField>("password").isPasswordField = true;
    var submit = this.Q<Button>("submit");
    WatchEffect(() => submit.SetEnabled(CanSubmit.Value));
}

void OnEmail() => Email.Value = this.Q<TextField>("email").value;
void OnPassword() => Password.Value = this.Q<TextField>("password").value;

void OnSubmit()
{
    if (!CanSubmit.Value) return;
    // Здесь можно вызвать сервис регистрации.
}
</script>

В Created() вычисляемые значения создаются один раз, до построения разметки. В Mounted() дочерние элементы уже доступны: здесь включаем маску пароля и связываем доступность кнопки с CanSubmit.

@change вызывает метод без аргумента события, поэтому значение поля в этом примере читается через Q<TextField>(). Подсказку обновляет биндинг в шаблоне, а кнопку — WatchEffect: он повторяет действие, когда меняются прочитанные внутри него реактивные значения.

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

Vue Router для UI Toolkit

Следующая задача — переключение экранов. У небольшого меню быстро появляются настройки, профиль, лобби, окно подтверждения. Нужно помнить, откуда пришёл пользователь, иногда запрещать переход, иногда сохранять состояние экрана.

В sus-router экрану назначается путь, например /settings или /user/42. Это адрес внутри интерфейса, он не требует веб-сервера. Push добавляет переход в историю, Replace заменяет текущую запись, Back возвращает назад.

Маршруты можно описать при запуске приложения:

using Sharq.Core;
using Sharq.Router;

SusApp.Create(GetComponent<UIDocument>())
    .UseTheme(SusTheme.Dark)
    .UseRouter(new SusRouter(), routes => routes
        .Route("/", typeof(HomeScreen)).Name("home")
        .Route("/user/:id", typeof(UserScreen)).KeepAlive()
        .Route("/settings", typeof(SettingsLayout)).Children(c => c
            .Route("profile", typeof(ProfileScreen))),
        initialPath: "/")
    .Run();

HomeScreen, UserScreen и остальные типы здесь — компоненты вашего проекта. У настроек есть вложенный экран profile, а :id обозначает параметр маршрута.

Переходы между экранами

Переходы между экранами

Пример навигации из пакета: вкладки и переходы через Push/Replace.

Проверка перед переходом

Допустим, часть экранов доступна только после входа. Общую проверку можно подключить через BeforeEach. Фрагмент из примера Guards:

_router.BeforeEach((from, to) =>
{
    if (to.FullPath == "/home") return true;
    if (!_isLoggedIn)
    {
        _statusChip.text = "Login required";
        return false;
    }
    return true;
});

Возвращаем false — переход отменяется. Аналогично можно проверить готовность игровой сессии перед входом в матч. Проверку для отдельного маршрута задаёт ISusRouteGuard; например, она может запретить уход с формы, где остались несохранённые изменения.

Возврат без потери состояния

Для одних экранов удобнее каждый раз создавать новый экземпляр. Для других хочется сохранить введённый текст или выбранную вкладку. За второй вариант отвечает KeepAlive:

_router.Register("/counter", typeof(CounterScreen),
    new SusRouteConfig { KeepAlive = true });
_router.Register("/form", typeof(FormScreen),
    new SusRouteConfig { KeepAlive = true });
_router.Register("/settings", typeof(SettingsScreen));

При уходе с /counter или /form роутер убирает экран из визуального дерева, но сохраняет его экземпляр в кэше. При возврате используется тот же экран с прежним состоянием. /settings в этом примере создаётся заново.

Модальные окна открываются поверх текущего экрана через OverlayHost. Для диалога подтверждения не нужно прятать основной экран и затем восстанавливать его вручную.

Модальное окно поверх экрана

Модальное окно поверх экрана

Пример модального окна из пакета роутера.

Примеры роутера используют обычные Button, Label и TextField из UI Toolkit. Их можно разобрать отдельно, а затем подключить свои компоненты или Kit.

Темы и готовые компоненты

В примере запуска уже был вызов UseTheme(SusTheme.Dark). SusApp подготавливает окружение интерфейса, подключает тему и создаёт слои для экранов и оверлеев. Для нового проекта есть мастер Setup Project в меню Window → SUS: он помогает создать конфигурацию и начальные файлы.

Токены тёмной темы

Токены тёмной темы

Пример цветов и других параметров тёмной темы.

Поверх ядра можно писать собственные компоненты. Если нужны готовые элементы, есть Kit: формы, таблицы, меню, диалоги. Я предлагаю их и как основу для своего интерфейса — своего рода скелеты компонентов с уже заданными стилями. Можно взять подходящий, изменить разметку и оформление, добавить нужные элементы и логику. Например, дополнить диалог своим блоком или перестроить форму под конкретный экран, сохранив ту часть, которая уже подходит.

Сейчас я также готовлю к публикации игровой пакет Game. В нём уже созданы более сложные составные компоненты: HUD, инвентарь, магазин и другие игровые интерфейсы. Их внешний вид и поведение можно посмотреть в каталоге на сайте. Идея та же: дать готовую основу, которую можно переделать и дополнить под свою игру.

Набор Sharq UI System Complete Bundle, в который входят Core, Kit и игровой пакет, готовится к повторной подаче в Asset Store. Ссылки на опубликованный Complete пока нет; доступные сейчас Core и Kit указаны в начале статьи.

Что видят инструменты отладки

Ещё одна полезная для нас возможность — получить состояние интерфейса в виде данных. В редакторе и development-сборках доступен SusUiProbe: он возвращает дерево элементов, значения свойств компонента и диагностику в JSON.

using Sharq.Core.Diagnostics;

var root = susApp.ScreenHost;
string tree = SusUiProbe.GetTreeJson(root);
string health = SusUiProbe.GetHealthJson(root);
string props = SusUiProbe.GetPropsJson(root, "HomeScreen");

В редакторе эти данные доступны и через MCP-инструменты. Так агент может прочитать структуру открытого экрана и проверить свойства элементов. Скриншот всё равно нужен, чтобы оценить внешний вид, но для вопроса «что сейчас находится в дереве?» уже есть более точный ответ.

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

Ограничения

  • Текущая версия рассчитана на Unity 6000.3 и новее.

  • SUS работает поверх UI Toolkit. Компоненты для uGUI/Canvas придётся писать отдельно.

  • .sharq компилируется в редакторе. Загрузить новый такой файл в готовую игру и исполнить его нельзя.

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

  • Роутер управляет интерфейсом. Загрузка игровых сцен, данных и ресурсов остаётся задачей приложения.

С чего начать

Для первого знакомства достаточно бесплатного Core: он включает и роутер. Установите набор, откройте примеры и попробуйте собрать один небольшой экран своего проекта.

Буду рад вопросам и примерам задач, на которых вы попробуете SUS. Особенно интересно, где привычный подход из веб-разработки помогает в Unity, а где приходится делать иначе.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.