Перейти к основному содержимому

Кастомизация

Собственная реализация портов

Общее

Для создания собственной реализации:

  • Наследуйтесь от PassageBase или TeleportBase, либо реализуйте ITransitionComponent;
  • Используйте класс PortsDropdown и соответствующие методы в RefreshContext или EditorGraph для создания выпадающих списков для инициализации текущего порта или выбора любого порта на графе;
  • Реализуйте метод GetGuid(), возвращающий Guid текущего порта;
  • В редакторе реализуйте Refresh(RefreshContext context) — полное описание методов контекста см. в RefreshContext.

PassageBase, TeleportBase и ITransitionComponent

PassageBase и TeleportBase — абстрактные базовые классы для прохода и телепорта: в них уже проведена работа с PortsDropdown и полями. Для большинства случаев достаточно наследоваться от одного из них и переопределить нужные методы (например, GetSpawnPosition()).

ITransitionComponent — минимальный контракт «порт на сцене»:

  • string GetGuid() — идентификатор порта в графе.
  • Vector3 GetSpawnPosition() — позиция появления персонажа у этого порта.

Дополнительно в редакторе ожидается метод void Refresh(RefreshContext context) — см. RefreshContext.

Если не подходят готовые базовые классы, можно реализовать только ITransitionComponent и написать логику самостоятельно (см. примеры).

подсказка

Метод Refresh() рекомендуется обернуть в #if UNITY_EDITOR, так как он нужен только в редакторе.

Методы расширения

Для ITransitionComponent так же предусмотрены методы расширения. IsInput(manager) и IsOutput(manager) позволяют узнать, является ли текущий компонент начальным или конечным для перехода (через который персонаж вошел/вышел). Менеджер передаётся явно, поэтому методы одинаково работают как со встроенным, так и с собственным TransitionManager.

МетодНазначение
IsOutput(manager)true если это компонент, в котором закончен переход.
IsInput(manager)true если это компонент, из которого начат переход.
примечание

Перегрузки без параметра (IsOutput(), IsInput()) помечены [Obsolete] и используют TransitionManager.Instance. Если в проекте включён собственный TransitionManager, они выбросят исключение — используйте перегрузки с явным manager.

IsShortcutOrigin() и IsShortcutDestination() позволяют узнать, является ли текущий компонент для shortcut-связи между сценами входным или выходным. Аналогично IsOneWayOrigin() и IsOneWayDestination() — для one-way-связей. Эти методы не требуют менеджера и читают граф напрямую.

МетодНазначение
IsShortcutDestination()true если компонент является "выходным" для shortcut
IsShortcutOrigin()true если компонент является "входным" для shortcut
IsOneWayDestination()true если компонент является "выходным" для one-way
IsOneWayOrigin()true если компонент является "входным" для one-way
подсказка

Если тип связи не совпадает (например, вызвать IsShortcutOrigin() для one-way связи) - метод вернёт false.

RefreshContext

RefreshContext — структура, которую редактор передаёт в метод void Refresh(RefreshContext context) у компонентов с интерфейсом ITransitionComponent. Используется только в редакторе. При смене сцены, иерархии и обновлениях графа вызывается Refresh, чтобы подтянуть актуальные Guid портов в PortsDropdown и связанные поля.

Поля:

ИмяТипОписание
EditorGraphEditorGraphГраф текущего контейнера. Используется для ручного доступа к данным, если не хватает методов ниже.

Методы:

МетодНазначение
void FillPortsDropdownData(PortsDropdown dropdown)Заполняет список портами активной сцены.
void FillAllPortsDropdownData(PortsDropdown dropdown)Заполняет список всеми портами графа из контейнера.

Методы переходов в TransitionManager

Task LoadSceneAsync(int buildIndex, TransitionContext context = null)

Загружает сцену по переданному индексу.

Параметры:

ИмяТипОписание
buildIndexintBuild Index сцены.
contextTransitionContextОпциональные параметры задержки между фазами перехода.

Task GoFromAsync(string currentPortGuid, bool ignoreShortcuts, ITransitionContext context = null)

Перемещает игрока к противоположному порту, опираясь на связи в графе.

Параметры:

ИмяТипОписание
currentPortGuidstringGuid текущего порта.
ignoreShortcutsboolИгнорировать ли шорткаты.
contextITransitionContextВстроенный TransitionManager работает только с объектом TransitionContext, позволяющий задавать параметры задержки между фазами перехода.

