--- 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.
Coração cheioCoração cheioCoração vazio
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/).