Por que “referências” importam em Blueprints
Em Blueprints, quase toda interação de gameplay depende de você ter uma referência para algum objeto no mundo (um Actor, um Component, o Player, um Widget, etc.). Uma referência é “um ponteiro” para uma instância específica em tempo de execução: com ela você consegue ler variáveis, chamar funções, disparar eventos e acessar componentes.
O desafio é obter e manter essas referências sem criar acoplamento excessivo (quando um Blueprint depende diretamente do tipo concreto do outro, dificultando reuso e manutenção). Este capítulo foca em: formas comuns de obter referências, o que é Cast To e quando evitar, e como usar Blueprint Interfaces e Event Dispatchers para comunicação desacoplada.
Formas comuns de obter referências (com exemplos)
1) Get Player Character / Get Player Controller
Use quando você precisa acessar o personagem/controlador do jogador local (single player ou player index específico). É direto e barato, mas ainda cria dependência se você fizer cast para uma classe específica.
- Quando usar: interações que sempre envolvem o jogador local (ex.: abrir inventário, atualizar HUD, checar posição do player).
- Cuidado: em projetos com múltiplos personagens jogáveis, evite assumir uma classe concreta sem necessidade.
Exemplo prático: em um Actor do cenário, obter o player e ler a localização.
Get Player Character (Player Index 0) -> Get Actor Location2) Get Actor of Class / Get All Actors of Class
Esses nós procuram Actors no mundo por classe.
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
- Get Actor of Class: retorna o primeiro encontrado. Útil quando você tem certeza que existe apenas um (ex.: um “GameManager” único).
- Get All Actors of Class: retorna uma lista. Útil para iterar, mas pode ser custoso se usado com frequência.
Boas práticas:
- Evite chamar a cada Tick. Prefira chamar uma vez (ex.: no BeginPlay) e guardar em variável.
- Para “singletons” de gameplay, considere guardar referência em um lugar central (GameMode/GameState/Subsystem) e injetar por variável exposta (ver abaixo).
3) Overlap: Other Actor (eventos de colisão)
Em eventos como OnComponentBeginOverlap ou ActorBeginOverlap, o parâmetro Other Actor já é uma referência para quem entrou na área de colisão.
- Quando usar: interações por proximidade (gatilhos, pickups, áreas de dano, portas com trigger).
- Cuidado:
Other Actoré do tipo Actor genérico; você pode filtrar por tags, interfaces, componentes ou (se necessário) cast.
Exemplo de filtragem sem cast: checar se o outro actor implementa uma interface (ver seção de Interfaces).
4) Variável exposta (Instance Editable / Expose on Spawn)
Uma forma muito limpa de obter referência é recebê-la em vez de procurar. Você cria uma variável do tipo referência (ex.: BP_Porta, Actor, ou melhor: uma Interface) e marca como:
- Instance Editable: para setar no Details Panel ao colocar o Actor no nível.
- Expose on Spawn: para passar a referência no momento do
SpawnActor.
Vantagem: reduz buscas no mundo e diminui acoplamento quando você usa tipos mais genéricos (Actor/Interface) em vez de classes concretas.
| Abordagem | Prós | Contras |
|---|---|---|
| Procurar (Get Actor of Class) | Rápido de prototipar | Pode ser custoso e frágil (depende do mundo) |
| Receber por variável exposta | Explícito, performático, fácil de manter | Requer configurar no editor/spawn |
O que é Cast To (e por que ele acopla)
Cast To tenta tratar uma referência genérica (ex.: Actor) como uma classe específica (ex.: BP_PlayerCharacter). Se o objeto em runtime for daquela classe (ou derivada), o cast “passa” e você ganha acesso às variáveis/funções específicas.
Quando faz sentido usar Cast To
- Quando você realmente precisa de algo específico daquela classe (uma função/variável que não existe em um tipo mais genérico).
- Quando a relação é naturalmente “forte” e estável (ex.: seu HUD sabe que o PlayerController é de uma classe específica do seu jogo).
- Quando você controla o fluxo e tem certeza do tipo (ex.: acabou de dar Spawn em uma classe específica e guardou como Actor genérico por algum motivo).
Quando evitar Cast To
- Quando você está fazendo cast em muitos lugares só para chamar uma ação simples (ex.: “Interagir”, “Receber Dano”, “Abrir”).
- Quando vários objetos diferentes deveriam responder à mesma ação (porta, alavanca, NPC, item) e você acabaria criando uma cadeia de casts.
- Quando o cast vira dependência circular: A conhece B e B conhece A por classes concretas.
Alternativas comuns ao cast: Blueprint Interfaces (para chamar ações comuns) e Event Dispatchers (para notificar eventos sem conhecer o ouvinte).
Blueprint Interfaces: comunicação por contrato (desacoplada)
Uma Blueprint Interface (BPI) define um conjunto de funções (assinaturas) que qualquer Blueprint pode implementar. Quem chama não precisa saber a classe concreta; só precisa de uma referência para um objeto que implemente a interface.
Vantagens
- Evita cadeias de
Cast To. - Permite múltiplos tipos de objetos responderem à mesma ação.
- Facilita reuso e testes (você troca implementações sem mudar quem chama).
Como chamar uma Interface
Em geral você usa:
Does Implement Interfacepara checar.- Chamada da função da interface (mensagem) no alvo (Target).
Se o alvo não implementar, a chamada não executa (ou você pode proteger com a checagem).
Event Dispatchers: “broadcast” de eventos para ouvintes
Um Event Dispatcher é um mecanismo de evento: um Blueprint “emite” (Broadcast/Call) e outros Blueprints “assinam” (Bind) para reagir. O emissor não precisa conhecer quem está ouvindo.
Quando usar Dispatchers
- Quando um objeto precisa avisar “algo aconteceu” para vários interessados (ex.: botão pressionado, porta abriu, item coletado).
- Quando você quer que o Player (ou HUD) reaja a eventos de objetos do mundo sem cast direto.
Pontos de atenção
- Você precisa ter uma referência para fazer o Bind (normalmente no BeginPlay, ao entrar em overlap, ou ao registrar um sistema).
- Se o objeto emissor for destruído, bindings deixam de ser relevantes; ainda assim, evite manter referências inválidas e prefira checar validade quando necessário.
Exercício prático: Interface BPI_Interagivel + resposta no jogador sem cast direto
Objetivo: criar uma interface BPI_Interagivel com a ação Interagir. Um objeto do cenário (ex.: uma alavanca) implementa essa interface. Ao interagir, ele dispara uma resposta no jogador sem cast direto, usando um Event Dispatcher no próprio jogador (ou no Controller) para notificar “Interação ocorreu”.
Parte A — Criar a Interface BPI_Interagivel
- Content Browser > Add > Blueprints > Blueprint Interface.
- Nomeie como
BPI_Interagivel. - Abra a interface e crie uma função chamada
Interagir. - Adicione um parâmetro de entrada opcional para contexto, por exemplo:
Interagentedo tipoActor(Object Reference). Isso permite que o objeto saiba “quem interagiu”.
Assinatura sugerida:
Interagir(Interagente: Actor)Parte B — Criar um objeto interagível no cenário (ex.: BP_Alavanca)
- Crie um Blueprint Actor chamado
BP_Alavanca. - Adicione um Static Mesh (visual) e, se quiser interação por proximidade, um Box Collision.
- Em Class Settings > Interfaces > Add > selecione
BPI_Interagivel. - No Event Graph, implemente o evento/função da interface: procure por
Event Interagir(ou a entrada equivalente da interface).
Lógica sugerida dentro de BP_Alavanca (sem cast para o player):
- Ao receber
Interagir(Interagente), valide seInteragenteé válido. - Em vez de cast para
BP_Player, você vai chamar um dispatcher no interagente via uma referência já conhecida (ver Parte C) ou via uma interface adicional (opcional). Para manter o exercício alinhado, vamos usar um dispatcher no jogador e fazer o Bind no jogador quando ele detectar o interagível.
Como o dispatcher será do jogador, a alavanca precisa de um jeito de “avisar” o jogador. Uma abordagem simples e desacoplada é: a alavanca expõe um dispatcher próprio e o jogador se inscreve; ou o jogador expõe um dispatcher e a alavanca chama. A opção mais comum é o objeto do mundo emitir e o jogador ouvir. Vamos seguir essa (mais desacoplada).
Parte C — Adicionar um Event Dispatcher no BP_Alavanca (emissor)
- No
BP_Alavanca, crie um Event Dispatcher chamadoOnInteragido. - Adicione um parâmetro no dispatcher:
Interagente(Actor). - Na implementação de
Interagir, chameOnInteragido(Call/Broadcast) passando oInteragente.
Event Interagir(Interagente) -> Call OnInteragido(Interagente)Opcionalmente, você pode também tocar uma animação, mudar material, ou alternar um booleano interno (ex.: bLigada) antes de emitir o evento.
Parte D — No jogador: detectar interagíveis e chamar a Interface
Você precisa de um fluxo de interação. Um padrão simples:
- O jogador mantém uma variável
AlvoInteracao(tipoActor). - Quando entra em overlap com um interagível, define
AlvoInteracao. - Quando aperta a tecla de interação (ex.: E), chama a interface
Interagirno alvo.
Passo a passo (Player Character):
- No Blueprint do Player Character, adicione um Sphere/Box Collision (ex.:
InteractionSphere) para detectar objetos próximos. - No
InteractionSphere, useOnComponentBeginOverlapeOnComponentEndOverlap. - Crie a variável
AlvoInteracao(tipoActor). - No BeginOverlap: se
Other ActorDoes Implement Interface(BPI_Interagivel), então setAlvoInteracao = Other Actor. - No EndOverlap: se
Other Actor == AlvoInteracao, então limpeAlvoInteracao(set None). - Crie um Input Action (ex.:
Interact) e, ao pressionar, seAlvoInteracaofor válido e implementar a interface, chameInteragirpassandoSelfcomoInteragente.
Input Interact Pressed -> IsValid(AlvoInteracao) -> Does Implement Interface (BPI_Interagivel) -> Interagir (Message) Target=AlvoInteracao Interagente=SelfNote que aqui não existe cast para BP_Alavanca, BP_Porta, etc. O jogador só exige que o alvo seja “interagível”.
Parte E — Resposta no jogador sem cast direto: Bind no dispatcher do interagível
Agora vamos fazer o jogador reagir ao evento emitido pelo objeto (alavanca) sem cast para uma classe específica do objeto.
Como o dispatcher OnInteragido está no BP_Alavanca, para fazer Bind você precisaria de uma referência tipada (ou cast). Para manter zero cast, a solução é mover o dispatcher para uma interface também (não dá: interfaces não carregam dispatchers), ou criar um componente comum, ou usar uma segunda interface para “registrar” callbacks. Para este exercício, vamos usar uma abordagem prática e comum: criar um Blueprint Actor Component chamado BPAC_Interagivel que contém o dispatcher, e anexar esse componente a qualquer objeto interagível. Assim, o jogador encontra o componente por tipo (sem cast para a classe do Actor).
Parte F — Criar um Actor Component para padronizar o dispatcher (BPAC_Interagivel)
- Crie um Blueprint Actor Component chamado
BPAC_Interagivel. - Dentro dele, crie um Event Dispatcher
OnInteragidocom parâmetroInteragente(Actor). - Adicione uma função pública no componente, por exemplo
EmitirInteragido, que chama o dispatcher.
EmitirInteragido(Interagente) -> Call OnInteragido(Interagente)Parte G — Usar o componente no BP_Alavanca e emitir o evento
- No
BP_Alavanca, adicione o componenteBPAC_Interagivel. - Na implementação de
Interagir(da interface), em vez de chamar um dispatcher do próprio actor, chameEmitirInteragidono componente.
Event Interagir(Interagente) -> BPAC_Interagivel->EmitirInteragido(Interagente)Parte H — No jogador: fazer Bind no dispatcher via componente (sem cast)
Quando o jogador detectar um interagível no overlap, além de setar AlvoInteracao, ele tenta obter o componente BPAC_Interagivel do actor e faz Bind no dispatcher.
- No Player Character, crie uma variável
InteragivelCompAtualdo tipoBPAC_Interagivel(Object Reference). - No BeginOverlap, após confirmar que implementa
BPI_Interagivel, useGet Component By ClassnoOther ActorbuscandoBPAC_Interagivel. - Se válido, faça
Bind Event to OnInteragidoe aponte para um Custom Event no jogador (ex.:OnInteragido_Receber). - Guarde esse componente em
InteragivelCompAtual. - No EndOverlap, se estiver saindo do mesmo actor, faça
Unbind(ouUnbind Allcom cuidado) e limpe as variáveis.
Custom Event no jogador: OnInteragido_Receber(Interagente). Dentro dele, você pode disparar uma resposta no jogador (ex.: tocar som, mostrar mensagem, incrementar contador).
OnComponentBeginOverlap(OtherActor) -> Does Implement Interface (BPI_Interagivel) -> Set AlvoInteracao = OtherActor -> GetComponentByClass(BPAC_Interagivel) -> Bind Event to OnInteragidoCustom Event OnInteragido_Receber(Interagente) -> (ex.) Print String "Interação recebida no jogador"Checklist de validação do exercício
- O jogador chama
Interagirvia Interface (Message), sem cast para o tipo do objeto. - O objeto do cenário implementa
BPI_Interagivele, ao interagir, emite um evento. - O jogador reage ao evento via Bind em um dispatcher obtido por componente, sem cast para a classe do objeto.
Padrões úteis para reduzir acoplamento
Prefira “programar para a interface”
- Variáveis do tipo Interface (quando aplicável) ou
Actor+ checagemDoes Implement Interface. - Chamadas por Interface Message para ações genéricas (Interagir, ReceberDano, Ativar).
Use Cast To como ferramenta pontual, não como cola do projeto
- Se você está fazendo cast repetidamente em vários lugares para chamar a mesma ação, isso é um sinal forte de que uma Interface ou Dispatcher resolveria melhor.
- Se o cast é inevitável, faça uma vez, armazene a referência tipada e valide (IsValid) antes de usar.
Evite buscas frequentes no mundo
- Se precisar de um Actor específico, prefira injetar por variável exposta (Instance Editable/Expose on Spawn) ou cachear no BeginPlay.
- Use Overlap e referências diretas quando a interação for espacial/proximidade.