Construct do Zero: Organização Profissional de Eventos (Legibilidade e Escalabilidade)

Capítulo 16

Tempo estimado de leitura: 11 minutos

+ Exercício

Por que organização de Event Sheets vira “sistema” em projetos grandes

Quando o projeto cresce, o problema deixa de ser “fazer funcionar” e passa a ser “manter funcionando” sem quebrar outras partes. Em Construct, isso significa: encontrar eventos rápido, entender intenções sem abrir dezenas de grupos, reaproveitar lógica sem duplicar, e conseguir adicionar features sem virar um emaranhado de condições e ações.

Organização profissional de eventos é um conjunto de práticas para deixar a lógica legível (qualquer pessoa entende) e escalável (você adiciona conteúdo sem multiplicar trabalho). O objetivo é transformar seus event sheets em módulos: cada sistema com sua responsabilidade, com padrões de nomes, comentários úteis e funções para ações repetidas.

Estrutura recomendada: separar por sistemas e por responsabilidade

Divisão por sistemas (macro)

Uma estrutura comum e fácil de manter é separar por sistemas principais. Exemplo de event sheets:

  • ES_Main (orquestra o fluxo geral e inclui outros sheets)
  • ES_Player (controle e regras do jogador)
  • ES_Enemies (IA, dano recebido, drops)
  • ES_Combat (regras de dano, invencibilidade, knockback, hitstop)
  • ES_UI (HUD, telas, botões)
  • ES_Audio (roteamento de SFX/música, volumes, chamadas centralizadas)
  • ES_Spawns (spawners, ondas, pontos de spawn)
  • ES_Data (variáveis globais, save/load, preferências)

Mesmo que você já tenha lógica espalhada, a refatoração consiste em mover eventos para o sheet “dono” do assunto e deixar o ES_Main apenas como ponto de entrada (include/organização).

Divisão por responsabilidade (micro)

Dentro de cada sheet, use grupos e subgrupos para separar responsabilidades. Exemplo no ES_Player:

Continue em nosso aplicativo e ...
  • Ouça o áudio com a tela desligada
  • Ganhe Certificado após a conclusão
  • + de 5000 cursos para você explorar!
ou continue lendo abaixo...
Download App

Baixar o aplicativo

  • [PLAYER] Init
  • [PLAYER] Input
  • [PLAYER] Movement
  • [PLAYER] Combat
  • [PLAYER] Damage & Invulnerability
  • [PLAYER] Animation
  • [PLAYER] Debug (desativado por padrão)

O padrão [SISTEMA] Assunto facilita a busca e mantém consistência visual. Em projetos com muitos sheets, isso reduz o tempo de “caça ao evento”.

Grupos e subgrupos: como usar sem virar labirinto

Regras práticas

  • Evite profundidade excessiva (muitos níveis de subgrupo). Prefira 1–2 níveis.
  • Um grupo deve ter um objetivo claro. Se ele mistura “input”, “animação” e “dano”, ele está grande demais.
  • Use grupos para ligar/desligar sistemas (ex.: [UI] Pause pode ser ativado/desativado).
  • Coloque eventos de “Setup/Init” no topo do sheet, e “Debug” no final.

Modelo de cabeçalho de grupo (comentário padrão)

Use um comentário no início de cada grupo para documentar intenção e dependências:

[PLAYER] Damage & Invulnerability
Responsabilidade: aplicar dano ao Player, invencibilidade temporária e feedback.
Depende de: ES_Combat (funções), ES_Audio (PlaySFX), variáveis globais de dificuldade.
Eventos-chave: OnPlayerHit, ApplyDamage_Player, StartIFrames.

Esse comentário reduz a necessidade de “ler tudo” para entender o que está acontecendo.

Nomenclatura consistente: variáveis, grupos, funções e tags

Padrões recomendados (simples e escaláveis)

  • Variáveis globais: g_* (ex.: g_gameState, g_difficulty, g_musicVolume)
  • Variáveis locais (do sheet/escopo): l_* (ex.: l_damage, l_sourceX)
  • Variáveis de instância: prefixo por objeto ou função (ex.: hp no Player; ou enemy_hp se você prefere explicitar)
  • Grupos: [SISTEMA] Assunto
  • Funções: verbo + objeto (ex.: ApplyDamage, PlaySFX, ChangeScreen)
  • Constantes (quando usar): CONST_* (ex.: CONST_MAX_HP)

