Welcome, Guest! Login | Register

3 State Zoom For Any Weapon [Print this Article]
Posted by: drnelson
Date posted: Jan 25 2005
User Rating: 4.5 out of 5.0
Number of views: 10356
Number of comments: 4
Description: I missed the zooming feature of the 357 that was in HL1 so I thought as a beginner tutorial I'd write a weapon zooming lesson. I then carried it out to a 3-stage zoom. This is for beginners and anyone curious as to my methods.
About Me:
I, like many others, am also new to the Half-Life 2 SDK scene. I did a lot of playing around in Half-Life's SDK's but this seems to be a whole new world. This article reflects what I have learned and are not the words of a Valve certified programmer. So if there are any issues please let me know right away and I will fix them as soon as possible. However, on that same note. I have tested this tutorial several times and it does work. So thanks for reading and I hope you enjoy it. -- David Nelson


About this Article:
This article is mainly for beginners. I have taken what I have learned from the crossbow and applied it towards the 357. I then created a 3 stage zooming feature. The method I use for the zoom keeps the option of a secondary attack open and a zoom key is easy to implement. (More on this later) This method can be applied to any weapon that doesn't have a secondary fire action with ease. Whenever I modify a file I add a little comment tag: // MOD so I can look back at all the files I modified by just doing a CTRL+SHIFT F and searching for MOD in my files. I hope this clears up any weird comments you will see in my code.

How the Zoom Works
It is always important to know how something works before you implement it. So to start off I suggest opening basecombatweapon_shared.cpp (in server (hl->source files)) and hit CTRL-F and search for
 CODE  
CBaseCombatWeapon::ItemPreFrame


CBaseCombatWeapon is the base class that our weapons are derived from. The function's ItemPreframe(), ItemPostFrame(), ItemHolsteredFrame() are very important to us because the game calls these functions once every frame. If we check if the secondary attack key was pressed during these times we can achieve a smooth, quick, and reliable zooming function.

For more information about the CBaseCombatWeapon I suggest reading Josiwe's excellent article: An Exploration Of Weapon_RPG: Part 1A

