Pular para o conteúdo principal
Versão: 5.0.x

Scene Operation

Toda operação retorna um SceneOperationde forma síncrona, antes de o trabalho começar. Ele é um handle vivo sobre esse trabalho: em que fase está, quanto já avançou, o que produziu e como esperar por ele.

Por que um handle e não uma Task

Uma Task te dá uma coisa: o resultado final. Qualquer outra coisa que você queira saber sobre um carregamento de cena — quanto já avançou, em que fase está, se ainda dá para pará-lo — precisa ser decidida antes da chamada, como parâmetros extras.

Já um SceneOperation é algo que você segura, então tudo isso é conectado depois da chamada:

SceneOperation op = MySceneManager.TransitionAsync("target", "loading");

op.Progressed += progress => bar.value = progress;
op.StateChanged += o => { if (o.State == SceneOperationState.ScreenOut) BeginIntro(); };

SceneResult result = await op;

É por isso que nenhum dos quatro métodos recebe um parâmetro de progresso ou de cancelamento: há um lugar melhor para colocá-los.

Esperando por ele

Três formas, todas suportadas pelo mesmo handle:

SceneResult result = await op; // direto, sem alocar Task
yield return op.ToCoroutine(); // de uma coroutine; falhas relançam a exceção
Task<SceneResult> task = op.AsTask(); // ponte para interoperar com terceiros

await op é o caminho principal. GetAwaiter() retorna um SceneOperationAwaiter sobre a própria lista de continuações da operação — sem Task, sem Awaitable. Como o pump roda no player loop, as continuações retomam na thread principal por construção, sem ida e volta pelo SynchronizationContext.

Ele também é re-awaitable — dar await duas vezes retorna o mesmo resultado, e op.Result continua legível após a conclusão. É justamente por isso que Awaitable não é usado internamente: seus objetos voltam para um pool depois de um único await.

info

AsTask() é uma conveniência, não um pilar do design. Ele custa um TaskCompletionSource por chamada e await op não, então recorra a ele apenas quando uma API de terceiros exigir uma Task.

O que ele reporta

Membro
KindQual operação é esta — Load, Unload, Transition, Reload, Composite
StateA fase em que está
ProgressDe 0 a 1
ResultAs cenas produzidas, vazio até a conclusão
ExceptionPor que falhou, ou null
IsDoneSe terminou, com sucesso ou não

E os eventos:

Evento
ProgressedDispara quando Progress muda. Não é disparado para valores inalterados.
StateChangedDispara a cada mudança de State
SceneLoaded / SceneUnloadedUma vez por cena
CompletedUma vez, ao terminar — seja sucesso, cancelamento ou falha. Inscrever-se depois da conclusão o invoca imediatamente.
nota

Um inscrito que lança exceção é reportado através do SceneManagerLog e contido. Ele não vai fazer a operação falhar, nem vai impedir os outros inscritos ou os awaiters de rodar.

Estados

PendingResolvingScreenInUnloadingLoadingActivatingScreenOutCompleted, com Canceled e Faulted como alternativas terminais.

Quais deles você vê depende da operação — um carregamento simples nunca chega a ScreenIn. A ordem segue o fluxo da transição, e é por isso que Unloading vem antes de Loading: a cena de origem vai embora assim que a tela de carregamento estiver visível, antes de a cena de destino entrar.

Então "a tela de carregamento terminou o fade out, comece a cutscene" é um estado no qual você se inscreve:

op.StateChanged += o =>
{
if (o.State == SceneOperationState.ScreenOut)
BeginIntroCutscene();
};

Cancelando

op.Cancel();
op.CancelWith(destroyCancellationToken); // a ponte opcional
atenção

As operações subjacentes da Unity continuam rodando. Uma cena que a engine já começou a carregar não pode ser abortada, então ela vai terminar. O que para é o relato desta operação, as fases restantes e os awaiters dela.

Combinando

SceneOperation both = SceneOperation.WhenAll(first, second);
SceneOperation any = SceneOperation.WhenAny(first, second);

Prefira estes a um Task.WhenAll em cima de AsTask(): eles rodam sobre as listas de continuações das próprias operações, então não alocam uma Task por operação.

Progresso

Progress é a média entre todas as cenas da operação.

atenção

Um grupo que mistura backends avança de forma desigual. Os Addressables incluem o tempo de download no seu progresso e o caminho padrão não, então um grupo misto não é uma linha reta. Trate-o como uma barra de progresso, não como um relógio.

nota

SceneOperation deliberadamente não é pooled. Esta API incentiva você a manter o handle — op.Result após a conclusão e aguardar duas vezes são ambos suportados — então nada tem como saber quando ele está livre. É uma alocação pequena por operação, diante das dezenas de kilobytes que um carregamento de cena custa. Os buffers por operação são pooled.