O importante não é o “prefixo perfeito”, e sim escolher um padrão e aplicar em todo o projeto. Isso evita variáveis duplicadas com nomes parecidos e facilita buscas.

Tags e identificadores: padronize para evitar “strings mágicas”

Se você usa tags (por exemplo, em inimigos, pickups, UI), defina um padrão e centralize os valores. Exemplo:

  • tag = "enemy", tag = "player", tag = "ui"
  • Ou um campo type com valores controlados: "slime", "bat", "boss"

Boa prática: mantenha uma lista documentada (em comentário no ES_Main ou ES_Data) com os valores válidos para evitar inconsistência (ex.: "Enemy" vs "enemy").

Funções (Function): quando e por que usar

Funções são o principal mecanismo de reutilização e padronização de ações. Elas ajudam a:

  • Evitar duplicação (mesma lógica repetida em Player, Enemies, hazards, etc.).
  • Garantir consistência (mesmo cálculo de dano, mesmo SFX, mesmo efeito).
  • Facilitar manutenção (muda em um lugar e reflete no projeto todo).

Critérios para transformar eventos em função

  • Você copiou/colou a mesma sequência 2+ vezes.
  • Existe uma “regra” que deve ser igual em todo lugar (ex.: invencibilidade, clamp de HP, tocar SFX).
  • Você quer uma API interna do projeto (ex.: “para trocar de tela, sempre chame ChangeScreen”).

Onde colocar funções

Crie um sheet dedicado, por exemplo ES_Functions (ou por sistema: ES_Combat para funções de combate, ES_UI para funções de UI). O importante é que seja fácil de encontrar.

Boas práticas para evitar duplicação (sem perder clareza)

1) Centralize “efeitos colaterais” em funções

Exemplo: ao aplicar dano, normalmente você também quer: tocar SFX, spawnar partículas, piscar sprite, atualizar HUD. Se cada inimigo fizer isso de um jeito, vira inconsistência. Centralize em uma função que receba parâmetros.

2) Use eventos “gatilho” (broadcast) com cuidado

Se você usa variáveis globais como “sinais” (ex.: g_playerHit = 1), prefira funções ou eventos bem nomeados para evitar estados difíceis de rastrear. Quando precisar de sinalização, documente e resete no mesmo lugar.

3) Prefira dados a ramificações

Em vez de criar um bloco enorme “se inimigo A, faz X; se inimigo B, faz Y”, tente armazenar parâmetros no inimigo (ex.: damage, knockback, sfxHit) e usar a mesma função para todos.

4) Uma fonte de verdade para estados

Se existe g_gameState, evite criar isPaused, inMenu, isGameOver em paralelo sem necessidade. Se precisar de flags, defina regras claras: o que manda em quê.

Passo a passo: refatoração prática dos eventos dos capítulos anteriores

O exercício abaixo assume que você já tem: dano/vida, SFX, troca de telas (menu/pause/game over), UI e inimigos básicos. A tarefa é reorganizar e criar funções reutilizáveis para ações repetidas.

Passo 1: criar a “árvore” de event sheets e grupos

  1. Crie (ou renomeie) os event sheets para refletir sistemas: ES_Main, ES_Player, ES_Enemies, ES_UI, ES_Audio, ES_Combat, ES_Functions (se preferir centralizar).
  2. No ES_Main, organize os includes (ou referências) e deixe apenas eventos de alto nível (ex.: inicialização global, roteamento de estados).
  3. Dentro de cada sheet, crie grupos com o padrão [SISTEMA] Assunto e mova os eventos correspondentes.

Passo 2: padronizar variáveis e nomes de grupos

  1. Liste variáveis globais existentes e renomeie para g_* (ex.: GameStateg_gameState).
  2. Escolha um padrão para HP e dano: por exemplo, hp como variável de instância em Player e Enemies, e damage como variável de instância em hitboxes/projéteis.
  3. Padronize nomes de grupos e comentários de cabeçalho.

