Coding a Basic Leaning System

Tutorial collection, comprehensive listings on main site.

Coding a Basic Leaning System

Postby Tutorial on Wed Jun 10, 2009 11:11 am

category
Miscellaneous

description
This is a basic tutorial on how to code a leaning system.

keywords
coding, lean, leaning system, leaning.

This is for single player mods but can easily be put into use for multi-player mods.

First things first we need to create two new buttons one for leaning left and one for leaning right. So open up in_buttons.h.

If you know how to create a button skip this part.

Now you should see a bunch of button definitions for example.
Code: Select all
#define IN_GRENADE2      (1 << 24)   // grenade 2

Ok so now we want to add our new buttons. After the last button definition add
Code: Select all
#define IN_LEANLEFT      (1 << 25)   //Lean left
#define IN_LEANRIGHT   (1 << 26)   //Lean right

Now the (1 << 25 ) and (1 << 26) should be one higher than the next one. By default the last buttons defined is IN_GRENADE2 which is (1 << 25). So when I added IN_LEANLEFT I put (1 << 25) as 25 is one higher than 24.

Ok now we need to open in_main.cpp

On about line 103 you should see some kbutton_t classes being defined. We need to add our buttons to this section of code.

So After
Code: Select all
static  kbutton_t   in_grenade2;

Add
Code: Select all
static  kbutton_t   in_leanleft;
static  kbutton_t   in_leanright;


So we have now defined our two buttons. Now we need to create a function for when the button is pressed and when it is released.

So scroll down to around line 468 and you should see aload of functions similar to theese.
Code: Select all
void IN_Grenade2Up( const CCommand &args ) { KeyUp( &in_grenade2, args[1] ); }
void IN_Grenade2Down( const CCommand &args ) { KeyDown( &in_grenade2, args[1] ); }


Now we are going to create 4 four new functions after these two. Two for each button. One to handle when the button is pressed and one to handle when the buttons is released.

Add
Code: Select all
void IN_LeanLeftDown( const CCommand &args ) { KeyDown( &in_leanleft, args[1] ); }
void IN_LeanLeftUp( const CCommand &args ) { KeyUp( &in_leanleft, args[1] ); }
void IN_LeanRightDown( const CCommand &args ) {KeyDown(&in_leanright, args[1] ); }
void IN_LeanRightUp( const CCommand &args ) {KeyUp(&in_leanright, args[1] ); }


Now you may be wondering what this code all does it is quite simple really.
We are creating a new function and parsing it a CCommand which points to args. Then inside of that function we call the KeyUp or KeyDown function and parse that a pointer to the kbutton_t that we created earlier. We are also parsing it the args with the value 1.

Now as c++ doesn't count white space this could also be written as
Code: Select all
void IN_LeanRightUp( const CCommand &args )
{
KeyUp(&in_leanright, args[1] );
 }

This shows the structure of the code in a more text-book manner.

So now we need to scroll all the way down to line 1308.

You should now see some code that looks like this.
Code: Select all
CalcButtonBits( bits, IN_GRENADE2, s_ClearInputState, &in_grenade2, bResetState );

So below this add
Code: Select all
CalcButtonBits( bits, IN_LEANLEFT, s_ClearInputState, &in_leanleft, bResetState );
   CalcButtonBits( bits, IN_LEANRIGHT, s_ClearInputState, &in_leanright, bResetState );

