---
title: "HUD de corações: do editor ao dano e cura"
version: snapshot-2026-10-06
engineGeneration: astra-current
language: C#
status: source-reviewed
runtimeVerified: false
platformEvidence: []
url: https://astraengine.com.br/pt-br/snapshot-2026-10-06/ui/hud-coracoes/
---
# HUD de corações: do editor ao dano e cura
Monte três corações com Image, ligue à vida do jogador e confira dano, cura e zero vida.
## É possível nesta versão?
**Sim, pela composição Canvas UI + Image + Behavior C#.** Image desenha o ícone e permite mudar Visible. A regra de vida é implementada no script PlayerHealth do exemplo. Não existe um componente pronto de "HUD de corações" ou binding automático de vida no snapshot. Este tutorial usa três corações inteiros; meio coração/preenchimento radial exigem outra composição, e Image não tem fillAmount.
## O resultado e a árvore
```text
Jogador HUD (objeto da cena)
└─ PlayerHealth ├─ Canvas UI → UI/hud.aeui
└─ HeartHud → Player = Jogador
UI/hud.aeui (documento)
├─ Hearts (Panel, sem fundo)
│ ├─ Empty1 (Image vazio) ← fica visível
│ ├─ Heart1 (Image cheio) ← script liga/desliga
│ ├─ Empty2 (Image vazio)
│ ├─ Heart2 (Image cheio)
│ ├─ Empty3 (Image vazio)
│ └─ Heart3 (Image cheio)
├─ Status (Text)
├─ Damage (Button)
└─ Heal (Button)
```
Os seis Images ficam sobrepostos em pares. Ao esconder Heart2, Empty2 continua desenhado na mesma posição. Use Panel com layout manual aqui; esconder filhos diretos de HBox pode reorganizar a fileira. A ordem é relevante: vazio primeiro, cheio depois.
Vida 2/3: ilustração com os recursos do tutorial. A execução real ocorre na Astra em Play.
## 1. Prepare os recursos
Adicione **Images/heart-full.png** e **Images/heart-empty.png** dentro do projeto. Use duas imagens 64 × 64 com alpha; ambas precisam existir e ser legíveis. [Baixe o pacote do tutorial](/examples/heart-hud/Astra-Heart-Hud.zip): inclui **UI/hud.aeui**, PNGs, scripts e [instruções](/examples/heart-hud/README.txt), para integrar num projeto existente. Abra e salve o .aeui pela área Interface para registrá-lo como recurso, ou siga a autoria manual abaixo. As duas imagens já aparecem no documento autoral, então o atlas conhece os dois recursos antes de esconder uma camada.
## 2. Crie o documento e preencha o layout
Siga [o caminho de autoria](/pt-br/snapshot-2026-10-06/ui/comece-aqui/) e salve **UI/hud.aeui**. Crie Panel e renomeie para **Hearts**. Selecionar Panel antes de criar Image faz os filhos pertencerem a ele. Todos usam âncoras inicial e final **(0,0)**.
| Elemento | Pai | Bordas: esquerda, topo, direita, base | Recurso / texto |
|---|---|---|---|
| Hearts, Panel | raiz | 24,24,184,72 | Desenhar fundo desligado |
| Empty1, Image | Hearts | 0,0,48,48 | Images/heart-empty.png |
| Heart1, Image | Hearts | 0,0,48,48 | Images/heart-full.png |
| Empty2, Image | Hearts | 56,0,104,48 | Images/heart-empty.png |
| Heart2, Image | Hearts | 56,0,104,48 | Images/heart-full.png |
| Empty3, Image | Hearts | 112,0,160,48 | Images/heart-empty.png |
| Heart3, Image | Hearts | 112,0,160,48 | Images/heart-full.png |
| Status, Text | raiz | 24,80,320,116 | Vida: 3/3 |
| Damage, Button | raiz | 24,124,124,168 | Dano |
| Heal, Button | raiz | 136,124,236,168 | Cura |
Para os Images, use **Ajuste = Conter**, **Tinta = branco**, **Visível = ligado**, **Clicável = desligado** e sem animação. Panel Hearts deve ter fundo transparente. Damage e Heal usam ação **Notificar**; não os configure para alterar Value do Image. Após criar os filhos, selecione a raiz/limpe a seleção antes de criar Status e os botões. Salve UI.
## 3. Configure a cena
1. Crie **HUD**, adicione **Canvas UI**, atribua **UI/hud.aeui** em **Documento UI**, use **Tela** e Habilitado.
2. Crie ou escolha **Jogador**. Ele pode ser só um objeto vazio para a demonstração por botão; física não é necessária nessa etapa.
3. Adicione os scripts abaixo na área de código, compile e anexe **PlayerHealth** a Jogador e **HeartHud** a HUD.
4. No Inspector do HeartHud, campo **Player**, escolha o objeto Jogador. Não escolha um Image da árvore UI: o campo é uma referência a objeto da cena.
5. Salve a cena e a UI. Receptor/câmera de entrada do Canvas podem ficar sem atribuição nesta demonstração visual.
## 4. Regra de vida: PlayerHealth.cs
[Baixar PlayerHealth.cs](/examples/heart-hud/PlayerHealth.cs)
```csharp
using System;
using Astra;
[ComponentId("docs.player-health")]
public sealed class PlayerHealth : Behavior
{
public const int Capacity = 3;
public int Current { get; private set; }
public bool IsDead => Current == 0;
public override void Awake() => Current = Capacity;
public void TakeDamage(int amount)
{
Current = Math.Max(0, Current - Math.Clamp(amount, 0, Capacity));
}
public void Heal(int amount)
{
Current = Math.Min(Capacity, Current + Math.Clamp(amount, 0, Capacity));
}
}
```
Awake começa com três corações. TakeDamage e Heal aceitam quantidades não negativas, limitadas à capacidade. Zero vida apenas muda o estado **IsDead**; este exemplo não inventa morte, respawn, animação ou persistência de save.
## 5. Ligar o estado às imagens: HeartHud.cs
[Baixar HeartHud.cs](/examples/heart-hud/HeartHud.cs)
```csharp
using System;
using Astra;
[ComponentId("docs.heart-hud")]
public sealed class HeartHud : Behavior
{
[PropertyId("player")]
public ObjectReference Player;
private GuiAccess hud = null!;
private PlayerHealth health = null!;
private readonly GuiElement[] hearts = new GuiElement[PlayerHealth.Capacity];
private GuiElement status;
private int lastHealth = -1;
public override void Start()
{
var player = Resolve(Player)
?? throw new InvalidOperationException("Atribua Jogador ao campo Player do HeartHud.");
health = player.GetBehavior()
?? throw new InvalidOperationException("Jogador precisa de PlayerHealth.");
hud = Gui.ForCanvas(Object);
for (int i = 0; i < hearts.Length; ++i)
{
hearts[i] = hud.Find($"Heart{i + 1}");
if (hearts[i].Kind != GuiKind.Image)
throw new InvalidOperationException($"Heart{i + 1} precisa ser Image.");
}
status = hud.Find("Status");
hud.Find("Damage");
hud.Find("Heal");
Refresh();
}
public override void Update(float deltaTime)
{
// Este script é o consumidor da fila deste Canvas.
while (hud.Poll(out var message))
{
if (message.Kind != GuiEventKind.Click) continue;
if (message.Element.Name == "Damage") health.TakeDamage(1);
else if (message.Element.Name == "Heal") health.Heal(1);
}
if (lastHealth != health.Current) Refresh();
}
private void Refresh()
{
lastHealth = health.Current;
for (int i = 0; i < hearts.Length; ++i)
hearts[i].Visible = i < lastHealth;
status.Text = $"Vida: {lastHealth}/{PlayerHealth.Capacity}"
+ (health.IsDead ? " | Sem vida" : "");
}
}
```
Gui.ForCanvas(Object) escolhe o Canvas do objeto HUD. Start resolve nomes e conserva handles somente desta execução. O script verifica os tipos dos corações e falha com mensagem quando Player/PlayerHealth estão ausentes. Update consome os botões e só escreve as imagens quando a vida muda. Não precisa procurar Heart1–3 a cada frame.
## 6. Dano vindo do gameplay
Outro Behavior pode resolver o jogador e chamar `player.GetBehavior()?.TakeDamage(1)` no momento real de um ataque. Para uma zona de dano, o arquivo abaixo usa **TriggerEnter**, uma vez por entrada, não TriggerStay a cada passo:
```csharp
using Astra;
[ComponentId("docs.heart-damage-trigger")]
public sealed class HeartDamageTrigger : Behavior
{
public override void TriggerEnter(ObjectReference other)
{
Resolve(other)?.GetBehavior()?.TakeDamage(1);
}
}
```
[Baixar HeartDamageTrigger.cs](/examples/heart-hud/HeartDamageTrigger.cs). Anexe à zona com corpo/colisor 3D em modo sensor. O outro objeto precisa participar da física 3D e carregar PlayerHealth. Consulte [Corpo físico](/pt-br/snapshot-2026-10-06/componentes/astra-physics-body/), [Colisor 3D](/pt-br/snapshot-2026-10-06/componentes/astra-physics-collider/) e [eventos físicos](/pt-br/snapshot-2026-10-06/sistemas/fisica-3d/). Eventos 2D têm contrato próprio; não substitua assinaturas por suposição. O script não define cooldown nem identifica filhos sem PlayerHealth: coloque o Behavior no objeto resolvido pelo evento ou adapte a busca explicitamente.
## 7. Conferir o resultado
| Ação em Play | Vida esperada | HUD esperado |
|---|---|---|
| Iniciar | 3 | três cheios, texto Vida: 3/3 |
| Dano | 2 | dois cheios e um vazio |
| Dano duas vezes | 0 | três vazios, texto Sem vida |
| Dano em zero | 0 | continua zero |
| Cura | 1 | um cheio e dois vazios |
| Cura até o máximo | 3 | não ultrapassa três |
| Parar e reabrir Play | 3 | reinicia, documento autoral preservado |
**Interagir não executa esses scripts.** Use Play para validar a ligação com a vida. Se a fonte recarregar durante Play, resolva novos handles ou reinicie.
Os três scripts deste tutorial compilaram sem erros contra o SDK do APK publicado. O documento do pacote foi gravado e relido pelo serializador nativo: formato AEUI 5, dez elementos. Isso verifica contratos e formato; o roteiro acima ainda precisa de aceite no Play e no aparelho. Consulte o [manifesto de exemplos](/snapshot-2026-10-06/examples.json) para a evidência de compilação.
## Responsividade, limite e roadmap
Os corações usam 160 × 48 px e margem 24 px no viewport Tela. Eles conservam tamanho e posição no canto superior esquerdo, sem assumir escala por resolução de referência. Confira landscape pequeno e tablet, notch/área segura, contraste e espaço da cena. Safe area automática e escala responsiva completa continuam em R5. Para fileira flexível, use HBox com **slots Panel** de tamanho preferido 48 × 48 e as duas Images dentro de cada slot.
Meios corações podem ser autorados com imagens adicionais e regra de meio ponto; nine-slice, fill radial, binding automático, timeline e templates completos continuam no [roadmap](/pt-br/snapshot-2026-10-06/ui/roadmap/). Vida persistente entre sessões pede SaveStore e regra explícita de save/load; não é consequência de salvar UI. Para erros, veja [diagnóstico de Image e HUD](/pt-br/snapshot-2026-10-06/ui/diagnostico/).