Task GoToAsync(string currentPortGuid, string targetPortGuid, TransitionContext context = null)

Перемещает игрока на любой выбранный порт. Не опирается на связи в графе.

Параметры:

ИмяТипОписание
currentPortGuidstringGuid текущего порта
targetPortGuidstringGuid целевого порта
contextITransitionContextВстроенный TransitionManager работает только с объектом TransitionContext, позволяющий задавать параметры задержки между фазами перехода.

примечание

Методы GoToAsync / GoFromAsync / LoadSceneAsync возвращают Task — их можно ожидать через await. Для вызова без ожидания (fire-and-forget) используйте _ = TransitionManager.Instance.GoFromAsync(...). Старые синхронные методы GoTo / GoFrom / LoadScene помечены [Obsolete]. У встроенного менеджера также есть перегрузка GoFromAsync(currentPortGuid, context) без ignoreShortcuts — как в интерфейсе ITransitionManager.

Примеры GoToAsync/GoFromAsync

Пример минимальной рабочей реализации собственного прохода с помощью GoFromAsync:

using UnityEngine;

namespace WorldGraphEditor.Examples
{
public class ExamplePassage : MonoBehaviour, ITransitionComponent
{
[SerializeField] private PortsDropdown _assignedPort = new();

private string _currentGuid;

// Любой вызов, например при входе в триггер
private void OnTriggerEnter(Collider other)
{
// Вызов GoFromAsync
_ = TransitionManager.Instance.GoFromAsync(_currentGuid);
}

#if UNITY_EDITOR
public void Refresh(RefreshContext context)
{
context.FillPortsDropdownData(_assignedPort);
_currentGuid = _assignedPort.GetSelectedValue();
}
#endif
public Vector3 GetSpawnPosition() => transform.position;

public string GetGuid() => _currentGuid;
}
}

Пример минимальной рабочей реализации собственного телепорта с помощью GoToAsync:

using UnityEngine;

namespace WorldGraphEditor.Examples
{
public class ExampleTeleport : MonoBehaviour, ITransitionComponent
{
[SerializeField] private PortsDropdown _assignedPort = new();
[SerializeField] private PortsDropdown _targetPort = new();

private string _currentGuid;
private string _targetGuid;

// Любой вызов, например при входе в триггер
private void OnTriggerEnter(Collider other)
{
// Вызов GoToAsync
_ = TransitionManager.Instance.GoToAsync(_currentGuid, _targetGuid);
}

#if UNITY_EDITOR
public void Refresh(RefreshContext context)
{
context.FillPortsDropdownData(_assignedPort);
context.FillAllPortsDropdownData(_targetPort);

_currentGuid = _assignedPort.GetSelectedValue();
_targetGuid = _targetPort.GetSelectedValue();
}
#endif

public Vector3 GetSpawnPosition() => transform.position;

public string GetGuid() => _currentGuid;
}
}

TransitionContext

TransitionContext — это класс, позволяющий переопределить задержку между фазами для текущего перехода. Может быть передан в качестве дополнительного параметра в GoToAsync, GoFromAsync и LoadSceneAsync.

Пример

_ = TransitionManager.Instance.GoFromAsync(_port.GetSelectedValue(), true,
new TransitionContext
{
PortEnteredDelay = new TransitionDelayData(DelayType.ThisFrame),
TransitionStartedDelay = new TransitionDelayData(DelayType.CustomDelay, 1.2f)
});

PortsDropdown

PortsDropdown — это класс, предназначенный для создания выпадающих списков, связанных с портами в графе. Он обеспечивает сохранность выбранного значения даже при переименовании портов или изменении их количества на ноде.

Содержит два метода:

string GetSelectedValue()

Возвращаемые значения:

ТипОписание
stringВыбранное значение (Guid)

void SetData(IEnumerable<(string Guid, string DisplayName)> data)

Обновляет данные для выпадающего списка, состоящие из Guid и отображаемого имени. Параметры:

ИмяТипОписание
dataIEnumerable<(string Guid, string DisplayName)>Данные, где каждый элемент содержитGuid и имя для отображения

Низкоуровневый доступ: EditorGraph и PortsDropdown

В типичном сценарии для заполнения PortsDropdown данными из графа в Refresh(RefreshContext context) достаточно вызвать context.FillPortsDropdownData(dropdown) или context.FillAllPortsDropdownData(dropdown) — см. RefreshContext.

