Voltar para o Blog
Quest Log

Cutscene na Unity com Timeline e Cinemachine

Linha do tempo com faixas coloridas de animação, áudio e câmera sobre uma cena de personagem diante de um portão

Unity Timeline na prática: cutscene de 20 segundos com animação, áudio, cortes de câmera no Cinemachine Track e Signals para devolver o controle ao jogador.

Ferramenta:Unity

Cutscene na Unity com Timeline e Cinemachine

A Unity Timeline é o editor de sequências da Unity: uma linha do tempo onde você coloca animações, ativação de objetos, áudio e cortes de câmera em faixas paralelas, e um componente Playable Director toca tudo sincronizado. Para uma cutscene, você cria um Timeline asset, liga o personagem a uma faixa de animação, a Main Camera a uma faixa do Cinemachine e usa Signals para avisar o gameplay quando a cena termina.

Aqui você monta uma cutscene curta, de uns 20 segundos: o portão se abre, a câmera corta para o rosto do personagem, toca um som, a câmera volta e o controle retorna ao jogador. Inclui o script para iniciar e pular a cutscene e a correção dos dois bugs que todo mundo encontra na primeira vez. Tudo no Unity 6.3 LTS com Cinemachine 3.

O que é a Timeline da Unity e quando usar

A Timeline resolve um problema específico: coisas que acontecem em momentos exatos, coordenadas entre vários objetos. Exemplos:

  • Cutscene de abertura, de chefe, de fim de fase.
  • Porta que abre com câmera mostrando a sala do outro lado.
  • Sequência de tutorial com câmera guiando o olhar.
  • Trailer gravado dentro do jogo.

Ela não serve para lógica que depende do jogador (inimigo que reage, combate). Para isso existe o Animator e o seu código. Uma boa regra: se a sequência é igual toda vez que roda, é Timeline; se ela depende de decisões em tempo de jogo, é código.

O pacote com.unity.timeline vem instalado com o Editor, então não precisa de Package Manager. A documentação atual é a da linha 1.8. Para os cortes de câmera, instale o Cinemachine pelo Package Manager.

Antes de abrir a ferramenta, vale ter a cena escrita: quem aparece, o que acontece, quanto tempo dura cada plano. O post sobre narrativa em jogos ajuda a decidir o que merece virar cutscene e o que deve ficar na jogabilidade.

Criando o Playable Director e o primeiro Timeline asset

  1. Na cena, crie um GameObject vazio chamado Cutscene_Portao.
  2. Abra Window > Sequencing > Timeline.
  3. Com o Cutscene_Portao selecionado, a janela mostra o botão Create. Clique, salve como Portao.playable numa pasta Assets/Timelines.

A Unity adiciona ao objeto um Playable Director, que é o "tocador", e cria o asset .playable, que é a "partitura". O mesmo asset pode ser tocado por directors diferentes, cada um ligando as faixas a objetos da sua cena.

No Inspector do Playable Director, os campos que importam agora:

  • Playable: o Timeline asset.
  • Update Method: Game Time (padrão, respeita Time.timeScale), Unscaled Game Time (ignora pausa e câmera lenta), DSP Clock (sincronizado com o áudio) ou Manual.
  • Play On Awake: desmarque. A cutscene vai começar por script, quando o jogador entrar na área.
  • Wrap Mode: Hold (segura o último frame), Loop (repete) ou None (toca uma vez e para). Vamos voltar a ele nos erros comuns.
  • Bindings: a lista de quem cada faixa controla.

Trilhas de animação, ativação e áudio

No canto da janela Timeline, o botão + (Add) mostra os tipos de faixa. Para a cutscene:

Activation Track: liga e desliga um objeto. Arraste o objeto FX_PoeiraPortao para a faixa. O bloco "Active" define o intervalo em que ele existe. Use para partículas, luzes, objetos de cenário que aparecem. Na faixa, Post-playback State decide como o objeto fica quando a Timeline termina: Active, Inactive, Revert ou Leave As Is.

Animation Track: anima um objeto com Animator. Arraste o portão para a faixa (a Unity pergunta se pode adicionar um Animator, aceite). Você tem dois jeitos de criar o movimento:

  • Arrastar um Animation Clip pronto para a faixa.
  • Clicar no botão de gravação vermelho da faixa, mover o tempo, mexer no objeto na cena e deixar a Unity gravar keyframes. Ao sair da gravação, o resultado vira um Infinite Clip na faixa, que você pode converter em clip normal pelo menu da faixa (Convert To Clip Track).

Para o personagem, arraste o objeto com o Animator dele e coloque um clip de "olhar para o portão" no momento certo. Sobrepor dois clips na mesma faixa cria um blend entre eles.

