Welcome, Guest! Login | Register

Game Movement Series #1: Wall jumping [Print this Article]
Posted by: ibutsu
Date posted: Dec 07 2004
User Rating: 5 out of 5.0
Number of views: 17972
Number of comments: 21
Description: How to setup wall jumping in half-life 2
Special thanks to X-0ut, omega and Entropy for their half-life 1 wall jumping tutorial which forms the basis for this tutorial.

Well hello there folks, today I am going to show you how to implement wall jumping in the half-life 2 sdk skeleton mod.
Ths tutorial is fairly simple, although a bit code heavy because we need to override the default jump code and just like X-0ut, I will only be showing you side-to-side wall jumping.

First things first, open up sdk_gamemovement.cpp and scroll down to the definition of CSDKGameMovement, it should look similar to this:
 CODE (C++) 

class CSDKGameMovement : public CGameMovement
{
public:
    DECLARE_CLASS( CSDKGameMovement, CGameMovement );

    CSDKGameMovement();
};


We will need to override the CheckJumpButton() function for this, so add the following function declaration into the class definition, below the constructor:

 CODE (C++) 

// Override default jump behavior
bool CheckJumpButton();


Okay, excellent! Now we have to add the definition for CheckJumpButton(), the majority of the code here is pulled straight from the standard jump code, I've stripped out the parts that related strictly to the half-life 2 dll. Insert this code below the definition of the constructor:

 CODE (C++) 

bool CSDKGameMovement::CheckJumpButton()
{
    if (player->pl.deadflag) // is the player dead?
    {
        mv->m_nOldButtons |= IN_JUMP ;   // don't jump again until released
        return false;
    }

    // See if we are waterjumping.  If so, decrement count and return.
    if (player->m_flWaterJumpTime)
    {
        player->m_flWaterJumpTime -= gpGlobals->frametime;
        if (player->m_flWaterJumpTime < 0)
            player->m_flWaterJumpTime = 0;

        return false;
    }

    // If we are in the water most of the way...
    if ( player->GetWaterLevel() >= 2 )
    {  
        // swimming, not jumping
        SetGroundEntity( (CBaseEntity *)NULL );

        if(player->GetWaterType() == CONTENTS_WATER)    // We move up a certain amount
            mv->m_vecVelocity[2] = 100;
        else if (player->GetWaterType() == CONTENTS_SLIME)
            mv->m_vecVelocity[2] = 80;

        // play swiming sound
        if ( player->m_flSwimSoundTime <= 0 )
        {
            // Don't play sound again for 1 second
            player->m_flSwimSoundTime = 1000;
            PlaySwimSound();
        }

        return false;
    }

    // Don't allow jumping when the player is in a stasis field.
    if ( player->m_Local.m_bSlowMovement )
        return false;

    if ( mv->m_nOldButtons & IN_JUMP )
        return false;       // don't pogo stick

    // Cannot jump will in the unduck transition.
    if ( player->m_Local.m_bDucking && (  player->GetFlags() & FL_DUCKING ) )
        return false;

    // Still updating the eye position.
    if ( player->m_Local.m_flDuckJumpTime > 0.0f )
        return false;

    float startz = 0.0f;
    float starty = 0.0f;
    float startx = 0.0f;

    float flMul;

    // This controls how high you jump
    if ( g_bMovementOptimizations )
    {
        Assert( sv_gravity.GetFloat() == 800.0f );
        flMul = 268.3281572999747f;
    }
    else
    {
        flMul = sqrt(2 * sv_gravity.GetFloat() * GAMEMOVEMENT_JUMP_HEIGHT); // 183.303028
    }

    // If we are not on the ground....
    if (player->GetGroundEntity() == NULL)
    {
        int i = 0;
        Vector EndPoint;
        trace_t tr;

        EndPoint[2] = player->GetAbsOrigin()[2];    // set the z value of the trace endpoint to the player z value

        // Store the original velocity
        startx = mv->m_vecVelocity[0];
        starty = mv->m_vecVelocity[1];
        startz = mv->m_vecVelocity[2];

        if( mv->m_nButtons & IN_MOVERIGHT )
        {
            // setup the trace end point as 24 units to the left of the player
            for(i = 0; i < 2; i++)
                EndPoint[i] = player->GetAbsOrigin()[i] + m_vecRight[i] * -24.0f;

            UTIL_TraceLine( player->GetAbsOrigin(), EndPoint, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr);
           
            if( tr.fraction < 1.0 )  // if there was a wall
            {
                for(i = 0; i < 2; i++)
                    mv->m_vecVelocity[i] = m_vecRight[i] * 275 * 1.1;

                mv->m_vecVelocity[2] += flMul;    // Jump!
            }
            else
            {
                // no wall found, do nothing
                mv->m_nOldButtons |= IN_JUMP;
                return false;
            }
        }
        else if( mv->m_nButtons & IN_MOVELEFT )
        {
            for(i = 0; i < 2; i++)  // setup the trace end point as 24 units to the right of the player
                EndPoint[i] = player->GetAbsOrigin()[i] + m_vecRight[i] * 24.0f;

            UTIL_TraceLine( player->GetAbsOrigin(), EndPoint, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr);

            if( tr.fraction < 1.0 )  // if there was a wall
            {
                for(i = 0; i < 2; i++)
                    mv->m_vecVelocity[i] = m_vecRight[i] * -275 * 1.1;

                mv->m_vecVelocity[2] += flMul;    // Jump!
            }
            else
            {
                // No wall found, do nothing
                mv->m_nOldButtons |= IN_JUMP;
                return false;
            }
        }
    }
    else   // We are on the ground, so jump normally
    {
        // In the air now.
        SetGroundEntity( (CBaseEntity *)NULL );

        player->PlayStepSound( mv->m_vecAbsOrigin, m_pSurfaceData, 1.0, true );

        MoveHelper()->PlayerSetAnimation( PLAYER_JUMP );

        float flGroundFactor = 1.0f;

        if (m_pSurfaceData)
        {
            flGroundFactor = m_pSurfaceData->game.jumpFactor;
        }

        // Acclerate upward
        // If we are ducking...
        startz = mv->m_vecVelocity[2];
        if ( (  player->m_Local.m_bDucking ) || (  player->GetFlags() & FL_DUCKING ) )
        {
            mv->m_vecVelocity[2] = flGroundFactor * flMul;
        }
        else
        {
            mv->m_vecVelocity[2] += flGroundFactor * flMul;
        }
    }

    FinishGravity();

    // I'm really not sure what these affect
    mv->m_outJumpVel.x += mv->m_vecVelocity[0] - startx;
    mv->m_outJumpVel.y += mv->m_vecVelocity[1] - starty;
    mv->m_outJumpVel.z += mv->m_vecVelocity[2] - startz;

    mv->m_outStepHeight += 0.15f;

    // Set jump time.
    if ( gpGlobals->maxClients == 1 )
    {
        player->m_Local.m_flJumpTime = GAMEMOVEMENT_JUMP_TIME;
        player->m_Local.m_bInDuckJump = true;
    }

    // Flag that we jumped.
    mv->m_nOldButtons |= IN_JUMP;    // don't jump again until released
    return true;
}


