Posted by: [ICR]
Date posted: Jun 22 2004 User Rating: N/A | Number of views: 2880 Number of comments: 0 | Description: This article describes the principles behind coding a VGUI HUD by piggy backing off the existing HUD, seriously reducing the amount of code needed. |
The purpose of this tutorial is to show you how to create a VGUI HUD for your mod. However, rather than give you all the code to cut and paste, or use complicated timing and reset functions etc. this will show you how to ride your code off the back of the existing HUD. After all, if the code is already there, why redo it? The addition of VGUI weapon selection and flashlight is going to be saved for another tutorial. This tutorial requires either a good knowledge of VGUI, or a good VGUI tutorial.I will be showing you the changes you need to make to the Wavelength series of tutorials ( http://articles.thewavelength.net/298/ http://articles.thewavelength.net/299/ http://articles.thewavelength.net/300/ ) so I recommend you follow through these. The first thing to do is create a basic VGUI panel. This is covered in the first tutorial. However, you do not need to do the server side coding, all our coding will be client side, piggy backing off the existing messages. If you do not have much experience with VGUI, I would recomment you follow the entire first tutorial before going on, as a) You will get a feel for VGUI and how it works for future times b) It will be easier to bug fix if you know the bugs came from either misinterpreting the tutorial, or this one. It is also recommended that you change the name to something a little more intuitive, such as VGUIHud or similar. However, to avoid confusion, I will be referring to them with the same names used in the tutorial. Change the following lines:
| | m_pFirstMenu->setVisible( false ); |
to
| | m_pFirstMenu->setVisible( true ); |
(both occurrences) Now this will set the panel visible as soon as the player spawns. However, do not threat, we will make things invisible later on (just carry on and all will become clear) You will want to change:
| | m_pFirstMenu = new CFirstMenu(100, false, 0, 0, ScreenWidth, ScreenHeight); |
to
| | m_pFirstMenu = new CFirstMenu(255, false, 0, 0, ScreenWidth, ScreenHeight); |
This will make it totally transparent, rather than give the screen a grey tint. If you wish, you can also remove:
| | if ( gEngfuncs.pDemoAPI->IsPlayingback() ) return NULL; |
This means that your HUD WILL show while you are playing back demos :) Before we can make the various elements of the HUD visible and invisible, we need to create them. The method of creation is similar to normal, except for a few elements. I will quickly show you how to create an ammo panel (just the panel and text, you can add the graphics, themes etc. yourself). Find your declaration of CFirstMenu in vgui_TeamFortressViewport.h. To this you need to add a panel that will act as a container for the ammo. This allows us to turn off all elements of the ammo (such as graphics and text) by hiding only the container, all the children of the panel being automatically hidden with it. So add:
| | CTransparentPanel *m_pAmmoContainer; Label *m_pAmmoValue; |
to the PUBLIC declarations. This is very important. Normally these elements only need to be changed by the VGUI system, and so are declared as private. However, we will be editing them all over the place, so we need to declare them as public. (You will also need to add Secondary Ammo, Battery and Health. The weapon selection and flashlight will not be dealt with in this tutorial, but rather saved for another) You then need to add these to your CFirstMenu constructor (CFirstMenu :: CFirstMenu(int iTrans, int iRemoveMe, int x, int y, int wide, int tall) : CMenuPanel(iTrans, iRemoveMe, x,y,wide,tall)):
| | m_pAmmoContainer = new CTransparentPanel( 200, XRES(0), YRES(0), XRES(100), YRES(60)); m_pAmmoContainer->setParent( this ); m_pAmmoContainer->setBorder( new LineBorder( Color(255 * 0.7,170 * 0.7,0,0) ) ); |
I haven't worried about position, size or themes for this, you can find out how to do these from the VGUI tutorials and add them yourself. You then need to add the text:
| | m_pAmmoValue = new Label( "", XRES(1), YRES(1), XRES(98), YRES(58) ); m_pAmmoValue->setParent( m_pAmmoContainer ); m_pAmmoValue->setText( "0" ); |
Again, positioning etc. isn't dealt with here, this just adds it and sets it's parent to the container. Now to set the panel to visible if the HUD is visible. You may or may not know, but the HUD is split up into several elements, such as flashlight, weapon bin, health etc., all of which can be toggled on and off server side (this is how they remove flashlight when zoomed in for example) To provide compatibility, this tutorial will leave this ability in tact. If you look in the draw functions of the elements (they are CHudAmmo::DrawWList(float flTime) in ammo.cpp, int CHudAmmoSecondary :: Draw(float flTime) in ammo_secondary.cpp, int CHudBattery::Draw(float flTime) in battery.cpp, int CHudFlashlight::Draw(float flTime) in flashlight.cpp and int CHudHealth::Draw(float flTime) in health.cpp. I will generally only refer to one of these functions when I am explaining the code to add, but unless otherwise specified, you should apply the same or similar code to all of the functions) you will see code similar to:
| | if ( (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) ) return 1; |
This returns before the draw function is reached, so that element won't be drawn. However, our drawing is handled by the VGUI code, so instead we shall simply turn the relevant panel off. Change the code to:
| | if ( (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) ) { gViewPort->m_pFirstMenu->m_pAmmoContainer->setVisible( false ); return 1; } |
Within int CHudAmmo::Draw(float flTime) you will also want to do a similar thing for:
| | if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) return 1; |
This will set the ammo panel to invisible if this element shouldn't be shown. You then want to set it visible if it should be shown, and isn't already visible. This can be done by:
| | if (!gViewPort->m_pFirstMenu->m_pAmmoContainer->isVisible()) gViewPort->m_pFirstMenu->m_pAmmoContainer->setVisible( true ); |
Now that we have the elements, and they become visible when appropriate, we need them to update. Again, we will piggy back off the existing functions and do this within the Draw functions (obviously after the code to check if it should be visible or not) I will not go through the exact details of how to code each element exactly here, after all the existing functions are there for you to look at. What I will show you is quickly how to set the value of the text once you have established what it should be:
| | char temp[128]; sprintf (temp, "%i", value); gViewPort->m_pFirstMenu->m_pElementValue->setText(temp); |
The value would be replaced with the int (or if it is a float, replace %i with %f) and m_pElementValue with the name of the relevant Label. This will now change the code to the relevant number. Simple huh? :) The final thing for this tutorial is dealing with the problem that if the HideVGUIMenu is called, as this will close our HUD if it is the top menu, which isn't very helpful. The way to get round it is to add a boolean to Panels, shouldClose. Open up VGUI_Panal.h in utils/vgui/include and add this line to the public declarations:
| | bool shouldClose() {return true;}; |
Find your declaration of CFirstMenu in vgui_TeamFortressViewport.h and add:
| | bool shouldClose() {return false;}; |
To the public decelerations. Now find void TeamFortressViewport::HideTopMenu() in vgui_TeamFortressViewport.cpp and change:
to
| | if (m_pCurrentMenu->shouldClose()) m_pCurrentMenu->Close(); |
Now it will never close your HUD :) I hope this has given you some insight into how to create a simple VGUI HUD. I am currently working on a tutorial for the weapon bin and flashlight, but don't be afraid to try it for yourself. |
|