Um ajuste que evita metade das dores de cabeça: no Inspector da Animation Track, Track Offsets. Apply Scene Offsets faz o clip partir da posição atual do personagem na cena; sem isso, um clip com movimento de raiz pode teletransportar o personagem para a origem do mundo.

Audio Track: arraste um AudioClip (o rangido do portão). Ligue a faixa a um AudioSource da cena nos Bindings para controlar volume e espacialização. Ajuste o início do som arrastando o bloco até casar com o movimento do portão.

Se você trabalha com animadores, a Timeline é a ponte entre o clip deles e o momento certo no jogo. O post sobre o que faz um animador de jogos mostra esse lado do pipeline.

Cortes de câmera com Cinemachine Track

Crie duas CinemachineCameras na cena:

  • CM_Portao: enquadra o portão abrindo.
  • CM_Rosto: close no personagem.

Deixe as duas com prioridade baixa, para não roubar a câmera do jogo fora da cutscene.

Na Timeline, + > Cinemachine Track. Arraste a Main Camera (a que tem o Cinemachine Brain) para o binding da faixa. Agora clique com o botão direito na faixa e adicione Cinemachine Shot clips. Cada clip aponta para uma CinemachineCamera, no campo da câmera no Inspector do clip.

A estrutura da cutscene de 20 segundos:

TempoCâmeraO que acontece
0 a 6 sCM_Portaoportão abre, poeira, rangido
6 a 12 sCM_Rostopersonagem reage
12 a 18 sCM_Portaorevela o caminho
18 a 20 scâmera do jogovolta ao gameplay

Clips encostados fazem corte seco. Clips sobrepostos fazem blend pelo tempo da sobreposição. Para voltar suave para a câmera de gameplay no fim, use Ease Out Duration no último clip: enquanto a Timeline comanda o Cinemachine, ela passa por cima da escolha por prioridade do Brain, e quando a faixa termina, o Brain volta a mandar.

Até aqui, você tem uma cena bonita que toca sozinha. O problema real começa quando ela precisa conversar com o resto do jogo: travar o jogador, salvar que a cena já foi vista, não tocar de novo, deixar pular. É esse encaixe entre sistemas que separa uma demonstração de um jogo, e é o tipo de coisa que um curso de Unity com projeto completo trabalha do começo ao fim.

Curso de Unity
Quer fazer seu primeiro jogo na Unity?

No curso de Unity 6 da CursoGame.Dev você vai do zero ao primeiro jogo, com um desafio prático em cada level e suporte individual no WhatsApp quando travar.

Conhecer o curso de Unity
Suporte no WhatsAppAcesso vitalícioGarantia de 7 dias

Signals: chamar código no momento certo da cutscene

Signals são marcadores na Timeline que disparam funções de script. Eles têm três peças:

  • Signal asset: um "nome de evento" salvo no projeto, por exemplo FimDaCutscene. Crie por Assets > Create > Timeline > Signal, ou direto pelo Inspector do marcador.
  • Signal Emitter: o marcador na linha do tempo. Adicione uma Signal Track (+ > Signal Track) ligada ao objeto que vai reagir, posicione o tempo em 20 s, clique com o botão direito na faixa e escolha Add Signal Emitter. No Inspector do marcador, escolha o Signal asset.
  • Signal Receiver: componente no objeto ligado à faixa. Com o marcador selecionado, clique em Add Signal Receiver. Na lista de reações, escolha o Signal e a função, como num botão de UI.

Para o nosso caso, ligue a Signal Track ao objeto Cutscene_Portao e faça o FimDaCutscene chamar CutsceneController.EndCutscene(), do script abaixo. No marcador há duas opções: Retroactive (dispara mesmo se a Timeline começar depois do tempo do marcador) e Emit Once (dispara só na primeira volta, útil com Loop).

Iniciar e pular a cutscene por script com PlayableDirector

Arquivo CutsceneController.cs, no Cutscene_Portao, junto com um BoxCollider2D ou BoxCollider marcado como trigger (aqui, versão 3D):

using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Playables;

[RequireComponent(typeof(PlayableDirector))]
public class CutsceneController : MonoBehaviour
{
    [SerializeField] private PlayableDirector director;
    [SerializeField] private MonoBehaviour playerController;
    [SerializeField] private InputAction skipAction = new InputAction("Skip", InputActionType.Button, "<Keyboard>/escape");
    [SerializeField] private string playerTag = "Player";

    private bool hasPlayed = false;
    private bool isPlaying = false;

    private void Reset()
    {
        director = GetComponent<PlayableDirector>();
    }

    private void OnEnable()
    {
        skipAction.Enable();
        skipAction.performed += OnSkip;
    }

    private void OnDisable()
    {
        skipAction.performed -= OnSkip;
        skipAction.Disable();
    }