Ниже описаны методы EditorGraph (доступен через context.EditorGraph или WorldGraphContainer.EditorGraph): они возвращают сырые последовательности для SetData, если нужна фильтрация, объединение с другими данными или иная кастомная сборка списка. Полная поверхность EditorGraph — в API: IWorldGraph, WorldGraph и EditorGraph.

Использование только в редакторе.

IEnumerable<(string Guid, string Name)> GetPortsDropdownData(string scenePath)

Параметры:

ИмяТипОписание
scenePathstringПуть к ассету сцены (файл .unity), как у Scene.path.

Возвращаемые значения:

ТипОписание
IEnumerable<(string Guid, string Name)>Данные обо всех портах на сцене. Их Guid и отображаемое имя

Пример

Рекомендуемый способ — через RefreshContext:

using UnityEngine;

namespace WorldGraphEditor.Examples
{
public class MyComponentWithDropdown : MonoBehaviour, ITransitionComponent
{
[SerializeField] private PortsDropdown _dropdown = new();
private string _currentPortGuid;

#if UNITY_EDITOR
public void Refresh(RefreshContext context)
{
context.FillPortsDropdownData(_dropdown);
_currentPortGuid = _dropdown.GetSelectedValue();
}
#endif
// public Vector3 GetSpawnPosition() {}
// public string GetGuid() {}
}
}

Вариант через EditorGraph:

using UnityEngine;
using UnityEngine.SceneManagement;

namespace WorldGraphEditor.Examples
{
public class MyComponentWithDropdown : MonoBehaviour, ITransitionComponent
{
[SerializeField] private PortsDropdown _dropdown = new();

private string _currentPortGuid;

#if UNITY_EDITOR
public void Refresh(RefreshContext context)
{
var scenePath = SceneManager.GetActiveScene().path;
var scenePortsData = context.EditorGraph.GetPortsDropdownData(scenePath);

_dropdown.SetData(scenePortsData);
_currentPortGuid = _dropdown.GetSelectedValue();
}
#endif
// public Vector3 GetSpawnPosition() {}
// public string GetGuid() {}
}
}
примечание

Перегрузка GetPortsDropdownData(int buildIndex) помечена как [Obsolete]. Предпочтительно использовать вариант с scenePath, чтобы не зависеть от порядка сцен в Build Settings.


IEnumerable<(string Guid, string Path)> GetAllPortsDropdownData()

Возвращает данные обо всех портах на графе, группируя их по сценам.

Возвращаемые значения:

ТипОписание
IEnumerable<(string Guid, string Path)>Данные обо всех портах на графе

Пример

Рекомендуемый способ — через RefreshContext:

using System;
using UnityEngine;

namespace WorldGraphEditor.Examples
{
public class MyComponentWithDropdown : MonoBehaviour, ITransitionComponent
{
[SerializeField] private PortsDropdown _dropdown = new();

private string _currentPortGuid;

#if UNITY_EDITOR
public void Refresh(RefreshContext context)
{
context.FillAllPortsDropdownData(_dropdown);
_currentPortGuid = _dropdown.GetSelectedValue();
}
#endif
// public Vector3 GetSpawnPosition() {}
// public string GetGuid() {}
}
}

Вариант через EditorGraph:

using System;
using UnityEngine;

namespace WorldGraphEditor.Examples
{
public class MyComponentWithDropdown : MonoBehaviour, ITransitionComponent
{
// Выпадающий список
[SerializeField] private PortsDropdown _dropdown = new();
private string _currentPortGuid;

#if UNITY_EDITOR
public void Refresh(RefreshContext context)
{
var allPortsData = context.EditorGraph.GetAllPortsDropdownData();
_dropdown.SetData(allPortsData);
_currentPortGuid = _dropdown.GetSelectedValue();
}
#endif
// public Vector3 GetSpawnPosition() {}
// public string GetGuid() {}
}
}

Выталкивание из проходов

Вы можете добавить "силу выталкивания" для порта, реализовав интерфейс IPusher и метод GetPushData(), возвращающий PushData.

PushData это структура, содержащая в себе два поля:

  • Force — Сила выталкивания
  • Exists — Указывает, существует сила или нет
public readonly struct PushData {
public readonly Vector3 Force;
public readonly bool Exists;

public PushData(Vector3 force)
{
Force = force;
Exists = true;
}
}

Пример

using UnityEngine;