Well, isn't that quite the chunk of code? :) Like I said before, the majority of that code is from the default jump code, the code we're interested lies after this line:

 CODE (C++) 

// If we are not on the ground....
if (player->GetGroundEntity() == NULL)


The code from this point and on accomplishes the following things:

1) First we test if we are in the air or not, if we are not we jump normally
2) If we are in the air, we test if we are pressing jump and strafe left or right
3) If we are pressing either of those combinations, we test if there is a wall 24 units to the left of us if we wish to jump right, or 24 units to the right of us if we wish to jump left (I chose 24 units because I found 16, which X-0ut used, made it much too easy to miss the jump if you are facing too far away or too close to the wall)
4) If there is a wall and we are not trying to wall jump into it, we will now jump out from the wall :)

There! Now, we know what that giant block of code does, but if we try to compile it, we get an error about attempting to access a private member of CBasePlayer and one about g_bMovementOptimizations being undeclared! Well, don't get too worried, this is simple to fix!

In sdk_gamemovement.cpp on about line 45 you should see this line of code:

 CODE (C++) 

EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CGameMovement, IGameMovement,INTERFACENAME_GAMEMOVEMENT, g_GameMovement );


Below that line add this line:

 CODE (C++) 

extern bool g_bMovementOptimizations;


Next open up c_baseplayer.h and scroll down to line 401, it should look similar to this:

 CODE (C++) 

// HACK FOR TF2 Prediction
friend class CTFGameMovementRecon;
friend class CGameMovement;
friend class CTFGameMovement;
friend class CHL1GameMovement;
friend class CCSGameMovement;
friend class CHL2GameMovement;


and add this line to the end of the list:

 CODE (C++) 

friend class CSDKGameMovement;


Next, open player.h and scroll down to line 792 where you should see the same code as in the last step, add the friend declaration to the end of this list as well.

Now save, compile and get ready to get wall jumping!

Rate This Article
This article is currently rated: 5 out of 5.0 (1 Votes)

You have to register to rate this article.
User Comments
prev ( [1] 2 ) next Showing comments 1-20


Posted By: Critical_Impact on Dec 08 2004 at 02:06:38
What is wall jumping?

Posted By: ibutsu on Dec 08 2004 at 06:28:41
jumping off of walls while in the air

Posted By: hopper on Dec 15 2004 at 22:00:16
You can clean this up a bit like this:

