Quando usar Function, Macro e Custom Event
Em Blueprints, existem três formas comuns de encapsular e reutilizar lógica: Functions, Macros e Custom Events. Elas parecem similares no dia a dia, mas têm diferenças importantes em entradas/saídas, fluxo de execução e boas práticas de manutenção.
| Recurso | Tem pinos de Exec? | Entradas/Saídas | Latente (Delay, Timeline)? | Reutilização | Uso típico |
|---|---|---|---|---|---|
| Function | Depende: impure tem Exec; pure não | Sim (inputs e outputs) | Não (em geral) | Alta (inclusive em bibliotecas) | Cálculos, validações, getters, pequenas rotinas determinísticas |
| Macro | Sim (sempre, como um “bloco” de grafo) | Sim (inputs e outputs) | Sim (pode conter nós latentes) | Média (dentro do Blueprint ou Macro Library) | Padronizar padrões de fluxo, “atalhos” de grafo, sequências repetidas |
| Custom Event | Sim | Inputs sim; outputs não (não retorna valor) | Sim | Boa para disparo/assinatura | Entradas de fluxo, chamadas assíncronas, eventos de gameplay, replicação |
Regra prática rápida
- Se você precisa retornar um valor (ex.: pontuação calculada), use Function (preferencialmente Pure se não houver efeitos colaterais).
- Se você precisa de Delay/Timeline ou quer um “bloco” com Exec que será colado em vários lugares, use Macro.
- Se você quer disparar algo (sem retorno) e possivelmente lidar com replicação ou encadear lógica assíncrona, use Custom Event.
Functions: Pure vs Impure (e por que isso importa)
Pure Function
Uma Pure Function não tem pinos de execução (Exec) e deve ser determinística: dado o mesmo input, retorna o mesmo output, sem alterar estado do jogo. Ela pode ser chamada “a qualquer momento” pelo Blueprint, inclusive várias vezes por frame, porque o grafo pode reavaliá-la conforme necessário.
- Ideal para: cálculos, conversões, leitura de variáveis, validações simples.
- Evite: tocar som, spawnar efeitos, mudar variáveis, destruir/desativar atores.
Impure Function
Uma Impure Function tem Exec (entrada e saída) e pode causar efeitos colaterais: alterar variáveis, chamar funções que mudam estado, interagir com componentes, etc.
- Ideal para: rotinas de gameplay que mudam estado (ex.: adicionar pontuação, desativar item).
- Boa prática: mantenha funções impuras pequenas e com nome que indique ação (verbo), por exemplo:
AdicionarPontuacao,DesativarItem.
Boas práticas de assinatura (inputs/outputs)
- Inputs claros: nomeie inputs com intenção, ex.:
PontosParaAdicionarem vez deValue. - Outputs mínimos: retorne apenas o necessário. Se você precisa de muitos outputs, considere retornar uma struct (se fizer sentido) ou dividir a função.
- Evite dependências ocultas: se a função depende de algo externo (ex.: referência do Player), prefira receber como input ou documentar claramente.
Macros: reutilização de padrões de fluxo
Macros são como “trechos de grafo” reutilizáveis. Elas são úteis para reduzir repetição visual, principalmente quando você repete o mesmo padrão de Exec com validações e ramificações.
Quando uma Macro é melhor que Function
- Quando você precisa de nós latentes (por exemplo,
Delay), e a lógica precisa ficar encapsulada. - Quando você quer um padrão de fluxo com múltiplas saídas de Exec (ex.:
Sucesso/Falha), deixando o grafo mais legível.
Cuidados com Macros
- Debug: macros podem dificultar um pouco o rastreio, porque “expandem” lógica no local de uso.
- Excesso: não transforme tudo em macro. Para lógica de negócio (regras), functions tendem a ser mais fáceis de manter e testar.
Custom Events: disparo de lógica e organização do fluxo
Custom Events são pontos nomeados de entrada no grafo de execução. Eles não retornam valores, mas aceitam parâmetros. São ótimos para organizar o Event Graph, separar responsabilidades e criar “gatilhos” claros.
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
Quando preferir Custom Event
- Quando você quer iniciar uma sequência de ações (ex.: “OnColetado”).
- Quando a lógica pode envolver Delay e você quer manter isso fora de uma function.
- Quando você precisa de um ponto claro para replicação (em projetos multiplayer), já que eventos podem ser configurados para rodar no servidor/cliente (dependendo do caso).
Passo a passo: criando Functions reutilizáveis no Blueprint do ItemColetável
O objetivo é pegar uma lógica típica de coleta (tocar efeito, adicionar pontuação, desativar item) e refatorar em funções pequenas e reutilizáveis. Isso melhora legibilidade, facilita manutenção e permite reaproveitar em outros itens.
1) Identificar a lógica atual
No Blueprint BP_ItemColetavel, normalmente existe um fluxo no Event Graph parecido com:
- Evento de overlap/uso
- Tocar som/efeito
- Adicionar pontos ao jogador/sistema
- Desativar o item (ocultar, desabilitar colisão, destruir)
Mesmo que sua implementação exata seja diferente, a refatoração segue a mesma ideia: separar cada responsabilidade em uma função.
2) Criar a Function TocarEfeito
Tipo: Impure Function (vai causar efeito no mundo).
Passos:
- No
BP_ItemColetavel, crie uma nova Function chamadaTocarEfeito. - Defina inputs opcionais (se fizer sentido):
Som(SoundBase),Particula(NiagaraSystem/ParticleSystem),Local(Vector) ou use a localização do próprio ator. - Dentro da função, chame os nós de spawn/tocar (por exemplo, tocar som no local e spawnar efeito).
Boa prática: se o item pode não ter som/efeito configurado, faça validação com IsValid antes de spawnar.
// Pseudofluxo (Blueprint mental model):
TocarEfeito():
if Som é válido: PlaySoundAtLocation(Som, GetActorLocation)
if Particula é válida: SpawnSystemAtLocation(Particula, GetActorTransform)3) Criar a Function AdicionarPontuacao
Tipo: Impure Function (vai alterar estado de pontuação em algum lugar).
Decisão importante: onde a pontuação vive? Em muitos projetos, fica no Player, PlayerState, GameState ou um componente de pontuação. A função deve ser escrita para minimizar acoplamento.
Passos (genérico e reutilizável):
- Crie uma Function chamada
AdicionarPontuacao. - Inputs sugeridos:
QuemColetou(Actor ou seu tipo de personagem),Pontos(Integer/Float). - Dentro, obtenha a referência do sistema de pontuação (por exemplo, via cast para o personagem, ou buscando um componente específico no
QuemColetou). - Aplique o incremento.
Boa prática: se precisar de cast, trate falha de cast com um ramo claro e comentário; não deixe o grafo “mudo” quando falhar.
// Pseudofluxo:
AdicionarPontuacao(QuemColetou, Pontos):
if QuemColetou tem componente Score:
Score.Add(Pontos)
else:
(opcional) Print/Log em desenvolvimento4) Criar a Function DesativarItem
Tipo: Impure Function.
Objetivo: encapsular o que significa “sumir” para o seu item. Você pode destruir o ator ou apenas desativá-lo para reuso/pooling.
Passos:
- Crie a Function
DesativarItem. - Dentro, aplique um conjunto consistente de ações, por exemplo:
- Desabilitar colisão do componente principal (ou do ator).
- Ocultar no jogo (
SetActorHiddenInGame). - Desabilitar tick (se aplicável).
- Opcional:
DestroyActor(se você não pretende reutilizar).
Boa prática: escolha um padrão e use sempre. Se alguns itens destroem e outros escondem, documente isso no Blueprint com comentários.
5) Reorganizar o Event Graph para usar as funções
Agora o evento de coleta fica curto e legível, chamando as funções em sequência.
// Pseudofluxo do evento de coleta:
OnColetado(QuemColetou):
TocarEfeito()
AdicionarPontuacao(QuemColetou, PontosDoItem)
DesativarItem()Resultado esperado: o Event Graph vira um “roteiro” de alto nível, e os detalhes ficam dentro das funções.
Quando transformar parte disso em Macro
Se você perceber que vários Blueprints repetem o mesmo padrão de validação e execução, por exemplo:
- Validar
QuemColetounão nulo - Checar se já foi coletado
- Executar sequência
Você pode criar uma Macro como ExecutarSeNaoColetado com duas saídas de Exec: Executar e Ignorar. Isso reduz “nós de branch” repetidos em vários lugares.
// Ideia de Macro:
ExecutarSeNaoColetado(bJaColetado):
Branch(!bJaColetado)
True -> Exec: Executar
False -> Exec: IgnorarBoa prática: use macro para padronizar fluxo; use function para regras e ações.
Bibliotecas simples de funções (Blueprint Function Library)
Quando uma função não depende do estado de um ator específico e pode ser útil em vários Blueprints, faz sentido colocá-la em uma Blueprint Function Library. Ela é um conjunto de funções estáticas acessíveis de qualquer Blueprint.
O que é um bom candidato para Function Library
- Conversões e formatações (ex.: converter enum para texto).
- Cálculos genéricos (ex.: calcular pontuação bônus com base em multiplicador).
- Funções utilitárias que recebem tudo por parâmetro e não dependem de variáveis internas do ator.
Passo a passo: criar uma biblioteca de funções
- No Content Browser: Add > Blueprints > Blueprint Function Library.
- Nomeie, por exemplo:
BFL_GameplayUtils. - Crie uma função, por exemplo:
CalcularPontuacaoFinal. - Marque como Pure se for apenas cálculo.
// Exemplo de assinatura:
CalcularPontuacaoFinal(PontosBase:int, Multiplicador:float) -> PontosFinais:intComo usar: em qualquer Blueprint, procure pelo nome da função da biblioteca e conecte como um nó comum.
Observação importante: ações que dependem de mundo (spawn de efeito, tocar som) geralmente não são bons candidatos para Function Library, a menos que você passe explicitamente contexto suficiente (World Context) e mantenha a função bem genérica. Para iniciantes, prefira manter TocarEfeito dentro do próprio ator do item.
Legibilidade: comentários, organização e padrões de nome
Organizando grafos com comentários
- Use Comment Boxes para agrupar blocos: “Validação”, “Efeitos”, “Pontuação”, “Desativação”.
- Escreva comentários que expliquem por que algo existe, não apenas o que o nó faz.
- Mantenha o fluxo principal na horizontal (esquerda para direita) e evite cruzar fios.
Reroute nodes e alinhamento
- Use Reroute Nodes para reduzir fios longos e cruzamentos.
- Alinhe nós e mantenha espaçamento consistente; isso reduz erros ao editar depois.
Padrões de nome
- Functions impuras: verbo no infinitivo, ex.:
DesativarItem,AplicarDano. - Functions puras: nome descritivo de retorno, ex.:
ObterValorDeVenda,EstaColetado. - Booleans: prefixo
b(ex.:bJaColetado) e nomes afirmativos.
Atividade prática: refatorar o ItemColetável
Objetivo
Transformar um Event Graph “grande” em um fluxo curto chamando três funções reutilizáveis: TocarEfeito, AdicionarPontuacao, DesativarItem.
Checklist de execução
- Crie as 3 functions no
BP_ItemColetavel. - Garanta que
TocarEfeitovalide assets opcionais (som/efeito) antes de usar. - Faça
AdicionarPontuacaoreceberQuemColetouePontospor input. - Padronize
DesativarItem(ocultar + desabilitar colisão, ou destruir). - No evento de coleta, substitua nós diretos por chamadas às funções.
- Adicione Comment Boxes no Event Graph e dentro das funções quando houver decisões (ex.: por que destruir vs ocultar).
Desafio extra (opcional)
- Crie uma Pure Function no item chamada
ObterPontosDoItemque retorna o valor final (base + bônus). Use-a antes de chamarAdicionarPontuacao. - Crie uma Macro local
ExecutarSeValidopara validarQuemColetoue evitar repetição de branches se você tiver mais de um ponto de coleta.