namespace WorldGraphEditor.Examples
{
public class MyPushingPassage : PassageBase, IPusher
{
[SerializeField] private Vector2 _pushForce;

public PushData GetPushData()
{
// Если сила (0, 0), то можно вернуть PushData со значениями по умолчанию
if (_pushForce == Vector2.zero)
// Возвращает значение по умолчанию, где Exists будет false
return default;

// Если сила есть, то ее можно передать в конструктор. Exists в таком случае станет true
return new PushData(_pushForce);
}

// Прочие методы
//...
}
}

Чтобы применить эту силу к объекту игрока, используйте TransitionManager.Instance.PushData для получения актуального значения.

Пример

using UnityEngine;

namespace WorldGraphEditor.Examples
{
public class PlayerController : MonoBehaviour
{
[SerializeField] private Rigidbody2D _rigidbody;

private void OnTransitionEnded()
{
// Получение силы выталкивания
var pushData = TransitionManager.Instance.PushData;
// Применение силы к Rigidbody только если она существует
if (pushData.Exists)
_rigidbody.AddForce(pushData.Force, ForceMode2D.Impulse);
}

private void Awake()
{
TransitionManager.Instance.TransitionEnded += OnTransitionEnded;
}

private void OnDestroy()
{
TransitionManager.Instance.TransitionEnded -= OnTransitionEnded;
}
}
}

Замена встроенного TransitionManager

По умолчанию используется встроенный TransitionManager, но вы можете полностью заменить его своей реализацией — например, для интеграции с DI-фреймворком (Zenject, VContainer и т.п.) или для другой архитектуры загрузки сцен.

Включение

  1. Откройте Edit → Project Settings → World Graph Editor (см. Настройки проекта);
  2. Включите чекбокс Use Custom Transition Manager;
  3. В появившемся поле Container укажите тот же WorldGraphContainer, что используется в графе.

После включения этого чекбокса встроенный TransitionManager не создаётся автоматически при старте игры. Инициализацию менеджера в этом случае полностью берёт на себя ваш код (например, DI-контейнер).

Интерфейс ITransitionManager

public interface ITransitionManager
{
public IWorldGraph Graph { get; }
public Vector3 NextSpawnPosition { get; }

public ITransitionComponent? OutputTransitionComponent { get; }
public ITransitionComponent? InputTransitionComponent { get; }

public event Action TransitionStarted;
public event Action SceneLoaded;
public event Action TransitionEnded;

public Task GoToAsync(string currentPortGuid, string targetPortGuid, ITransitionContext context = null);

public Task GoFromAsync(string currentPortGuid, ITransitionContext context = null);
}
  • Graph — рантайм-граф контейнера; получить его можно через WGEProjectConfig.Instance.GetWorldGraph().
  • OutputTransitionComponent / InputTransitionComponent — порты, между которыми происходит текущий или последний переход. Используются методами расширения IsOutput(manager) / IsInput(manager) (см. Методы расширения).
  • GoToAsync / GoFromAsync — асинхронные точки входа для запуска перехода: GoToAsync — телепорт между двумя произвольными портами, GoFromAsync — переход из текущего порта по связи в графе. Оба метода возвращают Task; флаг ignoreShortcuts из интерфейса убран — допустимость перехода определяет сама реализация ITransitionManager.

Для поиска и перемещения по графу у IWorldGraph (реализация — класс WorldGraph, наследующий GraphEngine) доступны методы CanPassTransition(guid, ignoreShortcuts, out status), TryGetPassageTransitionData(guid, out data), GetTeleportTransitionData(currentGuid, targetGuid), TryGetOppositePassageGuid и другие — полная таблица в API: IWorldGraph, WorldGraph и EditorGraph. Чтобы найти компонент порта на загруженной сцене, используйте TransitionComponentUtility.FindByGuid(portGuid).

примечание

При включённом собственном менеджере методы-расширения IsOutput() / IsInput() без параметра выбросят исключение — используйте IsOutput(manager) / IsInput(manager), передавая свой экземпляр ITransitionManager (см. Методы расширения).

Пример: реализация на Zenject

Готовый демо-проект, показывающий реализацию ITransitionManager через DI, доступен по ссылке.

Регистрация графа и сервиса в контейнере:

public class TransitionManagerProjectInstaller : MonoInstaller
{
public override void InstallBindings()
{
var graph = WGEProjectConfig.Instance.GetWorldGraph();

Container.BindInterfacesAndSelfTo<WorldGraph>().FromInstance(graph)
.AsSingle();

Container.BindInterfacesAndSelfTo<TransitionManagerService>()
.AsSingle();
}
}