float traceForeAmt = 32.0f;
float traceRightAmt = traceForeAmt;
float jumpForeAmt = 400.0f;
float jumpRightAmt = jumpForeAmt;

if(mv->m_nButtons & IN_MOVERIGHT)
{
traceRightAmt = -traceRightAmt;
}
else if( mv->m_nButtons & IN_MOVELEFT)
{
jumpRightAmt = -jumpRightAmt;
}
else
{
traceRightAmt = 0;
jumpRightAmt = 0;
}

if( mv->m_nButtons & IN_FORWARD)
{}
else if( mv->m_nButtons & IN_BACK)
{
traceForeAmt = 0;
jumpForeAmt = 0;
}
else
{
traceForeAmt = 0;
jumpForeAmt = 0;
}


and then you can do this...

for(i = 0; i < 2; i++)
{
EndPoint[i] = player->GetAbsOrigin()[i]
+ m_vecForward[i] * traceForeAmt
+ m_vecRight[i] * traceRightAmt;
}

and...

for(i = 0; i < 2; i++)
{
mv->m_vecVelocity[i] = m_vecRight[i] * jumpRightAmt + m_vecForward[i] * jumpForeAmt;
}

Then you only need to have the wall check/jump code written out once instead of once for each direction you could be wall jumping. This code is written so you can climb walls when you're facing them or jump off them left/right/diag.

-Hopper
www.mind-body-power.netEdited by hopper on Dec 23 2004, 03:33:51

Posted By: ibutsu on Dec 20 2004 at 16:46:44
Wow, thanks for the contribution, hopper! I'll edit the article and add your name to the special thanks list :)

Posted By: SoUlFaThEr on Dec 24 2004 at 16:40:32
ibutsu i send you a PM about 2 weeks ago...do you check those or do you ignore?

Posted By: eddie on Jan 05 2005 at 01:21:42
I am new to all of this, could you maybe explain why we added:

extern bool g_bMovementOptimizations;

I thought the tutorial was very good, but you said to add that line, but didn't really explain why, the answer could be obvious, but again i am new to all this.

Also, Where at in the CheckJumpButton function does hopper's code begin and end?Edited by eddie on Jan 05 2005, 01:22:18

Posted By: hopper on Jan 08 2005 at 18:36:41
Valve has a global boolean in the base game movement file that is used in teh code to determine whether to use a hardcoded value for how high to jump or to use a formula to determine it more realistically.

if ( g_bMovementOptimizations )
{
Assert( sv_gravity.GetFloat() == 800.0f );
flMul = 268.3281572999747f;
}
else
{
flMul = sqrt(2 * sv_gravity.GetFloat() * GAMEMOVEMENT_JUMP_HEIGHT); // 183.303028
}

Valve had that boolean set to false for the sdk, so you dont really NEED it. You can just always make flMul = 268.

(and)
this is how my code is in my mod. this should give you an idea of where it should go

// Store the original velocity
startx = mv->m_vecVelocity[0];
starty = mv->m_vecVelocity[1];
startz = mv->m_vecVelocity[2];

float traceForeAmt = Params()->Move->BODY_JUMPCHECK;
float traceRightAmt = traceForeAmt;
float jumpForeAmt = Params()->Move->BODY_DOUBLEJUMPVEL;
float jumpRightAmt = jumpForeAmt;

if(mv->m_nButtons & IN_MOVERIGHT)
{
m_iNumJumps--;
traceRightAmt = -traceRightAmt;

}
else if( mv->m_nButtons & IN_MOVELEFT)
{
m_iNumJumps--;
jumpRightAmt = -jumpRightAmt;
}
else
{
traceRightAmt = 0;
jumpRightAmt = 0;
}

if( mv->m_nButtons & IN_FORWARD)
{}
else if( mv->m_nButtons & IN_BACK)
{
traceForeAmt = 0;
jumpForeAmt = 0;
}
else
{
traceForeAmt = 0;
jumpForeAmt = 0;
}

for(i = 0; i < 2; i++)
{
EndPoint[i] = player->GetAbsOrigin()[i]
+ m_vecForward[i] * traceForeAmt
+ m_vecRight[i] * traceRightAmt;
}

UTIL_TraceLine( player->GetAbsOrigin(), EndPoint, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr);

if( tr.fraction < 1.0 ) // if there was a wall
{
for(i = 0; i < 2; i++)
mv->m_vecVelocity[i] = m_vecRight[i] * jumpRightAmt + m_vecForward[i] * jumpForeAmt;

mv->m_vecVelocity[2] += Params()->Move->BODY_DOUBLEJUMP*flGroundFactor; // Jump!
}
else
{
// No wall found, do nothing
mv->m_nOldButtons |= IN_JUMP;
return false;
}


hope this helps