    private void OnTriggerEnter(Collider other)
    {
        if (hasPlayed || !other.CompareTag(playerTag))
        {
            return;
        }

        StartCutscene();
    }

    public void StartCutscene()
    {
        hasPlayed = true;
        isPlaying = true;
        playerController.enabled = false;
        director.Play();
    }

    private void OnSkip(InputAction.CallbackContext context)
    {
        if (!isPlaying)
        {
            return;
        }

        director.time = director.duration;
        director.Evaluate();
        director.Stop();
        EndCutscene();
    }

    public void EndCutscene()
    {
        if (!isPlaying)
        {
            return;
        }

        isPlaying = false;
        playerController.enabled = true;
    }
}

Como funciona:

  • playerController é o script de movimento do jogador. Desligá-lo trava o controle durante a cena.
  • A InputAction declarada no próprio script já vem ligada ao Esc; no Inspector você pode adicionar o botão Start do gamepad.
  • Para pular, o código leva o tempo ao fim, chama Evaluate() para aplicar o estado final e para o director. O Stop() encerra a Timeline do mesmo jeito que o fim normal, então vale a regra do Wrap Mode explicada nos erros comuns: o que precisa continuar como no último frame (portão aberto, personagem no lugar novo) fica garantido no EndCutscene(). Ele é chamado diretamente, porque o Signal no fim da Timeline não dispara quando você salta o tempo.
  • O isPlaying evita que EndCutscene rode duas vezes (uma pelo Signal, outra pelo pulo).

Se precisar saber quando a Timeline terminou sem Signal, o PlayableDirector tem o evento stopped, que recebe o próprio director como parâmetro.

Erros comuns: personagem voltando à pose inicial e cutscene que não toca

O personagem volta à pose inicial no fim. Com Wrap Mode None, a Timeline para e devolve as propriedades ao estado anterior. Com Hold, ela segura o último frame, mas o director continua mandando no Animator, e o gameplay não consegue animar o personagem. A solução prática: termine a cutscene com o personagem numa pose que o Animator de gameplay também tem (Idle), deixe em None e, se a posição mudou, mova o personagem por código no EndCutscene para onde ele terminou.

O personagem teletransporta para a origem do mundo. Track Offsets da Animation Track. Use Apply Scene Offsets ou Apply Transform Offsets.

A cutscene não toca. Confira: o Playable Director tem o asset no campo Playable; os Bindings não estão vazios (faixa sem binding fica sem efeito); o trigger está funcionando (o jogador precisa de Rigidbody ou CharacterController para disparar OnTriggerEnter); você não está chamando Play() antes de o objeto estar ativo.

A câmera não corta. A Cinemachine Track está sem a Main Camera no binding, ou os clips apontam para CinemachineCameras desativadas.

A cutscene roda durante o menu de pausa. Update Method em Unscaled Game Time. Se a pausa deve congelar a cutscene, use Game Time.

Próximo passo

Monte a cutscene do portão numa cena de teste com objetos simples (cubos e cápsulas servem) antes de usar a arte final. Quando funcionar, adicione um segundo Signal no meio da cena para tocar uma fala, e salve em PlayerPrefs que a cutscene já foi vista, para ela não repetir ao carregar a fase. O guia de Cinemachine na Unity aprofunda as câmeras que você usou nos cortes.

Perguntas frequentes

Preciso instalar a Timeline na Unity 6?

Não. O pacote Timeline (com.unity.timeline) vem instalado com o Editor. Para abrir a janela, use Window > Sequencing > Timeline. Para cortes de câmera com Cinemachine Track, aí sim você precisa instalar o pacote Cinemachine.

Por que meu personagem volta para a pose inicial quando a cutscene acaba?

Com Wrap Mode em None, o Playable Director para no fim e as propriedades animadas voltam ao que eram antes. Em Hold, ele segura o último frame, mas continua mandando no personagem e bloqueia o Animator. A saída é terminar a cutscene com o personagem numa pose que o gameplay consegue assumir e devolver o controle por Signal.

Como chamar uma função de script no meio da Timeline?

Use Signals. Crie um Signal asset, coloque um Signal Emitter na Timeline no momento desejado e adicione um Signal Receiver no objeto ligado à faixa. No Receiver, escolha a função que roda como reação, do mesmo jeito que um evento de botão de UI.

Como pular uma cutscene da Timeline por script?

Leve o tempo do PlayableDirector para o fim (director.time = director.duration), chame director.Evaluate() para aplicar o estado final e depois director.Stop(). O Stop encerra a Timeline como no fim normal, então o que precisa continuar como no último frame (porta aberta, personagem no lugar novo) deve ser garantido pelo seu código de fim de cutscene, que o mesmo método de pular chama, já que os Signals do fim não disparam quando você salta o tempo.