Сам сервис (TransitionManagerService) получает IWorldGraph через конструктор и реализует переход через смену сцены:

public class TransitionManagerService : ITransitionManager
{
public IWorldGraph Graph { get; }

public ITransitionComponent OutputTransitionComponent { get; private set; }
public ITransitionComponent InputTransitionComponent { get; private set; }

public event Action TransitionStarted;
public event Action SceneLoaded;
public event Action TransitionEnded;

public Vector3 NextSpawnPosition { get; private set; }

public TransitionManagerService(IWorldGraph graph)
{
Graph = graph;
}

public async Task GoFromAsync(string currentPortGuid, ITransitionContext context = null)
{
// Проверка что переход можно совершить
if (!Graph.CanPassTransition(currentPortGuid, false, out var status))
{
Debug.LogWarning($"Can`t pass transition, reason: {status}");
return;
}

// Для GoFromAsync используется метод TryGetPassageTransitionData
if (!Graph.TryGetPassageTransitionData(currentPortGuid, out var data))
{
Debug.LogError("No transition data for this passage");
return;
}

await GoInternal(data);
}

public async Task GoToAsync(string currentPortGuid, string targetPortGuid, ITransitionContext context = null)
{
// Для GoToAsync используется метод GetTeleportTransitionData
var data = Graph.GetTeleportTransitionData(currentPortGuid, targetPortGuid);

await GoInternal(data);
}

private async Task GoInternal(RuntimeTransitionData data)
{
TransitionStarted?.Invoke();

// Использование TransitionComponentUtility для поиска портов на сцене
InputTransitionComponent = TransitionComponentUtility
.FindByGuid(data.CurrentPassageGuid);

// Загрузка сцены по ее Build Index
await SceneManager.LoadSceneAsync(data.TargetSceneBuildIndex);

// Использование TransitionComponentUtility для поиска портов на сцене
OutputTransitionComponent = TransitionComponentUtility
.FindByGuid(data.TargetPassageGuid);

NextSpawnPosition = OutputTransitionComponent?
.GetSpawnPosition() ?? Vector3.zero;

SceneLoaded?.Invoke();
TransitionEnded?.Invoke();
}
}

Поскольку метод GoFromAsync не принимает ignoreShortcuts, при необходимости, можно воспользоваться ITransitionContext и передать параметр через него:

public class IgnoreShortcutsContext : ITransitionContext
{
public bool IgnoreShortcuts { get; }

private IgnoreShortcutsContext(bool ignoreShortcuts)
{
IgnoreShortcuts = ignoreShortcuts;
}

public static ITransitionContext Ignore => new IgnoreShortcutsContext(true);
public static ITransitionContext Respect => new IgnoreShortcutsContext(false);
}

Обработка в TransitionManagerService:

public async Task GoFromAsync(string currentPortGuid, ITransitionContext context = null)
{
var ignoreShortcuts = context is IgnoreShortcutsContext passContext && passContext.IgnoreShortcuts;

if (!Graph.CanPassTransition(currentPortGuid, ignoreShortcuts, out var status))
{
// ...
}

// ...
}

Вызов из ITransitionComponent:

public void Traverse()
{
// (true)
_manager.GoFromAsync(GetGuid(), IgnoreShortcutsContext.Ignore);

// (false)
_manager.GoFromAsync(GetGuid(), IgnoreShortcutsContext.Respect);

// (false)
_manager.GoFromAsync(GetGuid());
}

TransitionComponentUtility

Для поиска ITransitionComponent или его реализаций на сцене должен использоваться класс TransitionComponentUtility. Это необходимо, поскольку внутри себя методы FindByGuid(string) и FindByGuid<T>(string) заодно вызывают Refresh() на каждом переборном компоненте, чтобы их guid были актуальны на момент сравнения.

Методы:

МетодОписание
ITransitionComponent FindAny()Возвращает первый попавшийся ITransitionComponent на сцене.
T FindAny<T>()Возвращает первый попавшийся T, реализующий ITransitionComponent на сцене.
ITransitionComponent FindByGuid(string)Возвращает ITransitionComponent по переданному guid.
T FindByGuid<T>(string)Возвращает T, реализующий ITransitionComponent по переданному guid.

Ручной запуск встроенного TransitionManager

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

Отключение автозагрузки

  1. Установите AutoLoad в false
  2. Чтобы создать менеджер, вызовите TransitionManager.CreateInstance()

Пример

using UnityEngine;

