Creating a Custom Health Bar HUD Element with VGUI2 in Source Engine
Step‑by‑step guide to adding a custom VGUI2 health bar HUD element in Source Engine, including code, registration, compilation, and verification.
25 Jan 2026, 04:17 UTC

Desired Outcome
Add a reusable VGUI2 panel that draws a health bar for the local player, updates each frame, and scales correctly across different resolutions.
Prerequisites
- Source SDK 2013 (or later) installed and a working mod or game project.
- Basic C++ knowledge and ability to rebuild the client DLL (
client.dll). - Access to VGUI2 headers (
vgui_controls.h,vgui.h) and the engine interfaces. - A backup of the original
client.dllbefore making changes.
Procedure
-
Create the panel class
Add a new header
HealthBar.hand source fileHealthBar.cppto the client project.// HealthBar.h #pragma once #include class HealthBar : public vgui::Panel { DECLARE_CLASS_SIMPLE( HealthBar, vgui::Panel ); public: HealthBar( vgui::Panel *parent, const char *name ); virtual void OnThink() override; virtual void Paint() override; private: int m_iHealth; // cached health value };// HealthBar.cpp #include "HealthBar.h" #include "cbase.h" #include "vgui/ISurface.h" #include "vgui/ISystem.h" #include "vgui/ILocalize.h" using namespace vgui; HealthBar::HealthBar( Panel *parent, const char *name ) : BaseClass( parent, name ), m_iHealth( 100 ) { SetSize( 200, 20 ); // initial size; will be scaled later SetPos( 10, 10 ); // top‑left corner; will be adjusted in OnThink SetPaintBackgroundEnabled( true ); SetBgColor( Color( 0, 0, 0, 120 ) ); // semi‑transparent dark background } void HealthBar::OnThink() { BaseClass::OnThink(); C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( !pPlayer ) return; int newHealth = pPlayer->GetHealth(); if ( newHealth != m_iHealth ) { m_iHealth = newHealth; // Force a repaint when health changes Repaint(); } // Keep panel within screen bounds using proportional scaling int screenWide, screenTall; engine->GetScreenSize( screenWide, screenTall ); int wide = vgui::scheme()->GetProportionalScaledValue( 200 ); int tall = vgui::scheme()->GetProportionalScaledValue( 20 ); SetSize( wide, tall ); SetPos( 10, screenTall - tall - 10 ); // bottom‑left with margin } void HealthBar::Paint() { BaseClass::Paint(); int wide, tall; GetSize( wide, tall ); // Draw red health bar proportionally int healthWide = ( wide * m_iHealth ) / 100; surface()->DrawSetColor( Color( 200, 0, 0, 255 ) ); surface()->DrawFilledRect( 0, 0, healthWide, tall ); // Optional: draw a white border surface()->DrawSetColor( Color( 255, 255, 255, 255 ) ); surface()->DrawOutlinedRect( 0, 0, wide, tall ); } -
Register the panel with VGUI
In the client DLL’s initialization function (usually
ClientDLL_Initor similar), add the panel to the VGUI hierarchy using theGET_PANELmacro.// Example snippet inside ClientDLL_Init #include "HealthBar.h" void ClientDLL_Init( void ) { // ... existing init code ... // Create a panel under the game UI root vgui::Panel *pGameParent = g_pVGui->GetPanel( PANEL_GAMEUIDLL ); new HealthBar( pGameParent, "HealthBar" ); // ... rest of init ... } -
Recompile and launch
Build the client DLL (ensure you have the correct configuration for Debug or Release). Copy the resulting
client.dllinto your mod’sbinfolder, then launch the game.
Expected Checks
- Visual confirmation: the health bar appears at the bottom‑left of the screen, scales with resolution, and shows a red fill proportional to the player’s health.
- Functional check: inflict damage or use a health kit; the bar should update instantly without noticeable FPS impact.
- Console verification: open the console (
~) and runvgui_drawtree 1. The hierarchy should list a panel namedHealthBarunderPANEL_GAMEUIDLL. - Error check: watch for any
VGUI:warnings whendeveloper 1is enabled.
Recovery Options
- If the panel does not appear, verify that the
GET_PANELmacro was called after VGUI is initialized (typically afterg_pVGui->Initialize). - Revert to a known‑working HUD element (e.g., the default crosshair) by commenting out the
new HealthBarline and rebuilding. - Check the build output for missing includes or linker errors; ensure
vgui_controls.libis linked. - Run with debug symbols (
-debuglaunch option) to catch assertions that may indicate threading violations (VGUI must be accessed on the main thread).
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.