I mentioned the above because for the 357 we will be adding those functions to our code. Other weapons already use some of these functions but the 357 does not. What we are actually doing is overriding the base classes functions and then calling those base functions after our code. (If you're confused just ignore all this)

So the basic idea is that when the functions are called after, before, or in between frames we will check to see if the player pressed the +attack2 key. If he did we will enter into our zoom function. It will check to see if we are already zoomed in. If we are and we are not zoomed in all the way, then we will zoom in all the way. If we are already zoomed in all the way we will go back to the normal view. (We are actually changing the players Field Of View or FOV for short. After this is implemented we need to be careful that we have some method to reset the view back to normal. To do this we will implement a function to reset the FOV when we holster (switch or run out of ammo) the firearm. This will stop the FOV from staying permantly zoomed in.


Implementation
First we need to open weapon_357.cpp which is located in: HL Server Code - Source Files - HL2 DLL and set your cursor under the #includes

We then add the following lines:
 CODE (C++) 

#define NEXT_ZOOM_TIME  0.2f  // Next possible zoom :MOD
#define ZOOM_STATE_NORMAL   0      // No Zoom
#define ZOOM_STATE_2X   1      // first zoom
#define ZOOM_STATE_4X   2      // last zoom


The first define just declares a time variable of type float that will stop the user from pressing the zoom to quickly.
The next three create the three states of our zoom. Normal is normal FOV, 2X is half the way in, and 4X is the farthest zoom.

Next we go into the Class declaration. Here we need to add some new variables and functions. The function should look like this:
 CODE (C++) 

class CWeapon357 : public CBaseHLCombatWeapon
{
   DECLARE_CLASS( CWeapon357, CBaseHLCombatWeapon );
 public:

   CWeapon357( void );

   void ItemPostFrame( void );  // MOD: Add these three for zoom
   void ItemBusyFrame( void );
   void ItemHolsterFrame( void );

   void PrimaryAttack( void );
   void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );

   DECLARE_SERVERCLASS();
   DECLARE_DATADESC();

 private:  

   void CheckZoom( void ); // Checks our Zoom State

   int  m_iZoomState;      // Holds Zoom State :MOD
   float    m_flNextZoomTime; // Holds Zoom Time
};


The changes are marked with comments. Here we just add our functions that will be called after every frame. We will use these to check our zoom states and reset the FOV. Also we added the CheckZoom() function so we can check our zoom state and change our FOV appropriately.

Now we need to register our variables we created in the macros. (I honestly am not sure if that is what we are doing exactly. But from what I've learned in the SDK we need to do this)
 CODE (C++) 

BEGIN_DATADESC( CWeapon357 )
     DEFINE_FIELD( m_iZoomState, FIELD_INTEGER ), // MOD: added this field
     DEFINE_FIELD( m_flNextZoomTime, FIELD_FLOAT ),  // Also added this field
END_DATADESC()


I hope to learn more about why we have to do that exactly but as of right now I appologize for not knowing. If anyone knows please leave a comment or leave me a message! Thanks!

Now we need to scroll down to the end of the file and add the functions we declared earlier:
 CODE (C++) 

void CWeapon357::ItemBusyFrame( void )
{
   CheckZoom(); // MOD: Check our Zoom States
   
   BaseClass::ItemBusyFrame();
}

// Weapon holstered so set our FOV back to normal
void CWeapon357::ItemHolsterFrame( void )
{
   if (m_iZoomState != ZOOM_STATE_NORMAL) // are we zoomed? :MOD
   {
      CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
   
      m_iZoomState = ZOOM_STATE_NORMAL; // Set our zoom state
      pPlayer->SetFOV(this, 0, 0.1f);  // set our FOV to normal
   }
     
   BaseClass::ItemHolsterFrame();   // Call our base function we derived from's code
}

void CWeapon357::ItemPostFrame( void )
{
   CheckZoom();  // check zoom

   BaseClass::ItemPostFrame();
}


We first implement ItemBusyFrame() so we can change our zoom even when we're reloading.
We then implement ItemHolsterFrame() so that when the gun is switched or holstered the FOV is reset. We first check to see we are even zoomed in before we waste the time fixing the FOV.
Last we add ItemPostFrame() because we want to check and see if the user has pressed the key to zoom.

Now we just need to implement our CheckZoom() Function:
 CODE (C++) 

void CWeapon357::CheckZoom( void )
{
   CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );

   if (pPlayer == NULL)
      return;

   if ( (pPlayer->m_afButtonPressed & IN_ATTACK2) && (gpGlobals->curtime > m_flNextZoomTime) )
   {
      m_flNextZoomTime = gpGlobals->curtime + NEXT_ZOOM_TIME; // set our time up
       
      switch(m_iZoomState)
      {
         case ZOOM_STATE_NORMAL:
            m_iZoomState = ZOOM_STATE_2X;
            pPlayer->SetFOV(this, 20, 0.2f);
            break;

         case ZOOM_STATE_2X:
            m_iZoomState = ZOOM_STATE_4X;
            pPlayer->SetFOV(this, 10, 0.2f);
            break;

         case ZOOM_STATE_4X:
            m_iZoomState = ZOOM_STATE_NORMAL;
            pPlayer->SetFOV(this, 0, 0.2f);
            break;
       
         default:
            break;
      }
   }
}


Here is a line by line explanation of my code above:
First we get a handle to our player object so we can set the FOV. If this fails (the player is dead or some error) the function ends.
Next we check and see if the +attack2 button was pressed (right mouse for most people). If it is we then check to see if the time is greater that the NextZoomTime. We do this so we don't zoom in and out too quickly. Also above I mentioned that it would be easy to transfer this code over to a key instead of the secondary attack. To do this you would just change the & IN_ATTACK2 to look for another key and you are free to setup a secondary attack function and still have a zoom. (Or you could just use valves 'z' key zoom thing. But where's the fun in that?)
Next we set our m_flNextZoomTime to the current time plus our pre-defined time to slow the speed of the zoom change.
We then enter our switch statement. We check the variable: m_iZoomState for 3 cases.
The first case checks to see if we are at ZOOM_STATE_NORMAL. If so it switches the state to ZOOM_STATE_2X and changes the FOV to zoom in a little. (more on the SetFOV func in a second)
If we were already in ZOOM_STATE_2X it puts us in ZOOM_STATE_4X and sets the FOV accordingly. And last, if we are at 4X it switches us back to normal and updates the FOV.

