Construct do Zero: Sistema de Vida, Dano, Coleta e Pontuação

Capítulo 9

Tempo estimado de leitura: 12 minutos

+ Exercício

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.HP

Dica: 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).

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

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 HP
Player is overlapping Enemy AND Player.Invuln = 0  -> Player: Set Invuln to 1
Player is overlapping Enemy AND Player.Invuln = 0  -> Player: Start timer reminder "invuln" for Player.InvulnTime seconds
Player: On timer "invuln"  -> Player: Set Invuln to 0

Observaçã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 HP
Player is overlapping Bullet AND Player.Invuln = 0  -> Bullet: Destroy
Player is overlapping Bullet AND Player.Invuln = 0  -> Player: Set Invuln to 1
Player is overlapping Bullet AND Player.Invuln = 0  -> Player: Start timer "invuln" for Player.InvulnTime seconds

Se 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 += 16

Dica: 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 100

Se 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 true

Som 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 txtScore e atualize:
Every tick -> txtScore: Set text to "Score: " & gScore

Evento de coleta:

Player is overlapping Coin -> Add 10 to gScore
Player 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: Destroy

Importante: 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: Destroy

Se seu Construct não tiver min disponível diretamente, faça por condição:

If Player.HP < Player.MaxHP -> Add 1 to Player.HP

Condiçã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:

  • gGameOver inicial 0

Eventos:

Player.HP <= 0 AND gGameOver = 0 -> Set gGameOver to 1
Player.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

ParteO que deve acontecerComo validar
HPPlayer começa com HP definido e HUD mostraAo iniciar, texto mostra HP correto
Dano por contatoEncostar no Enemy reduz HP 1 vez e ativa invulnSegurar encostado não drena HP rapidamente
KnockbackAo tomar dano, Player é empurrado para longeVisualmente afasta do Enemy
Feedback de hitFlash + som + partículas apenas quando dano ocorreDurante invuln não repete som/partículas
CoinColetar soma +10 e destrói moedaScore aumenta e moeda some
ItemHealColetar cura +1 sem passar do MaxHPHP não ultrapassa MaxHP
Game OverAo HP <= 0, troca para layout GameOver uma vezNão fica “piscando” entre telas

Eventos mínimos do exercício (modelo)

1) HUD

Every tick -> txtHP: Set text to "HP: " & Player.HP
Every tick -> txtScore: Set text to "Score: " & gScore

2) Dano por contato com cooldown

Player overlapping Enemy AND Player.Invuln = 0 AND gGameOver = 0 -> Subtract 1 from Player.HP
Player overlapping Enemy AND Player.Invuln = 0 AND gGameOver = 0 -> Set Player.Invuln to 1
Player overlapping Enemy AND Player.Invuln = 0 AND gGameOver = 0 -> Start timer "invuln" for Player.InvulnTime
Player 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 burst
Player overlapping Enemy AND Player.Invuln = 0 AND gGameOver = 0 -> Apply knockback (simple push)
Player: On timer "invuln" -> Set Player.Invuln to 0

3) Flash durante invulnerabilidade

Player.Invuln = 1 -> Player: Set visible to (floor(time*10) % 2 = 0)
Player.Invuln = 0 -> Player: Set visible to true

4) Coleta de Coin

Player overlapping Coin -> Add 10 to gScore
Player overlapping Coin -> Audio: Play "sfx_coin"
Player overlapping Coin -> Particles: Set position to (Coin.X, Coin.Y); Spawn burst
Player overlapping Coin -> Coin: Destroy

5) Coleta de ItemHeal

Player overlapping ItemHeal -> If Player.HP < Player.MaxHP then Add 1 to Player.HP
Player overlapping ItemHeal -> Audio: Play "sfx_heal"
Player overlapping ItemHeal -> ItemHeal: Destroy

6) Game Over com trava

Player.HP <= 0 AND gGameOver = 0 -> Set gGameOver to 1
Player.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 = 0 antes de subtrair HP, ou o timer não está voltando Invuln para 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 gGameOver ou 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.X para empurrar para longe) e teste com inimigo em ambos os lados.

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

Ao implementar dano por contato entre Player e Enemy em um jogo feito por eventos, qual abordagem evita que o HP diminua várias vezes por segundo enquanto os sprites continuam sobrepostos?

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

Você errou! Tente novamente.

Como o overlap pode ficar verdadeiro por vários ticks, é preciso uma trava. Checar Invuln=0 antes de dar dano e ativar um cooldown por timer garante que o HP só diminua uma vez até a invulnerabilidade terminar.

Próximo capitúlo

Construct do Zero: UI e HUD (Textos, Barras, Ícones e Botões)

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

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.