Posted By: hopper on Jan 09 2005 at 00:15:09
btw, unless you add some special handling, this code will allow you to jump up walls also. The way I deal with this is by limiting the number of wall jumps that are allowed when going up a wall.

Posted By: eddie on Jan 09 2005 at 05:40:11
great explanation hopper, That was very very helpful, i appreciate it.

Posted By: Metal on Jan 14 2005 at 21:03:19
Hey, hopefully someone can help me out with this, I've implemented walljumping in my MOD...however it's not working correctly. It will jump off a wall to the left but then it just snaps me right back to the wall. I've been trying everything I can think of to fix this problem but to be quite honest I'm not even sure what's causing it. I've even taken the default jump code and rewritten in a doublejump from scratch to see if I could get that working but it had the same result. I'm using ms vc++ 6 if that makes any difference, I've followed the tut step by step, checked over it, tried hopper's way, and like i said started from scratch every method has the same result. Plz any help if possible would be great!

*A very good tutorial, hope for more of them*Edited by Metal on Jan 14 2005, 21:03:53

Posted By: hopper on Feb 05 2005 at 16:47:42
By double jumping you mean like metroid prime double jumping? Jump, then jump again in mid air? Does double jumping just pull you down to wall?

Maybe its the collision bug that never seems to really get fixed in the sdk. Are they flat surfaces that you are jumping off of? or are they irregular? And are they static props?

Also, check to make sure that whatever you are doing is happening on both the server and the client side. Make sure you dont have like a "#ifdef client.dll" statement or anything around the whole thing.

Posted By: jediborg on Feb 07 2005 at 03:51:21
This Wall-jumping tutorial leaves many questions to be answered,
if you have to be in the air to wall-jump, does that mean you have to jump next to a wall, then strafe left/right and hit the jump button again?

does this code allow for multiple wall jumping (I.E. jumping multiple times between two walls to "climb" up two walls and reach a great height(kinda like in prince of persia, or metroid?)

i implemented this code into the gamemovement.cpp file instead of the sdk_gamemovement.cpp because we're making a single-player mod, not a multiplayer one. so far, all this code allows me to do is jump away from a wall and up a great distance

what buttons, exactly, do you have to press to "wall jump"?

Posted By: jediborg on Feb 07 2005 at 04:13:53
also, what exactly is "pogo jumping?" i've deleted the code that disables it, and i can't see any difference

Posted By: hopper on Feb 10 2005 at 20:52:30
The way it is originally, if you are up against a wall that is on your left, if you hit strafe to the right and jump at hte same time while you are in the air, you will be launched away from the wall tothe right.

With the modifications that I talk about, you can do jump away from the wall diagonally forward or climb up walls. You can multiple wall jump if you want unless you stick in code that limits the number of jumps allowed. you can also change how high your jump will throw you.

<quote>so far, all this code allows me to do is jump away from a wall and up a great distance</quote>

Thats wall jumping for you. If you had more than one wall running parallel next to eachother you could probably also jump between them.

Posted By: hopper on Feb 10 2005 at 20:56:05
pogo jumping:
When you press jump and dont release it, you should jump up in the air and then land. Pogo jumping is where you instantly jump again because you have jump held down. You in effect, bounce around like you're on a pogo stick. You need that code in there otherwise you will pogo.

Posted By: Unknown on Mar 19 2005 at 21:35:36
This doesnt work for the hl2dm sdk right? :(

Posted By: ibutsu on Apr 15 2005 at 07:53:18
It may not, I wrote this before the dm sdk had been released. btw, thanks to hopper for the better job then I have done at helping people in these comments :) I'll try to get all these updates written into an update, I've not spent much time w/ hl2 dev since I did these articles, so sorry for any lack of help/support. Soulfather: I got your pm and I tried to respond via e-mail but it kept failing and returning them later :\

-ibutsu

Posted By: Jorg40 on Sep 15 2005 at 14:05:19
What can I do if I want this into the DM SDK?

Posted By: endlosnull on Sep 27 2005 at 17:00:02
I had a few problems when I put this tutorial into the "Start Mod from Scratch" option but I seemed to have fixed it. I had to add,

player->

before every m_pSurfaceData so it would look like,

player->m_pSurfaceData

I also had to put the,

extern bool g_bMovementOptimizations;

Not after,

EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CGameMovement, IGameMovement,INTERFACENAME_GAMEMOVEMENT, g_GameMovement );

But after the header inclusions.
Good tutorial though.

Posted By: Jorg40 on Mar 29 2006 at 18:00:48
What about the DM sdk?

prev ( [1] 2 ) next
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: 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
 
Particle Engine tutorial part 5
Half-Life | Coding | Client Side Tutorials
By: Persuter | Aug 02 2009
 

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

Wavelength version: 3.0.0.9
Valid XHTML 1.0! Valid CSS!