Passo 3: criar a função reutilizável “PlaySFX”

Objetivo: qualquer sistema toca SFX chamando um único ponto, que já respeita volume e evita spam.

Assinatura sugerida:

  • PlaySFX(name, volume, pitch)

Implementação (estrutura):

  1. No sheet ES_Audio (ou ES_Functions), crie o evento: On function PlaySFX.
  2. Dentro, aplique volume final com base em g_sfxVolume (global) e no parâmetro volume.
  3. Toque o som pelo nome/identificador recebido.
Function: PlaySFX(name, volume, pitch)
- Set local l_finalVol = volume * g_sfxVolume
- Audio: Play (tag: "sfx", name: name, volume: l_finalVol, pitch: pitch)

Refatoração: procure em todos os sheets ações “Audio: Play …” e substitua por chamadas PlaySFX.

Passo 4: criar a função “ChangeScreen” (troca de tela/estado)

Objetivo: padronizar transições (menu, jogo, pause, game over, vitória), evitando eventos duplicados e inconsistentes.

Assinatura sugerida:

  • ChangeScreen(targetState, optionalLayout)

Implementação (estrutura):

  1. Crie On function ChangeScreen no ES_UI ou ES_Main.
  2. Centralize: setar g_gameState, habilitar/desabilitar grupos relevantes, mostrar/esconder camadas de UI, e se necessário trocar de layout.
  3. Opcional: tocar SFX de navegação e aplicar fade.
Function: ChangeScreen(targetState, optionalLayout)
- Set g_gameState = targetState
- If optionalLayout != "": System: Go to layout optionalLayout
- Call PlaySFX("ui_confirm", 1, 0)
- (Opcional) UI: ativar grupo [UI] HUD quando targetState = "playing"

Refatoração: substitua eventos espalhados de “ir para layout X”, “mostrar menu”, “pausar” por chamadas a ChangeScreen.

Passo 5: criar a função “ApplyDamage” (aplicar dano padronizado)

Objetivo: uma regra única para reduzir HP, aplicar invencibilidade, feedback visual e disparar morte quando necessário. Isso reduz duplicação entre Player e Enemies.

Decisão importante: em Construct, funções não “tipam” objetos automaticamente. Você pode padronizar de duas formas:

  • Abordagem A (recomendada): criar duas funções: ApplyDamage_Player e ApplyDamage_Enemy (mais simples e explícito).
  • Abordagem B (genérica): uma função ApplyDamage que opera no objeto atualmente selecionado (exige disciplina de seleção/picking).

A seguir, um modelo simples e robusto usando a Abordagem A.

Passo 5A: ApplyDamage_Player

Assinatura sugerida:

  • ApplyDamage_Player(amount, sourceX, sourceY, sfxName)

Implementação (estrutura):

  1. Cheque invencibilidade (ex.: Player.iFrames > 0) e ignore dano se ativo.
  2. Subtraia HP e faça clamp (não deixar negativo).
  3. Inicie invencibilidade (set iFrames).
  4. Chame PlaySFX e dispare feedback (flash/partículas) de forma centralizada.
  5. Se HP <= 0, chame ChangeScreen("gameover", ...) ou dispare evento de morte.
Function: ApplyDamage_Player(amount, sourceX, sourceY, sfxName)
- If Player.iFrames > 0: return
- Player.hp = max(Player.hp - amount, 0)
- Player.iFrames = 0.6
- Call PlaySFX(sfxName, 1, 0)
- (Opcional) Spawn hit effect at Player
- If Player.hp = 0: Call ChangeScreen("gameover", "")

Passo 5B: ApplyDamage_Enemy

Assinatura sugerida:

  • ApplyDamage_Enemy(uid, amount, sourceX, sourceY, sfxName)

Por que passar UID: você garante que está aplicando dano no inimigo correto, mesmo se a seleção mudar.

Implementação (estrutura):

  1. Selecione o inimigo pelo UID.
  2. Subtraia HP, feedback, e se morrer: dropar item/pontos, tocar SFX, destruir.
