TweenerSystem
Namespace: Vortex.Unity.UI.TweenerSystem
Сборка: ru.vortex.unity.ui.misc
Назначение
Система анимаций на базе UniTask. Два режима: сценарный (TweenerHub + TweenLogic) и standalone (AsyncTween fluent API). Поверх сценарного — StateView<TEnum>: переключатель состояний, где каждое значение enum — свой TweenerHub.
Возможности:
- Сценарные анимации: Forward / Back / Pulse с поддержкой offset и switch-точек
StateView<TEnum>— состояния на твинерах: выбранное — Forward, остальные — Back; в инспекторе — таблица состояний и автосоздание хабов (Sync)- Горячие клавиши
Alt+T/Ctrl+Alt+T— добавитьTweenerHubна объект или отдельным слоем - 5 готовых TweenLogic: цвет, прозрачность CanvasGroup, масштаб, fillAmount, pivot
- Standalone fluent API для одноразовых анимаций из кода
- 16 типов easing + поддержка AnimationCurve
- Шорткаты для типовых операций (Move, Scale, Fade, Color, Slider)
Вне ответственности:
- Skeletal/sprite-анимации (Animator, DOTween)
- Анимации физики
Зависимости
| Зависимость | Назначение |
|---|---|
| UniTask | Асинхронные анимации (CancellationToken, UniTask.Yield) |
Vortex.Core.SettingsSystem |
Settings.Data() — debug-флаги |
Vortex.Unity.AppSystem |
TimeController.Accumulate() — аккумуляция вызовов |
Vortex.Unity.EditorTools |
[ClassLabel] |
| Odin Inspector | [ShowInInspector], [MinValue], [MaxValue]; OdinValueDrawer — шапка StateView |
| TextMeshPro | Поддержка в ColorLogic |
Архитектура
TweenerSystem/
├── TweenerHub.cs # Сценарный контроллер (MonoBehaviour)
├── TweenLogic.cs # Абстрактная база анимации
├── TweenPreset.cs # ScriptableObject: curve, duration, switch-флаги
├── StateView.cs # StateView<TEnum> + StateViewBase: TweenerHub на каждое состояние enum
├── TweenLogics/
│ ├── ColorLogic.cs # Цвет: Image, Text, TMP, SpriteRenderer
│ ├── CanvasOpacityLogic.cs # Прозрачность CanvasGroup + blocksRaycasts
│ ├── RectScaleLogic.cs # Масштаб RectTransform (Both/X/Y)
│ ├── FillImageLogic.cs # fillAmount Image
│ └── PivotLogic.cs # pivot RectTransform
├── UniTaskTweener/
│ ├── AsyncTween.cs # Standalone fluent API
│ ├── AsyncTweenExtensions.cs # Шорткаты (Move, Scale, Fade...)
│ └── Easing.cs # 16 типов easing
├── Editor/
│ ├── StateViewDrawer.cs # Шапка состояний StateView, кнопка Sync (Odin)
│ └── TweenerHubDrawer.cs # Кнопки Back / Forward под полем TweenerHub (Odin)
└── Debug/
├── Model/SettingsModelExtAsyncTweener.cs
└── Presets/DebugSettingsExtAsyncTweener.cs
Сценарный режим
TweenerHub (MonoBehaviour)
Управляет массивом TweenLogic. Привязывается к GameObject на сцене.
tweenerHub.Forward(); // воспроизведение вперёд
tweenerHub.Back(); // воспроизведение назад
tweenerHub.Pulse(); // переключение направления
tweenerHub.Forward(true); // мгновенный переход (skip)
Жизненный цикл:
Awake— инициализация всех TweenLogic (Init())OnEnable— возобновление отложенных анимацийOnDisable— снятие из очередиTimeControllerOnDestroy—DeInit()всех TweenLogic
В инспекторе под любым полем TweenerHub — кнопки Back и Forward (Editor/TweenerHubDrawer.cs): проверить анимацию, не заходя на сам хаб. Вне Play Mode переключение мгновенное, в Play Mode — с анимацией; пока поле пустое, кнопки недоступны. Кнопки есть и у элементов массива хабов в StateView.
TweenLogic (abstract, Serializable)
Базовый класс анимации. Наследники реализуют SetValue(float value) для интерполяции 0→1.
| Поле | Тип | Описание |
|---|---|---|
preset |
TweenPreset |
Кривая, длительность, switch-флаги |
offset |
float |
Задержка Forward (секунды) |
offsetBack |
float |
Задержка Back (секунды) |
Абстрактные методы:
| Метод | Описание |
|---|---|
SetValue(float) |
Применение интерполированного значения |
SwitchOn() |
Активация визуального элемента |
SwitchOff() |
Деактивация визуального элемента |
OnStart() |
Callback начала анимации |
OnEnd() |
Callback завершения анимации |
Состояние: _isForward, _progress (0..1), _cts (CancellationTokenSource). Поддерживает смену направления во время воспроизведения с пересчётом elapsed time.
TweenPreset (ScriptableObject)
| Поле | Тип | Описание |
|---|---|---|
curve |
AnimationCurve |
Кривая easing |
duration |
float |
Длительность (0..5 сек) |
offOnStartPoint |
bool |
Деактивировать элемент в точке 0 |
offOnEndPoint |
bool |
Деактивировать элемент в точке 1 |
Реализации TweenLogic
| Класс | Цель | Что анимирует |
|---|---|---|
ColorLogic |
Image[], Text[], TMP[], SpriteRenderer[] | Цвет (Lerp start→end) |
CanvasOpacityLogic |
CanvasGroup[] | alpha; blocksRaycasts управляется асимметрично (start ≠ end) |
RectScaleLogic |
RectTransform[] | localScale (режим Both / X only / Y only) |
FillImageLogic |
Image[] | fillAmount |
PivotLogic |
RectTransform | pivot (Vector2 Lerp startPos→endPos) |
StateView<TEnum> (поле-класс)
Переключатель состояний на твинерах: на каждое значение enum — свой TweenerHub. У выбранного состояния хаб в Forward, у остальных — в Back. Альтернатива UIStateSwitcher, когда состояния — это анимации.
public enum GalleryState { Off, NaniCutscene, Image }
[SerializeField] private StateView<GalleryState> playView;
playView.Set(GalleryState.Image); // Image — Forward, Off и NaniCutscene — Back
playView.Set(GalleryState.Off, true); // без анимации
var current = playView.State;
playView.Apply(); // привести хабы к текущему состоянию
| Член | Описание |
|---|---|
Set(TEnum value, bool skip = false) |
Выставить состояние: хаб выбранного — Forward, остальные — Back; skip — без анимации |
State |
Текущее состояние |
Apply(bool skip = false) |
Привести хабы к текущему состоянию — например, из OnEnable владельца |
Устройство:
[Serializable]-класс — поле любого MonoBehaviour; сериализуютсяstate(текущее состояние) иhubs(хабы).- Хабы идут по порядку значений enum (
Enum.GetValues), а не по их числам: enum с пропусками (A = 0, B = 5) работает. - Общая часть — неgeneric-основа
StateViewBase: один drawer обслуживает поле с любым enum. - Жизненного цикла у поля нет. При включении хабы сами возвращаются в последнее положение (изначально
Back); чтобы привести их к сохранённомуstate, владелец вызываетApply(). - Пустой элемент массива пропускается.
Инспектор (StateViewDrawer, Odin):
- над полем — таблица состояний, как у
[StateSwitcher]: номер, подпись (изTooltip/LabelTextзначения enum, иначе имя), назначенный хаб или[None]; активное состояние подсвечено; - клик по строке — переключение с Undo; вне Play Mode хабы переключаются мгновенно;
- Sync — подгоняет длину массива под число состояний и каждому пустому состоянию создаёт дочерний слой владельца
[{поле}_{состояние}_Tween]сTweenerHub, какCtrl+Alt+T. Слои выстраиваются в порядке enum, всё отменяется одним шагом Undo. Ассет префаба в Project не синхронизируется — префаб нужно открыть.
Горячие клавиши
Для выделенных объектов сцены или открытого префаба (UI/UIBuilder/Shortcuts/TweenerHubShortcut.cs):
| Сочетание | Меню | Действие |
|---|---|---|
Alt+T |
Tools/Vortex/UI/Add TweenerHub |
Добавить TweenerHub на сам объект; где он уже есть — пропуск |
Ctrl+Alt+T |
Tools/Vortex/UI/Add TweenerHub Layer |
Дочерний слой [TweenerHub] с хабом: первым в иерархии, в нулевой точке, на обычном Transform (RectTransform снимается); новые слои выделяются |
Отмена — одним шагом Undo. Пункты меню живут в пакете UIBuilder вместе с остальными горячими клавишами вёрстки; добавление компонента и создание слоя — общий код EditorTools/HierarchyTools/HierarchyLayers.cs, им же пользуется Sync у StateView.
Standalone режим (AsyncTween)
Namespace: Vortex.Unity.UI.TweenerSystem.UniTaskTweener
Fluent API для одноразовых анимаций без привязки к сцене:
new AsyncTween()
.Set(() => transform.localScale, v => transform.localScale = v, Vector3.one, 0.3f)
.SetEase(EaseType.OutBack)
.OnComplete(() => Debug.Log("Done"))
.OnUpdate(progress => { })
.Run();
| Метод | Описание |
|---|---|
Set(getter, setter, target, duration) |
Конфигурация (float, Vector2, Vector3, Color) |
SetEase(EaseType) / SetEase(AnimationCurve) |
Кривая анимации |
OnComplete(Action) |
Callback завершения (не вызывается при Kill) |
OnKill(Action) |
Callback при прерывании через Kill (не вызывается при нормальном завершении) |
OnUpdate(Action<float>) |
Callback каждого кадра (progress 0..1) |
SetToken(CancellationToken) |
Внешний токен отмены |
Run() |
Запуск (возвращает self для цепочки). Параметры сбрасываются после запуска |
Kill() |
Отмена анимации, вызывает OnKill |
SetPause(bool) |
Заморозить / отпустить: на паузе время не копится, значение стоит, после снятия анимация идёт с того же места. Флаг экземпляра — переживает Run и Kill: запуск на паузе стартует замороженным |
Свойства: Progress (float 0..1), IsPlaying (bool), IsPaused (bool).
Пауза твинера ничего не знает о паузе игры: её ставит владелец твина (например, хэндлер паузы игры уровня Sdk).
Шорткаты (AsyncTweenExtensions)
new AsyncTween().SetLocalMove(transform, targetPos, 0.5f).Run();
new AsyncTween().SetMove(transform, worldPos, 0.5f).Run();
new AsyncTween().SetScale(transform, Vector3.zero, 0.2f).SetEase(EaseType.InBack).Run();
new AsyncTween().SetFade(canvasGroup, 0f, 0.3f).Run();
new AsyncTween().SetColor(graphic, Color.red, 0.4f).Run();
new AsyncTween().SetSlider(slider, 0.75f, 0.5f).Run();
new AsyncTween().SetSize(rectTransform, newSize, 0.3f).Run();
new AsyncTween().SetAnchoredMove(rectTransform, anchoredPos, 0.4f).Run();
new AsyncTween().SetPivot(rectTransform, newPivot, 0.3f).Run();
Easing
16 типов: Linear, InQuad, OutQuad, InOutQuad, InCubic, OutCubic, InOutCubic, InBack, OutBack, InOutBack, InElastic, OutElastic, InOutElastic, InBounce, OutBounce, InOutBounce.
Debug
Settings.Data().AsyncTweenerDebugMode — включается в ассете DebugSettings (toggle asyncTweenerLogs).
Граничные случаи
| Ситуация | Поведение |
|---|---|
| Смена направления во время анимации | Корректный пересчёт elapsed time |
AsyncTween с duration ≤ 0 |
Мгновенное применение + OnComplete (паузу не ждёт) |
AsyncTween на паузе (SetPause(true)) |
Цикл идёт, время не копится, OnUpdate не зовётся; Kill и токен отмены работают как обычно |
TweenerHub на OnDisable |
Снимается из очереди TimeController |
Forward(skip: true) |
Мгновенный переход без анимации |
Pulse() во время анимации |
Очередь Pulse после текущего tween |
CanvasOpacityLogic Forward→Back |
blocksRaycasts управляется асимметрично |
Kill() на AsyncTween |
Отмена через CancellationTokenSource, OnComplete не вызывается, OnKill вызывается |
Run() после Set() |
Параметры fluent-цепочки сбрасываются (ResetParams), но OnKill сохраняется до завершения или следующего Kill |
Повторный Run() без Set() |
Мгновенное применение (duration = 0), OnComplete вызывается |
У состояния StateView нет хаба |
Set / Apply пропускают пустой элемент |
Значение удалено из enum StateView |
Sync укорачивает массив; слой удалённого состояния остаётся в иерархии — удалить вручную |
| Sync на ассете префаба в Project | Ошибка в лог: слои создаются только в сцене или открытом префабе |