Cleanup is going to take awhile, so the site is back up but editing has been disabled.
Hud Monitor
From HalfLife 2 Knowledge Base
Contents |
- By Wilco
OVERVIEW
This tutorial focuses on Adding a New Element to the already existing HUD. It Doesn't go into sending messages from the Server to the client that the HUD hooks into (See Valve SDK Documentation). It assumes a basic understanding of C++ syntax and using Classes, and that you know how to compile the SDK and run it, but thats about it.
This particular method was done using a blank Single Player MOD, I haven't tried the multiplayer part yet, so that may be slightly different (However this is a very simple client side only MOD so It will probably work fine).
The HUD is a VGUI 2 hierarchy. There is a main window/hud (accessed by g_pClientMode->GetViewport() ) which is basically the screen. This is the parent of other VGUI Panels, which make up the individual HUD components, I.E. Health count, Ammo count, etc. Each Component derives from VGUI::Panel. Valve also made a CHudNumericDisplay class you can use to show simple components like the health and ammo (it derives from VGUI::Panel itself).
SOURCE CODE FILES
Hud_Monitor.h
The only files you need to worry about for this are on the client side. All the HUD components are in Client->Source Files->HL2 DLL in VS2003 Solution explorer, or cl_dll\hl2_hud in the windows folder heirarchy. We will first make a new blank header file here called hud_monitor.h (Right Click on HL2_DLL folder in the Solution explorer and choose Add->New Item). I would recommend putting this in cl_dll\hl2_hud with the other hud files, but it can be anywhere.
In this we'll put:
#include "hudelement.h"
#include <vgui_controls/Panel.h>
class CHudMonitor : public CHudElement, public vgui::Panel
{
DECLARE_CLASS_SIMPLE( CHudMonitor, vgui::Panel );
public:
CHudMonitor( const char *pElementName );
protected:
virtual void Paint();
int m_nTextureID;
};
The 2 includes allow us to derive from CHudElement and vgui::Panel, which are the standard base classes for a HUD Panel.
Our Class is called CHudMonitor, its good to tie Class Names to the File name, just makes things easier :). It derives from CHudElement (an interface for adding this class to the hud), and the basic VGUI Panel class.
Inside our class we call a Macro, which basically tells the compiler to put a set of instructions in place of where the macro is, putting in the arguments we supply. This performs some housekeeping with HL2 classes declarations.
Under Public definitions we put the constructor. Under Protected we put the Paint(); function. This is itself an override of the Paint function in the base classes, but we need to do some stuff to show our texture here. We also put the variable m_nTextureID, which will act as an Index to our Texture.
Thats it for monitor.h.
Hud_Monitor.cpp
Now we need the actual implementation of the classes, so create a file called hud_monitor.cpp' in the same folder. In it we'll start with this:
#include "hud.h" #include "cbase.h" #include "hud_monitor.h" #include "iclientmode.h" #include "hud_macros.h" #include "vgui_controls/controls.h" #include "vgui/ISurface.h" #include "tier0/memdbgon.h"
hud.h is an generic include file handling some basic Hud Commands cbase.h is another generic file that includes other important header files hud_monitor.h is the header we just created with the definition iclientmode.h defines the vgui namespace and some the GetViewport() function hud_macros.h is not used in this tutorial, but contains the macro definitions like HOOK_HUD_MESSAGE that allow you to connect to server->client msgs, so useful controls.h contains lots of vgui namespace definitions for controls for forms. ISurface.h containts some nice VGUI drawing commands.
memdbgon.h appears to allow memory debugging, not sure about that but looks important :).
now add this below:
CHudMonitor::CHudMonitor( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "HudMonitor" )
{
vgui::Panel *pParent = g_pClientMode->GetViewport();
SetParent( pParent );
//AW Create Texture for Looking around
m_nTextureID = vgui::surface()->CreateNewTextureID();
vgui::surface()->DrawSetTextureFile( m_nTextureID, "debug/debugcamerarendertarget" , true, true);
SetHiddenBits( HIDEHUD_PLAYERDEAD | HIDEHUD_NEEDSUIT );
};
DECLARE_HUDELEMENT( CHudMonitor );
This defines the CHudMonitor Constructor Function. Those of you who know a bit more about Classes in C++ will see it also automatically calls function CHudElement and the Base Class's constructors. These are necessary so keep them in, but note the second parameter for the Base Class call, here it is "HudMonitor". This is the name by which the Code will find more information in the hudlayout.res file, which is mentioned after this coding section.
In this constructor function we firstly get the Main Viewport using g_pClientMode->GetViewport(), which is a VGUI Panel, And set it as our parent. The SetParent Function is a comes from the Panel Base Class we derived from. We then get a new Texture ID (An index to a place to put our texture), and then Set the texture file we will want to draw later (This doesn't do it itself). I'm not 100% sure what the 2 true commands refer to but It looks like a good idea to leave them as true if you use this function. The texture file im using for this is the debug texture for cameras, but you can use any texture you want to show.
SetHiddenBits is another command from a VGUI Panel, and says under what circumstances we don't want to show the Panel. You can use:
HIDEHUD_WEAPONSELECTION // Hide ammo count & weapon selection HIDEHUD_FLASHLIGHT HIDEHUD_ALL HIDEHUD_HEALTH // Hide health & armor / suit battery HIDEHUD_PLAYERDEAD // Hide when local player's dead HIDEHUD_NEEDSUIT // Hide when the local player doesn't have the HEV suit HIDEHUD_MISCSTATUS // Hide miscellaneous status elements (trains, pickup history, death notices, etc) HIDEHUD_CHAT // Hide all communication elements (saytext, voice icon, etc) HIDEHUD_CROSSHAIR // Hide crosshairs HIDEHUD_VEHICLE_CROSSHAIR // Hide vehicle crosshair HIDEHUD_INVEHICLE
Rather Annoyingly if you dont put anything, or just HIDEHUD_PLAYERDEAD, it will show on the main screen if you have a cool Map Background, so HIDEHUD_NEEDSUIT is a good 1 (Plus you need the suit to see the rest anyway by default).
And Finally:
void CHudMonitor::Paint()
{
vgui::surface()->DrawSetTexture( m_nTextureID );
vgui::surface()->DrawTexturedRect( 0, 0, this->GetWide(), this->GetTall() );
}
vgui::Surface() gets us a pointer to a Class we can use to draw stuff with. DrawSetTexture sets the texture (from a textureID) it will use to draw with, and DrawTextureRect draws a Rectangle with this texture (duh). The argument for this are:
position of top left corner across relative to top left of the panel position of top left corner down relative to top left of the panel rectangle width rectangle height
this->GetWide() and GetTall() just gets the current Width and height of this panel.
Now Compile the code, and try running it. (you'll need to use Impulse 101 in the console to give yourself the suit and stuff) :).
RESOURCE FILES
This code will draw us a panel, but it will be right in the top left corner and very small :). To change this Valve have a file called hudlayout.res in the scripts/ folder. This contains the basic parameters of the Hud Layout.
Open it up and at the top and after
"Resource/HudLayout.res"
{
add this:
HudMonitor
{
"fieldName" "HudMonitor"
"xpos" "0"
"ypos" "0"
"wide" "266"
"tall" "200"
"visible" "1"
"enabled" "1"
}
HudMonitor is the name we put in the base constructor call above. If you change this change the Baseclass(NULL,"HudMonitor") call aswll. For fieldname, just keep it the same as the main name. xpos Sets the X position of the Top left corner ypos Sets the Y position of the top left corner wide sets how wide the panel is tall sets how tall it is visible sets its default state to visible enabled.... makes it enabled by default.
These are standard and loaded into existing variables in code. If you don't put them in default values will be used.
IMPORTANT POINT: These values refer to a screen resolution of 640x480. VGUI will automatically scale these values to match other resolutions, so remember that when thinking up values. putting a r in the xpos field will justify it to the right of the screen, but it still refers to the top LEFT point of the panel, so "r0" will put your panel off the right of the screen. It took me 3 days to work out this was why my panel wouldn't show :).
There You go:
Further bits
hudlayout.res includes none standard field definitions. To use these put
CPanelAnimationVarAliasType( type, variable_name, "name_in_file", "default_value", "special" );
Special is an optional field, you can use "proportional_float" to make this variable value proportional to screen scaling from 640x480 resolution