namespace WorldGraphEditor.Examples
{
public class MyTransitionManagerLoader : MonoBehaviour
{
[SerializeField] private float _loadDelay = 2f;

private void Start()
{
Invoke(nameof(MyLoadMethod), _loadDelay);
}

private void MyLoadMethod()
{
// Создание менеджера
TransitionManager.CreateInstance();
}
}
}
примечание

TransitionManager так же содержит в себе метод LoadFromResources(), однако он лишь возвращает экземпляр класса из папки Resources и не создает объект в DontDestroyOnLoad. В первую очередь этот метод используется в режиме редактора для получения ссылки. Рекомендуется использовать именно CreateInstance(), поскольку в нем предусмотрена защита от создания нескольких экземпляров класса.


События и вызов асинхронного кода

Встроенный TransitionManager обладает событиями, которые оповещают о текущих фазах перехода:

  • Initialized: Вызывается после успешной инициализации TransitionManager;
  • Destroyed: Вызывается в OnDestroy() в TransitionManager;
  • PortEntered: Вызывается при вызове GoFromAsync() или GoToAsync();
  • TransitionStarted: Вызывается перед началом загрузки следующей сцены;
  • SceneLoaded: Вызывается после загрузки сцены и после того, как был найден "выходной порт" OutputTransitionComponent а так же, определена позиция появления игрока NextSpawnPosition;
  • TransitionEnded: Вызывается после создания префаба игрока. Если префаб не был указан, событие все равно будет вызвано;
  • PortLeaved: Вызывается после OnTransitionEnded.

Задержка между фазами перехода

Вы можете задать задержку между фазами перехода перед вызовом асинхронных методов с помощью EventCallConfig:

  1. Создание
  • ПКМ → Create → World Graph Editor → Event Call Config.
  1. Укажите один из доступных видов задержки:
  • This Frame — В текущем кадре;
  • Next Frame — В следующем кадре;
  • Physics Update — В FixedUpdate();
  • Custom Delay — Через заданное время.
  1. Перетащите EventCallConfig в соответствующее поле TransitionManager.

Ожидание завершения асинхронных методов

Если нужно дождаться выполнения операций, таких, как генерация уровня, вы можете зарегистрировать асинхронные методы с учётом их приоритета с помощью TransitionManager.RegisterAsyncHandler(). Чем выше значение приоритета, тем раньше метод будет вызван.

подсказка

Таким образом, порядок вызова при каждой фазе перехода будет таким:

  1. Вызов события перехода (OnPortEntered / OnTransitionStarted / OnSceneLoaded / OnTransitionEnded);
  2. Ожидание задержки EventCallConfig;
  3. Ожидание выполнения асинхронных методов.

Тип события, после которого начинается выполнение зарегистрированных асинхронных методов, указывается с помощью перечисления EventType.

События, для которых можно зарегистрировать асинхронные методы:

public enum EventType
{
OnPortEntered,
OnTransitionStarted,
OnSceneLoaded,
OnTransitionEnded,
}

Работа с асинхронными методами

static void RegisterAsyncHandler(EventType eventType, Func<CancellationToken, Task> func, int priority)

Параметры:

ИмяТипОписание
eventTypeEventTypeТип события, после которого должен начаться вызов асинхронных методов.
funcFunc<CancellationToken, Task>Асинхронный метод, который принимает CancellationToken и возвращает Task.
priorityintПриоритет вызова метода.

static void UnregisterAsyncHandler(EventType eventType, Func<CancellationToken, Task> func)

Параметры:

ИмяТипОписание
eventTypeEventTypeТип события, для которого нужно удалить метод
funcFunc<CancellationToken, Task>Асинхронный метод, который принимает CancellationToken и возвращает Task

примечание

Встроенный TransitionManager в методе OnDestroy автоматически вызывает CancellationTokenSource.Cancel(), а так же удаляет все зарегистрированные в нем методы.

Пример

using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;

namespace WorldGraphEditor.Examples
{
public class AsyncAfterSceneLoadedExample : MonoBehaviour
{
private readonly EventType _event = EventType.OnSceneLoaded;

private void Awake()
{
TransitionManager.RegisterAsyncHandler(Event, RunAfterSceneLoaded, 0);
}

private async Task RunAfterSceneLoaded(CancellationToken token)
{
await Awaitable.WaitForSecondsAsync(0.25f, token);
}

private void OnDisable()
{
TransitionManager.UnregisterAsyncHandler(Event, RunAfterSceneLoaded);
}
}
}