Visão geral das mecânicas do capítulo
Neste capítulo você vai montar um “núcleo” de gameplay baseado em variáveis e eventos: vida (HP) do jogador, dano (por contato e por projétil), knockback simples, coleta de moedas/itens, pontuação, feedbacks (flash, som e partículas) e condição de derrota (Game Over). O objetivo é que tudo funcione de forma confiável, evitando um problema comum em jogos por eventos: o dano duplicar a cada tick enquanto o jogador continua encostado no inimigo.
Objetos e variáveis que você vai usar
- Player (sprite do jogador)
- Enemy (sprite do inimigo)
- Bullet (projétil do inimigo, opcional)
- Coin (coletável)
- Item (coletável especial, opcional: cura/bonus)
- Particles (objeto de partículas para hit e coleta)
- Audio (para SFX)
- Text/BitmapText para HUD (HP e Score)
Variáveis recomendadas:
- Global number
gScore(pontuação) - Player instance variables:
HP,Invuln(0/1),InvulnTime(segundos),KnockX,KnockY - Enemy instance variable (opcional):
Damage - Bullet instance variable (opcional):
Damage
Sistema de Vida (HP) e HUD
Conceito
HP é um número que representa quantos “pontos de vida” o jogador possui. Quando recebe dano, o HP diminui. Quando chega a 0, o jogo entra em estado de derrota. O HUD é apenas a visualização dessas variáveis (não é a lógica).
Passo a passo: criar HP e exibir no HUD
- No Player, crie a variável de instância
HP(ex.: valor inicial 5). - Crie (ou use) um texto de HUD:
txtHP. - Evento para atualizar o texto (a cada tick ou quando necessário):
Every tick -> txtHP: Set text to "HP: " & Player.HPDica: se você preferir otimizar, atualize o texto apenas quando o HP mudar (usando uma função/flag). Para começar, Every tick é suficiente e simples.
Dano por contato (Enemy encostando no Player) sem duplicar por ticks
O problema do dano duplicado
Em Construct, a condição “Player is overlapping Enemy” pode ficar verdadeira por vários ticks seguidos enquanto os sprites continuam encostados. Se você subtrair HP diretamente ali, o jogador perde vida muito rápido (várias vezes por segundo).
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
Solução 1 (recomendada): invulnerabilidade temporária (cooldown)
Você aplica dano uma vez e ativa um estado de invulnerabilidade por um curto período. Durante esse tempo, o jogador não toma dano novamente.
Passo a passo: variáveis e timer de invulnerabilidade
- No Player, crie variáveis:
Invuln(inicial 0)InvulnTime(ex.: 0.6)
Eventos:
Player is overlapping Enemy AND Player.Invuln = 0 -> Player: Subtract 1 from HPPlayer is overlapping Enemy AND Player.Invuln = 0 -> Player: Set Invuln to 1Player is overlapping Enemy AND Player.Invuln = 0 -> Player: Start timer reminder "invuln" for Player.InvulnTime secondsPlayer: On timer "invuln" -> Player: Set Invuln to 0Observação: o nome do recurso pode variar conforme sua versão/estilo (timer por comportamento, plugin de timer, ou “Wait”). Se você usar Wait, garanta que ele esteja no mesmo bloco que setou Invuln, e que não crie múltiplas esperas em paralelo. Uma forma segura é usar um timer por instância do Player.
Solução 2 (alternativa): Trigger once enquanto sobreposto
Você pode usar Trigger once dentro do evento de overlap. Porém, isso só dispara novamente quando a condição deixa de ser verdadeira e volta a ser verdadeira. Em muitos jogos, o jogador pode ficar “preso” no inimigo e nunca mais tomar dano (ou tomar pouco), então a invulnerabilidade temporária costuma ser mais controlável.
Dano por projétil (Bullet) com destruição e cooldown
Conceito
Projéteis normalmente causam dano ao tocar o jogador e depois são destruídos (ou desativados). Mesmo assim, ainda é importante respeitar a invulnerabilidade para evitar múltiplos hits em situações de spawn/overlap.
Passo a passo: dano do Bullet
Defina o dano do projétil:
- Crie em Bullet a variável
Damage(ex.: 1).
Eventos:
Player is overlapping Bullet AND Player.Invuln = 0 -> Player: Subtract Bullet.Damage from HPPlayer is overlapping Bullet AND Player.Invuln = 0 -> Bullet: DestroyPlayer is overlapping Bullet AND Player.Invuln = 0 -> Player: Set Invuln to 1Player is overlapping Bullet AND Player.Invuln = 0 -> Player: Start timer "invuln" for Player.InvulnTime secondsSe você quiser que o projétil atravesse e possa acertar depois, em vez de destruir, você pode desativar colisão por um tempo ou usar um sistema de “já acertou” por UID. Para o núcleo do capítulo, destruir é o mais simples.
Knockback simples (empurrão ao tomar dano)
Conceito
Knockback é um deslocamento rápido do jogador na direção oposta ao atacante. Ele melhora o “feeling” do hit e ajuda a evitar que o jogador fique colado no inimigo tomando dano em sequência.
Implementação prática (sem física complexa)
Você pode aplicar um impulso simples alterando a posição ou usando um comportamento de movimento. Uma abordagem comum é: ao receber dano, calcular um vetor de empurrão e aplicar por poucos frames.
Crie no Player:
KnockX(0)KnockY(0)
Ao tomar dano por contato (no mesmo bloco onde subtrai HP):
Player is overlapping Enemy AND Player.Invuln = 0 -> Player: Set KnockX to (Player.X - Enemy.X)Player is overlapping Enemy AND Player.Invuln = 0 -> Player: Set KnockY to (Player.Y - Enemy.Y)Player is overlapping Enemy AND Player.Invuln = 0 -> Player: Set position to (Player.X + normalize(KnockX,KnockY).x * 16, Player.Y + normalize(KnockX,KnockY).y * 16)Como Construct não tem uma função única “normalize” padrão em todos os setups, você pode simular normalização com magnitude:
Let mag = sqrt(KnockX*KnockX + KnockY*KnockY)dx = KnockX / max(mag, 0.001)dy = KnockY / max(mag, 0.001)Set position to (X + dx*16, Y + dy*16)Se preferir algo ainda mais simples (e aceitável para protótipo): empurre apenas no eixo X baseado em quem está à esquerda/direita:
On damage -> If Player.X < Enemy.X then Player.X -= 16 else Player.X += 16Dica: se o seu Player usa um behavior de movimento, você pode também zerar momentaneamente a velocidade e aplicar uma força/impulso, mas o deslocamento direto funciona bem para um knockback “arcade”.
Feedback de dano: flash, som e partículas
Conceito
Feedback é o que faz o jogador “sentir” que tomou dano: um flash visual, um som curto e um efeito de partículas. O ideal é disparar esses feedbacks apenas quando o dano realmente acontece (ou seja, no mesmo evento que reduz HP, e não em todo tick de overlap).
Passo a passo: flash (piscar) durante invulnerabilidade
Uma técnica simples é alternar a opacidade enquanto Invuln=1.
Player.Invuln = 1 -> Player: Set opacity to (50 + 50 * sin(time*20))Player.Invuln = 0 -> Player: Set opacity to 100Se você preferir um pisca mais “quadrado”:
Player.Invuln = 1 -> Player: Set visible to (floor(time*10) % 2 = 0)Player.Invuln = 0 -> Player: Set visible to trueSom de hit
On damage event -> Audio: Play "sfx_hit" (not looping)Partículas de hit
On damage event -> Particles: Set position to (Player.X, Player.Y)On damage event -> Particles: Spawn/Start (burst curto)Se você tiver dois tipos de partículas (hit e coleta), mantenha objetos separados ou troque o preset antes de emitir.
Coleta de moedas/itens e pontuação
Conceito
Coletáveis normalmente fazem três coisas: (1) incrementam uma variável (score, moedas, inventário), (2) dão feedback (som/partícula/animação), (3) removem o item do cenário para não coletar de novo.
Passo a passo: moeda que soma pontos
- Crie a variável global
gScore(inicial 0). - Crie um texto
txtScoree atualize:
Every tick -> txtScore: Set text to "Score: " & gScoreEvento de coleta:
Player is overlapping Coin -> Add 10 to gScorePlayer is overlapping Coin -> Audio: Play "sfx_coin"Player is overlapping Coin -> Particles: Set position to (Coin.X, Coin.Y)Player is overlapping Coin -> Particles: Spawn/Start (burst curto)Player is overlapping Coin -> Coin: DestroyImportante: aqui não costuma haver problema de “duplicar por ticks” porque a moeda é destruída no mesmo evento. Ainda assim, se você estiver usando animação de coleta (em vez de destruir), use um estado/flag Collected na moeda para garantir que só conte uma vez.
Item especial (ex.: cura) com limite máximo de HP
Defina um máximo de vida. Você pode usar uma variável global gMaxHP ou uma variável no Player MaxHP. Exemplo com MaxHP no Player:
- No Player:
MaxHP(ex.: 5)
Evento de coleta de item de cura:
Player is overlapping ItemHeal -> Player.HP = min(Player.HP + 1, Player.MaxHP)Player is overlapping ItemHeal -> Audio: Play "sfx_heal"Player is overlapping ItemHeal -> ItemHeal: DestroySe seu Construct não tiver min disponível diretamente, faça por condição:
If Player.HP < Player.MaxHP -> Add 1 to Player.HPCondição de derrota (Game Over) ao chegar a 0
Conceito
A derrota deve acontecer quando o HP chega a 0 (ou menor). É importante disparar isso uma única vez, para evitar múltiplas trocas de tela, múltiplos sons, etc.
Passo a passo: evento de Game Over com trava
Crie uma variável global gGameOver (0/1) ou uma variável no Player. Exemplo com global:
gGameOverinicial 0
Eventos:
Player.HP <= 0 AND gGameOver = 0 -> Set gGameOver to 1Player.HP <= 0 AND gGameOver = 0 -> Audio: Play "sfx_gameover"Player.HP <= 0 AND gGameOver = 0 -> System: Go to layout "GameOver" (or restart current)Se você não tiver uma tela GameOver pronta, pode reiniciar o layout atual após um pequeno delay. Para evitar duplicação, use a trava gGameOver antes do delay.
Organizando os eventos: “On damage” como bloco central
Por que centralizar?
Quando você tem dano por contato e por projétil, é comum duplicar lógica (subtrair HP, invulnerabilidade, flash, som, partículas, knockback). Centralizar reduz erros e facilita ajustes.
Estratégia prática (sem programar)
Você pode criar um grupo de eventos “DAMAGE” e padronizar ações. Exemplo de padrão:
- Condições de hit (contato/projétil) apenas definem quem causou e quanto de dano.
- Um bloco comum aplica: reduzir HP, setar invuln, feedback e knockback.
Se você usa Funções no Construct, pode criar uma função ApplyDamage(amount, sourceX, sourceY). Se não quiser usar funções, mantenha o mesmo conjunto de ações copiado, mas sempre dentro do mesmo gatilho Player.Invuln = 0.
Exercício guiado: coletáveis + dano confiável + Game Over
Objetivo do exercício
- Criar 2 tipos de coletáveis: Coin (score) e ItemHeal (cura).
- Implementar dano por contato com cooldown (invulnerabilidade) para não duplicar por ticks.
- Adicionar feedback (flash + som + partículas) no dano e na coleta.
- Enviar para GameOver quando HP chegar a 0.
Checklist de implementação
| Parte | O que deve acontecer | Como validar |
|---|---|---|
| HP | Player começa com HP definido e HUD mostra | Ao iniciar, texto mostra HP correto |
| Dano por contato | Encostar no Enemy reduz HP 1 vez e ativa invuln | Segurar encostado não drena HP rapidamente |
| Knockback | Ao tomar dano, Player é empurrado para longe | Visualmente afasta do Enemy |
| Feedback de hit | Flash + som + partículas apenas quando dano ocorre | Durante invuln não repete som/partículas |
| Coin | Coletar soma +10 e destrói moeda | Score aumenta e moeda some |
| ItemHeal | Coletar cura +1 sem passar do MaxHP | HP não ultrapassa MaxHP |
| Game Over | Ao HP <= 0, troca para layout GameOver uma vez | Não fica “piscando” entre telas |
Eventos mínimos do exercício (modelo)
1) HUD
Every tick -> txtHP: Set text to "HP: " & Player.HPEvery tick -> txtScore: Set text to "Score: " & gScore2) Dano por contato com cooldown
Player overlapping Enemy AND Player.Invuln = 0 AND gGameOver = 0 -> Subtract 1 from Player.HPPlayer overlapping Enemy AND Player.Invuln = 0 AND gGameOver = 0 -> Set Player.Invuln to 1Player overlapping Enemy AND Player.Invuln = 0 AND gGameOver = 0 -> Start timer "invuln" for Player.InvulnTimePlayer overlapping Enemy AND Player.Invuln = 0 AND gGameOver = 0 -> Audio: Play "sfx_hit"Player overlapping Enemy AND Player.Invuln = 0 AND gGameOver = 0 -> Particles: Set position to (Player.X, Player.Y); Spawn burstPlayer overlapping Enemy AND Player.Invuln = 0 AND gGameOver = 0 -> Apply knockback (simple push)Player: On timer "invuln" -> Set Player.Invuln to 03) Flash durante invulnerabilidade
Player.Invuln = 1 -> Player: Set visible to (floor(time*10) % 2 = 0)Player.Invuln = 0 -> Player: Set visible to true4) Coleta de Coin
Player overlapping Coin -> Add 10 to gScorePlayer overlapping Coin -> Audio: Play "sfx_coin"Player overlapping Coin -> Particles: Set position to (Coin.X, Coin.Y); Spawn burstPlayer overlapping Coin -> Coin: Destroy5) Coleta de ItemHeal
Player overlapping ItemHeal -> If Player.HP < Player.MaxHP then Add 1 to Player.HPPlayer overlapping ItemHeal -> Audio: Play "sfx_heal"Player overlapping ItemHeal -> ItemHeal: Destroy6) Game Over com trava
Player.HP <= 0 AND gGameOver = 0 -> Set gGameOver to 1Player.HP <= 0 AND gGameOver = 0 -> Audio: Play "sfx_gameover"Player.HP <= 0 AND gGameOver = 0 -> Go to layout "GameOver"Erros comuns e como corrigir
- HP derrete ao encostar no inimigo: faltou checar
Player.Invuln = 0antes de subtrair HP, ou o timer não está voltandoInvulnpara 0. - Som de hit toca várias vezes: o som está em um evento que roda todo tick (overlap sem cooldown). Mova o som para o mesmo bloco do dano (com
Invuln=0). - Game Over dispara várias vezes: faltou a trava
gGameOverou ela é setada depois do “Go to layout”. Sempre setar a trava antes. - Coletável soma várias vezes: o item não está sendo destruído/desativado imediatamente, ou precisa de uma flag
Collected. - Knockback empurra para direção errada: inverta o sinal (use
Player.X - Enemy.Xpara empurrar para longe) e teste com inimigo em ambos os lados.