The pPlayer->SetFOV() function has three paramaters:
1.) CBaseEntity *pRequester - which is this in most cases. But it is the object that is requesting the FOV change.
2.) int FOV - the field of view amount we want to change
3.) float zoomRate - the rate of the zoom to occur. A large value here will make the zoom value slowly zoom in. A small value is more of a cutting from one view to the next.

That is our SetFOV function. Easy! That is also all of our modifications.

Conclusion
I hope this helps someone dip their feet in. I did this as an experiment and had a lot of fun playing around with the many options. I plan on writing quite a few easier tutorials for the community unless people request that I don't. =) I do want to mention that this can easily be a copy and paste tutorial. And that's fine if that's what you really want to do. But if that is all you get from any tutorial you spent the time reading you need to start thinking outside the box and try and apply the tutorials to other aspects of the SDK. I hope you have enjoyed this tutorial and I hope it is well receieved. I have checked and double checked this tutorial for errors but something may have slipped past me. If so please let me know right away! Thanks for reading! -- David Nelson

Rate This Article
This article is currently rated: 4.5 out of 5.0 (4 Votes)

You have to register to rate this article.
User Comments Showing comments 1-4

Posted By: drnelson on Feb 02 2005 at 07:42:26
I'd love to see some comments! And possibly rate my article with the rating system? I'm just curious as to what you think of it.

Thanks,
David

Posted By: imperio59 on Feb 04 2005 at 19:58:04
It's a nice tutorial, I thought no one would ever make one of these zooming tutorials again, but it's always a nice read, reminds me of my first adventures with the HL1 SDK ;)

Posted By: kapalkaudi on Feb 20 2005 at 19:41:48
I think that this tutorial is very detailed and well written. Although the code is simple it teaches a lot.

QUOTE:
I plan on writing quite a few easier tutorials for the community unless people request that I don't.


I don't think you need to write an easier tutorial. Every tutorial that is exlpaned like this one is easy

Posted By: Ennuified on Oct 18 2007 at 15:35:46
Awesome stuff, these easy tuts are great for me.


You must register to post a comment. If you have already registered, you must login.

Latest Articles
3rd person View in Multiplayer
Half-Life 2 | Coding | Client Side Tutorials
How to enable it in HL2DM

By: cct | Nov 13 2006

Making a Camera
Half-Life 2 | Level Design
This camera is good for when you join a map, it gives you a view of the map before you join a team

By: slackiller | Mar 05 2006

Making a camera , Part 2
Half-Life 2 | Level Design
these cameras are working monitors that turn on when a button is pushed.

By: slackiller | Mar 04 2006

Storing weapons on ladder
Half-Life 2 | Coding | Snippets
like Raven Sheild or BF2

By: British_Bomber | Dec 24 2005

Implementation of a string lookup table
Half-Life 2 | Coding | Snippets
A string lookup table is a set of functions that is used to convert strings to pre-defined values

By: deathz0rz | Nov 13 2005


Latest Comments
knock knock
General | News
By: MIFUNE | Dec 31 2017
 
knock knock
General | News
By: omega | Dec 22 2016
 
knock knock
General | News
By: MIFUNE | Oct 10 2015
 
New HL HUD Message System
Half-Life | Coding | Shared Tutorials
By: chbrules | Dec 31 2011
 
knock knock
General | News
By: Whistler | Nov 05 2011
 
Particle Engine tutorial part 4
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 18 2010
 
Particle Engine tutorial part 2
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 11 2010
 
Particle Engine tutorial part 3
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 11 2010
 
Game Movement Series #2: Analog Jumping and Floating
Half-Life 2 | Coding | Shared Tutorials
By: mars3554 | Oct 26 2009
 
Particle Engine tutorial part 5
Half-Life | Coding | Client Side Tutorials
By: Deadpool | Aug 02 2009
 

Site Info
297 Approved Articless
8 Pending Articles
3940 Registered Members
0 People Online (3 guests)
About - Credits - Contact Us

Wavelength version: 3.0.0.9
Valid XHTML 1.0! Valid CSS!