Function: ApplyDamage_Enemy(uid, amount, sourceX, sourceY, sfxName)
- Pick Enemy by UID = uid
- Enemy.hp = max(Enemy.hp - amount, 0)
- Call PlaySFX(sfxName, 1, 0)
- (Opcional) Spawn hit effect at Enemy
- If Enemy.hp = 0:
  - Add score
  - (Opcional) Drop item
  - Destroy Enemy

Refatoração: onde quer que você tenha eventos “Enemy hp -= X” ou “Player hp -= X”, substitua por chamadas às funções.

Passo 6: transformar sequências repetidas em “eventos reutilizáveis” (padrões)

Além de funções, você pode criar padrões reutilizáveis com grupos “template” e subgrupos por tipo. Exemplos:

  • Template de morte: [ENEMY] Death com subeventos para pontuação, drop e efeitos.
  • Template de interação: [UI] Button com lógica padrão de hover/click e chamada ChangeScreen.
  • Template de hit: [COMBAT] HitResolution que chama ApplyDamage_* e feedback.

Regra: se o template precisar de parâmetros, prefira função. Se for uma sequência fixa e bem localizada, grupo pode bastar.

Checklist de legibilidade (use como revisão rápida)

ItemVerificação
Grupos nomeadosTodos os grupos seguem [SISTEMA] Assunto e têm comentário de cabeçalho
Sem duplicação óbviaSequências repetidas viraram funções (PlaySFX, ApplyDamage, ChangeScreen)
Variáveis consistentesGlobais g_*, locais l_*, instância com padrão definido
Estados centralizadosg_gameState (ou equivalente) é a fonte principal; flags auxiliares são documentadas
Busca rápidaVocê encontra qualquer regra em até 10–20 segundos usando nomes e estrutura

Exercício guiado: refatorar seu projeto atual

Tarefa A — reorganização por sistemas

  1. Crie os sheets: ES_Main, ES_Player, ES_Enemies, ES_UI, ES_Audio, ES_Combat.
  2. Mova eventos para o sheet correspondente (sem alterar lógica ainda).
  3. Crie grupos com o padrão [SISTEMA] Assunto e adicione comentários de cabeçalho.

Tarefa B — padronização

  1. Renomeie variáveis globais para g_*.
  2. Escolha e aplique padrão de HP/dano (instância) para Player e Enemies.
  3. Documente valores válidos de tags/strings usadas (em um comentário central).

Tarefa C — funções obrigatórias

  1. Implemente PlaySFX(name, volume, pitch) e substitua todas as ações diretas de tocar som.
  2. Implemente ChangeScreen(targetState, optionalLayout) e substitua transições espalhadas.
  3. Implemente ApplyDamage_Player(amount, sourceX, sourceY, sfxName) e ApplyDamage_Enemy(uid, amount, sourceX, sourceY, sfxName).

Tarefa D — caça à duplicação (auditoria)

  1. Use busca por palavras-chave: hp, Audio: Play, Go to layout, Set visible, Destroy.
  2. Para cada sequência repetida 2+ vezes, decida: vira função ou vira template de grupo.
  3. Após refatorar, remova eventos antigos duplicados e valide o comportamento (dano, UI, áudio, transições).

Agora responda o exercício sobre o conteúdo:

Em um projeto grande no Construct, qual prática melhor ajuda a manter a lógica legível e escalável, evitando duplicação e inconsistências entre sistemas?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

Separar por sistemas e por responsabilidade facilita encontrar regras e entender intenções. Centralizar lógicas repetidas em funções reduz duplicação, garante consistência (dano, áudio, transições) e torna a manutenção mais simples.

Próximo capitúlo

Construct do Zero: Otimização, Depuração e Testes Sem Programar

Arrow Right Icon
Capa do Ebook gratuito Construct do Zero: Desenvolvendo Jogos 2D Sem Programar (com Eventos)
89%

Construct do Zero: Desenvolvendo Jogos 2D Sem Programar (com Eventos)

Novo curso

18 páginas

Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.