Tutorial 2026-03-19

Desenvolvimento de HUD Personalizado para FiveM - Do Zero

TDYSKY

TDYSKY

Fundador & Lead Developer na Agency Scripts

Por que construir um HUD personalizado

O HUD padrão do GTA V foi projetado para um jogo de ação para um jogador, não para os cenários complexos de RPG que os servidores FiveM exigem. Um HUD personalizado permite exibir informações específicas do RPG, como fome, sede, estresse e status do trabalho, que simplesmente não existem no GTA vanilla. Além da funcionalidade, um HUD personalizado define a identidade visual do seu servidor e dá o tom a partir do momento em que um jogador aparece. Os jogadores notam imediatamente a diferença de qualidade entre um servidor executando elementos de UI padrão e outro com um HUD polido e feito sob medida que combina com a marca e o tema do servidor. Construir seu próprio HUD do zero também significa controlar todos os aspectos do desempenho, garantindo que a sobreposição seja executada com custo mínimo de recursos e, ao mesmo tempo, fornecendo exatamente as informações que seus jogadores precisam.

Estrutura de recursos NUI

FiveM usa NUI (New User Interface) para renderizar HTML, CSS e JavaScript dentro do cliente do jogo. Seu recurso HUD precisa de uma estrutura de pastas específica para funcionar corretamente. O arquivo fxmanifest.lua declara os metadados do recurso, o script client.lua envia dados do jogo para a camada NUI e a pasta html/ contém sua interface baseada na web. Aqui está um manifesto de recursos mínimos para começar:

fx_version 'cerulean'
game 'gta5'

description 'Custom HUD'
author 'YourName'
version '1.0.0'

ui_page 'html/index.html'

client_script 'client.lua'

files {
    'html/index.html',
    'html/style.css',
    'html/script.js',
    'html/fonts/*.woff2'
}

A diretiva ui_page informa ao FiveM qual arquivo HTML renderizar como sobreposição NUI, e a tabela files lista todos os ativos aos quais o navegador precisa acessar. Se você esquecer de incluir um arquivo CSS ou fonte nesta lista, o navegador falhará silenciosamente ao carregá-lo sem qualquer mensagem de erro, o que é uma fonte comum de confusão para desenvolvedores novos no desenvolvimento NUI. Mantenha sua estrutura de recursos limpa separando as preocupações: HTML para layout, CSS para estilo e JavaScript para lógica e animações.

Enviando dados do jogo para a IU

O script Lua do lado do cliente é responsável por ler o estado do jogo e enviá-lo para a camada NUI em intervalos regulares. Você precisa reunir saúde, armadura e quaisquer valores de status específicos da estrutura, como fome e sede. A função principal é SendNUIMessage(), que envia uma carga JSON para o JavaScript em execução no quadro NUI. Seja estratégico quanto à frequência de atualização, pois o envio de dados a cada quadro desperdiça ciclos de CPU, enquanto a atualização muito lenta faz com que o HUD pareça lento. Uma taxa de tick de 200-500 milissegundos atinge o equilíbrio certo para barras de status:

CreateThread(function()
    while true do
        local ped = PlayerPedId()
        local health = GetEntityHealth(ped) - 100  -- GTA health starts at 100
        local maxHealth = GetEntityMaxHealth(ped) - 100
        local armor = GetPedArmour(ped)

        -- Framework-specific data (QBCore example)
        local playerData = QBCore.Functions.GetPlayerData()
        local hunger = playerData.metadata['hunger'] or 100
        local thirst = playerData.metadata['thirst'] or 100
        local stress = playerData.metadata['stress'] or 0

        SendNUIMessage({
            action = 'updateStatus',
            health = math.floor((health / maxHealth) * 100),
            armor = armor,
            hunger = math.floor(hunger),
            thirst = math.floor(thirst),
            stress = math.floor(stress)
        })

        Wait(300)
    end
end)

Para o velocímetro, você precisa de um thread separado rodando em uma taxa mais rápida porque a velocidade muda rapidamente e os jogadores esperam feedback em tempo real enquanto dirigem. Um intervalo de 50 a 100 milissegundos funciona bem para dados do veículo. Execute o thread do velocímetro apenas quando o jogador estiver realmente em um veículo para economizar recursos e desative-o quando ele sair:

CreateThread(function()
    while true do
        local ped = PlayerPedId()
        if IsPedInAnyVehicle(ped, false) then
            local veh = GetVehiclePedIsIn(ped, false)
            local speed = GetEntitySpeed(veh) * 3.6  -- Convert to km/h
            local rpm = GetVehicleCurrentRpm(veh)
            local gear = GetVehicleCurrentGear(veh)
            local fuel = GetVehicleFuelLevel(veh)

            SendNUIMessage({
                action = 'updateVehicle',
                speed = math.floor(speed),
                rpm = rpm,
                gear = gear,
                fuel = math.floor(fuel)
            })
            Wait(50)
        else
            SendNUIMessage({ action = 'hideVehicle' })
            Wait(500)
        end
    end
end)