Right so this code calls the CalcButtonBits function and parses it a integer called bits, we then parse this function out button we defined inside in_buttons.h, then we parse it a variable that is defined earlier in this file, then we parse it a pointer to our kbutton_t that we defined earlier. then finally we parse a integer called bResetState.
Now if we look at the function this is all contained within.
Code: Select all
int CInput::GetButtonBits( int bResetState )
{
   int bits = 0;

you can see the bResetState is parsed into the main function.

Ok with that all done we have now created a button and this next little part is optional but it can be quite useful.

We are now going to created ConCommand that press our and release out button. A ConCommand is a console command in case you didn't know.

Ok scroll down to line 1464 and you should see
Code: Select all
static ConCommand endgrenade2( "-grenade2", IN_Grenade2Up );
static ConCommand startgrenade2( "+grenade2", IN_Grenade2Down );

Now we are going to create some of our own.
Add this below
Code: Select all
static ConCommand startleanleft( "+leanleft", IN_LeanLeftDown );
static ConCommand endleanleft( "-leanleft", IN_LeanLeftUp );
static ConCommand startleanright( "+leanright", IN_LeanRightDown );
static ConCommand endleanright( "-leanright", IN_LeanRightUp );

So what we have done their is create our console commands. Now we parsed the ConCommand a string which is what you type into the console to activate this command, then we parse it our void we created earlier.

If you want to add your button to the keyboard section of the options menu gui. It is quite simple.
Open kb_act.lst (inside the scripts folder of your mod directory) and add
Code: Select all
"+leanleft"            "Lean Left"
"+leanright"         "Lean Right"

Under the section you want them to be listed.

Now we have finished everything to do with button creation. We can move onto creating our lean functionality. I've decided to place my code inside the hl2_player.cpp and hl2_player.h file. The code can be adapted to be put inside of gamemovement.cpp and .h if need be.

First off open hl2_player.h and scroll down to about line 297 this is just above the protected section of the class definition.

Now we need to define our function and variables.
So add
Code: Select all
//New Leaning stuff
   void CheckLean();
   void StartLeaning();
   void StopLeaning();
   bool IsLeaning(){return m_bIsLeaning;}

Now if we were to compile now we would get an error because m_bIsLeaning isn't defined yet. We are going to define that now.

Scroll down into the protected section of the class and add.
Code: Select all
   //New Leaning stuff
   bool            m_bIsLeaning;


Ok now open up hl2_player.cpp and scroll all the way down to line 3771 this should be after the FirePlayerProxyOutput function. This is where we are going to add our code. It doesn't matter were we add it really but I like this position as it is after all the stock coder for the class CHL2_Player.

First we are going to add the checklean code so add
Code: Select all
void CHL2_Player::CheckLean()
{
   if(IsSuitEquipped())
      {
         if(m_afButtonPressed & IN_LEANLEFT)
            StartLeaning();
         else if(m_afButtonPressed & IN_LEANRIGHT)
            StartLeaning();
         else if (m_afButtonReleased & IN_LEANLEFT)
            StopLeaning();
         else if (m_afButtonReleased & IN_LEANRIGHT)
            StopLeaning();
      }
   else
      return;
}

Ok what this code does is quite simple, first it check if the player has a suit equipped and if not it returns. If the player does have a suit equipped it checks if the Leanleft button is pressed and if so it calls the leaning function, it then does the same thing for the LeanRight button. Then if none of the buttons are pressed it checks if the buttons has just been released and if so it calls the StopLeaning function.

After this function we are going to add our start leaning function so add
Code: Select all
void CHL2_Player::StartLeaning()
{
   if(IsSprinting())
      StopSprinting();

   if(IsZooming())
      StopZooming();

   //Create new vectors
   Vector lean,currentoffset,newoffset;
   currentoffset = GetViewOffset();
   AngleVectors(EyeAngles(), NULL, &lean, NULL);
   newoffset = currentoffset;
   if(m_nButtons & IN_LEANLEFT)
   {
      lean *= -25;
      newoffset.x = clamp(lean.x, -40, 40);
      newoffset.y = clamp(lean.y, -40, 40);
      SetViewOffset( newoffset );
   }
   else if(m_nButtons & IN_LEANRIGHT)
   {
      lean *= 25;
      newoffset.x = clamp(lean.x, -40, 40);
      newoffset.y = clamp(lean.y, -40, 40);
      SetViewOffset( newoffset );
   }
   m_bIsLeaning = true;
}

Now this code is slightly more complicated so I will try my best to explain it. At first we check if we are sprint and if so we stop the player sprinting, we then check to see if we are zooming and if so we stop the player from zooming.

We then go ahead and create three new vectors called lean, currentoffset and newoffset. We then set currentoffset to equal the current view offset by calling the GetViewOffset function.

We then call a math function that get the vectors of an QAngle class and assigns them to defined vectors. The QAngle class we want to get our vectors from is returned from the EyeAngles function so we call that. We then only want to get the right vector so we call a NULL for the forward and Up vectors. But we parse the lean vector for right (side) vector.

Now we set the newoffset to equal the currentoffset. Then we check if the IN_LeanLeft buttons is pressed down and if it is we will times the lean vector (which goes right) by -10. We times by minus ten to make it go left instead of right. We then add the lean vector to the newoffset but also clamp the vector in both the X and Y direction. We only allow it to go between -40 and 40 for both axis. We then set the viewoffset to equal our new offset.

Next we do the same but for the right side therefore this time we times by ten to move it to the right.

After all these if statements we set our bool valve to equal true because we are leaning.

So now we need to add code to our StopLeaning function so after the StartLeaning function add
Code: Select all
void CHL2_Player::StopLeaning()
{
   if (IsDucking())
      SetViewOffset( VEC_DUCK_VIEW );

   else
      SetViewOffset( VEC_VIEW );

   m_bIsLeaning = false;
}


This code if far simpler, basically we check if the player is ducking and if so we set the view offset to a predefined offset that equates to ducking. If we aren't ducking we set our view offset to equal the standard view offset.

So yeah now we got leaning right?
Well no not just yet.

We basically need to call our check lean function each frame to see if we need to lean. So do a find (Ctrl + F) for ItemPostFrame this should take you to a function that is called after each frame. So inside this function call CheckLean.
Code: Select all
void CHL2_Player::ItemPostFrame()
{
   BaseClass::ItemPostFrame();

   if ( m_bPlayUseDenySound )
   {
      m_bPlayUseDenySound = false;
      EmitSound( "HL2Player.UseDeny" );
   }

   CheckLean();

   if(IsLeaning())
      Weapon_Lower();
}

Now you can see I added it after the EmitSound call.
Also I gave a use for the IsLeaning bool we created earlier. Basically I added a check to see if we are leaning and if so I decided to lower the players weapon.

So more use for the IsLeaning bool include.
In the CanSprint function you can add
Code: Select all
&& !IsLeaning()

Inside the if statement to stop the player from sprinting while they are leaning.

Also Inside the CanZoom function I added
Code: Select all
//If leaning don't
   if (IsLeaning())
      return false;

To stop the player from zooming while leaning.

Because I defined the bool IsLeaning() in the public section of the class you can use it pretty much anywhere/ any file.

Notes: This is just basic leaning you will probably want to add screen rotation as well.
you can also network the m_bIsleaning bool so you can use it on the client side.
If you see any errors please let me know I will try to fix them.

Sorry forgot to mention to increase the distance increase the clamp value and increase the value you time the lean vector by.

Right here is a video of it working in-game (I had quite low values on at his point which I edited later and put into the tutorial.



-Surfa
- Don't send PM's to this user -
Tutorial
Not A Real User
 
Joined: Sun Mar 06, 2005 11:00 pm

Re: Coding a Basic Leaning System

Postby mky on Thu Jun 11, 2009 10:46 pm

Hahaha I thought it said "Basic Learning System". Needless to say I freaked.
User avatar
mky
Been Here A While
Been Here A While
 
Joined: Sat Sep 06, 2008 12:35 am
Location: texas

Re: Coding a Basic Leaning System

Postby Surfa on Fri Jun 12, 2009 3:57 pm

I had the same problem when writing the code countless errors because I wrote IN_LearnLeft of something similar by accident.
Surfa
May Contain Skills
May Contain Skills
 
Joined: Sun Dec 30, 2007 3:04 pm

Re: Coding a Basic Leaning System

Postby FeareD on Wed Jul 08, 2009 9:27 pm

Thanks works like a charm. There are only a few steps to get it working on multiplayer which I did.
By the way you may want to add rolling about -45/45.
I know I will be.

I was just about to code my own leaning system but then I saw this... :D Thanks again

::FeareD
FeareD
Member
Member
 
Joined: Sun May 17, 2009 3:05 am

Re: Coding a Basic Leaning System

Postby Surfa on Fri Jul 10, 2009 10:29 pm

Yeah I may go a head a re-write this for multiplayer as it kinda allows cheating in some sense if you set the values fairly high. Also yeah I will add something about adding camera roll.
Surfa
May Contain Skills
May Contain Skills
 
Joined: Sun Dec 30, 2007 3:04 pm

Re: Coding a Basic Leaning System

Postby FeareD on Sat Jul 11, 2009 4:06 am

Well to stop the cheating send a traceline out and if it's to close to a wall it stops before it goes through it.

::FeareD
FeareD
Member
Member
 
Joined: Sun May 17, 2009 3:05 am

Re: Coding a Basic Leaning System

Postby Surfa on Sat Jul 11, 2009 2:06 pm

As well as the fact that we aren't animating the player model and hence you would be able to stand behind the wall and not be shot but be able to shoot people that are round the corner.
Surfa
May Contain Skills
May Contain Skills
 
Joined: Sun Dec 30, 2007 3:04 pm

Re: Coding a Basic Leaning System

Postby RedQueensAce on Thu Nov 05, 2009 7:37 pm

FeareD, do you mind posting what steps it takes to bring this code into multiplayer?
RedQueensAce
Just Joined
Just Joined
 
Joined: Thu Nov 05, 2009 7:35 pm

Re: Coding a Basic Leaning System

Postby Surfa on Thu Nov 05, 2009 9:22 pm

Honestly I should re-do this tutorial it was mainly just a collection of some code I found on chat bear that I edit to suit my needs. Also I wouldn't recommend doing this way for multiplayer unless you make a few corrections to the code. I may re-write it at some point with multiplayer as the main focus.
Surfa
May Contain Skills
May Contain Skills
 
Joined: Sun Dec 30, 2007 3:04 pm

Re: Coding a Basic Leaning System

Postby Terr on Thu Nov 05, 2009 9:43 pm

I'd talk to the guys working on Neotokyo, as they're probably working on related code right now, since some players have complained that left-leaning (due to model stance discrepancies) allows people to shoot without being seen.
Terr
Sir Post-a-lot
Sir Post-a-lot
 
Joined: Mon Oct 12, 2009 11:35 pm

Re: Coding a Basic Leaning System

Postby Increazon on Mon Mar 08, 2010 2:46 pm

Why the video deleted?
Increazon
Dumpling
Dumpling
 
Joined: Sun Mar 07, 2010 4:41 pm

Re: Coding a Basic Leaning System

Postby Sapphon on Sun Nov 14, 2010 12:23 am

Great tutorial, very helpful. Thanks a lot. It may seem stupid, but Valve's documentation lacks even simple things like "how to add a field to the ingame options menu button mapping".
Sapphon
Dumpling
Dumpling
 
Joined: Mon Oct 04, 2010 3:57 pm

Re: Coding a Basic Leaning System

Postby Bearded Dwarf on Mon Feb 20, 2012 7:24 pm

I'm getting an error:
Code: Select all
1>------ Build started: Project: Client Episodic, Configuration: Release Win32 ------
1>  in_main.cpp
1>in_main.cpp(469): error C2660: 'KeyDown' : function does not take 1 arguments
1>in_main.cpp(470): error C2660: 'KeyUp' : function does not take 1 arguments
1>in_main.cpp(471): error C2660: 'KeyDown' : function does not take 1 arguments
1>in_main.cpp(472): error C2660: 'KeyUp' : function does not take 1 arguments
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Can anyone help me? I'm a complete noob when it comes to coding...
Anyways, great tutorial!
Bearded Dwarf
Just Joined
Just Joined
 
Joined: Mon Feb 20, 2012 7:19 pm

Re: Coding a Basic Leaning System

Postby LordDz on Mon Feb 20, 2012 8:41 pm

It says itself in the code, you're trying to call a function and you're just sending 1 argument (variable) to it, look at the function and when you call it, send the variables to it.
User avatar
LordDz
May Contain Skills
May Contain Skills
 
Joined: Mon Sep 01, 2008 12:28 pm
Location: Hammer Crash Logs

Return to Tutorials

Who is online

Users browsing this forum: No registered users