Construindo a interface HTML e CSS

O design visual do seu HUD determina como você se sente no jogo. Os HUDs FiveM modernos usam designs limpos e minimalistas com fundos semitransparentes, cantos arredondados e animações sutis. Posicione suas barras de status no canto inferior esquerdo, onde não obstruam o jogo, e coloque o velocímetro no canto inferior direito quando o jogador estiver dirigindo. Use propriedades personalizadas CSS para cores para que você possa criar facilmente um tema para todo o HUD alterando algumas variáveis. Barras de progresso animadas com transições suaves dão ao HUD uma sensação refinada:

<!-- html/index.html -->
<div id="hud-container">
    <div class="status-bars">
        <div class="bar-wrapper">
            <i class="icon health-icon"></i>
            <div class="bar">
                <div class="bar-fill health-fill" id="health-bar"></div>
            </div>
        </div>
        <div class="bar-wrapper">
            <i class="icon armor-icon"></i>
            <div class="bar">
                <div class="bar-fill armor-fill" id="armor-bar"></div>
            </div>
        </div>
        <div class="bar-wrapper">
            <i class="icon hunger-icon"></i>
            <div class="bar">
                <div class="bar-fill hunger-fill" id="hunger-bar"></div>
            </div>
        </div>
        <div class="bar-wrapper">
            <i class="icon thirst-icon"></i>
            <div class="bar">
                <div class="bar-fill thirst-fill" id="thirst-bar"></div>
            </div>
        </div>
    </div>
    <div class="speedometer" id="speedometer" style="display:none">
        <div class="speed-value" id="speed-value">0</div>
        <div class="speed-unit">KM/H</div>
        <div class="fuel-bar">
            <div class="fuel-fill" id="fuel-bar"></div>
        </div>
    </div>
</div>

Para CSS, use transition na largura da barra para criar animações de preenchimento suave e aplique pointer-events: none a todo o contêiner do HUD para que não interfira na entrada do jogo. Cores diferentes para cada barra de status ajudam os jogadores a identificar rapidamente qual recurso está baixo, sem ler os rótulos. Vermelho para saúde, azul para armadura, laranja para fome e ciano para sede é uma convenção amplamente adotada que os jogadores entendem intuitivamente.

Tratamento de mensagens JavaScript

A camada JavaScript recebe mensagens do cliente Lua e atualiza o DOM de acordo. Registre um ouvinte de evento de mensagem que é despachado com base no campo de ação na carga útil. Mantenha sua lógica de atualização leve porque ela é executada em qualquer frequência com que seus threads Lua enviam dados, e qualquer atraso na camada JavaScript se traduz diretamente em falhas visuais. Evite consultas DOM dentro do manipulador de atualização armazenando em cache referências de elementos na inicialização:

// html/script.js
const elements = {
    healthBar: document.getElementById('health-bar'),
    armorBar: document.getElementById('armor-bar'),
    hungerBar: document.getElementById('hunger-bar'),
    thirstBar: document.getElementById('thirst-bar'),
    speedometer: document.getElementById('speedometer'),
    speedValue: document.getElementById('speed-value'),
    fuelBar: document.getElementById('fuel-bar')
};

window.addEventListener('message', (event) => {
    const data = event.data;

    switch (data.action) {
        case 'updateStatus':
            elements.healthBar.style.width = data.health + '%';
            elements.armorBar.style.width = data.armor + '%';
            elements.hungerBar.style.width = data.hunger + '%';
            elements.thirstBar.style.width = data.thirst + '%';

            // Color shift when low
            if (data.health < 25) {
                elements.healthBar.classList.add('critical');
            } else {
                elements.healthBar.classList.remove('critical');
            }
            break;

        case 'updateVehicle':
            elements.speedometer.style.display = 'flex';
            elements.speedValue.textContent = data.speed;
            elements.fuelBar.style.width = data.fuel + '%';
            break;

        case 'hideVehicle':
            elements.speedometer.style.display = 'none';
            break;
    }
});

Adicione uma classe CSS para estados críticos que aciona uma animação pulsante na barra, chamando a atenção do jogador quando sua saúde ou fome caem perigosamente. Esse tipo de feedback visual é muito mais eficaz do que depender dos jogadores para monitorar constantemente seus números de status e adiciona uma camada de polimento que separa os HUDs amadores dos profissionais.

Personalização do Minimapa

O minimapa padrão do GTA é funcional, mas entra em conflito visual com a maioria dos designs de HUD personalizados. FiveM oferece controle sobre a posição, tamanho, forma e nível de zoom do minimapa por meio de funções nativas. Você pode criar um minimapa circular, movê-lo para combinar com o layout do HUD ou até mesmo ocultá-lo totalmente e substituí-lo por uma solução personalizada. A abordagem mais comum é remodelar o minimapa para complementar a estética do seu HUD, mantendo intacta a funcionalidade subjacente do mapa do jogo:

CreateThread(function()
    -- Wait for map to load
    Wait(500)

    -- Set minimap shape and position
    local minimapHandle = RequestScaleformMovie('MINIMAP')
    SetMinimapClipType(1)  -- 0 = rectangle, 1 = circle

    -- Adjust minimap position and size
    local defaultAspect = 1920 / 1080
    local resX, resY = GetActiveScreenResolution()
    local aspect = resX / resY
    local ratio = defaultAspect / aspect

    SetMinimapComponentPosition('minimap', 'L', 'B',
        0.0, -0.032, 0.145 * ratio, 0.210)
    SetMinimapComponentPosition('minimap_mask', 'L', 'B',
        0.0, 0.032, 0.128 * ratio, 0.300)
    SetMinimapComponentPosition('minimap_blur', 'L', 'B',
        -0.01, -0.032, 0.272 * ratio, 0.420)

    -- Hide default health and armor bars
    local minimap = RequestScaleformMovie('MINIMAP')
    while not HasScaleformMovieLoaded(minimap) do Wait(0) end

    while true do
        -- Disable default HUD components
        HideHudComponentThisFrame(6)  -- Vehicle name
        HideHudComponentThisFrame(7)  -- Area name
        HideHudComponentThisFrame(8)  -- Vehicle class
        HideHudComponentThisFrame(9)  -- Street name
        Wait(0)
    end
end)

Ao personalizar o minimapa, sempre leve em consideração diferentes proporções de tela. Um minimapa que parece perfeito em uma tela 16:9 será esticado ou mal posicionado em monitores ultralargos. Calcule a proporção entre a proporção padrão e a real e aplique-a aos componentes de largura. Teste seu minimapa em pelo menos três resoluções comuns (1920x1080, 2560x1440 e 3440x1440) para garantir um posicionamento consistente em diferentes configurações de jogadores.

Ocultando elementos padrão do GTA HUD

Ao construir um HUD personalizado, você deve ocultar os elementos padrão do GTA que sua IU personalizada substitui, caso contrário, os jogadores verão informações duplicadas. FiveM fornece o HideHudComponentThisFrame() nativo para essa finalidade, mas deve ser chamado a cada quadro porque o GTA reativa os componentes do HUD a cada tick. Os IDs dos componentes cobrem tudo, desde as estrelas de procurado até a exibição do dinheiro e a roda da arma. Para um HUD de substituição completo, você normalmente deseja ocultar a barra de saúde, a barra de armadura, a exibição do dinheiro e os indicadores do veículo, mantendo visíveis elementos essenciais, como legendas e pop-ups de notificação. Crie uma tabela configurável de IDs de componentes para que os proprietários de servidores possam alternar quais elementos padrão ocultar sem modificar seu código. Além disso, use DisplayRadar(false) se o seu HUD incluir seu próprio substituto de minimapa, mas esteja ciente de que ocultar o radar também desativa o mapa do menu de pausa, a menos que você o reative quando o menu de pausa for detectado.

Melhores práticas de desempenho

O desempenho do HUD é fundamental porque ele funciona constantemente enquanto o jogador está no jogo, fazendo com que até mesmo pequenas ineficiências se transformem em quedas perceptíveis de quadros em sessões de jogo prolongadas. A otimização mais impactante é controlar a frequência de atualização. Barras de status que mudam lentamente, como fome e sede, podem ser atualizadas a cada 500 milissegundos ou até mesmo a cada segundo, enquanto valores que mudam rapidamente, como velocidade, precisam de atualizações mais frequentes. Use a renderização condicional para enviar mensagens NUI somente quando os valores realmente mudarem, em vez de enviar os mesmos dados repetidamente. No lado do JavaScript, evite innerHTML para atualizações porque isso força o navegador a analisar novamente o HTML e use textContent ou alterações diretas nas propriedades de estilo. Minimize as animações CSS em elementos que são atualizados com frequência porque o mecanismo de animação do navegador e as atualizações do JavaScript podem entrar em conflito, causando falhas visuais. Se o seu HUD usa fontes personalizadas, pré-carregue-as no cabeçalho HTML para evitar mudanças de layout quando o arquivo de fonte terminar de carregar. Por fim, crie o perfil de seu recurso usando o comando resmon integrado do FiveM e faça com que seu HUD consuma menos de 0,1 ms por quadro em média, deixando espaço para dezenas de outros recursos em execução no cliente.

Partilhar este artigo

Pronto para melhorar o teu servidor?

Explora os nossos scripts FiveM premium na loja Agency Scripts ou junta-te à nossa comunidade no Discord para suporte e atualizações.