Posted by: ibutsu
Date posted: Dec 06 2004 User Rating: 5 out of 5.0 | Number of views: 14011 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:
| | | 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:
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:
| | | bool CSDKGameMovement::CheckJumpButton() { if (player->pl.deadflag) { mv->m_nOldButtons |= IN_JUMP ; return false; }
if (player->m_flWaterJumpTime) { player->m_flWaterJumpTime -= gpGlobals->frametime; if (player->m_flWaterJumpTime < 0) player->m_flWaterJumpTime = 0;
return false; }
if ( player->GetWaterLevel() >= 2 ) { SetGroundEntity( (CBaseEntity *)NULL );
if(player->GetWaterType() == CONTENTS_WATER) mv->m_vecVelocity[2] = 100; else if (player->GetWaterType() == CONTENTS_SLIME) mv->m_vecVelocity[2] = 80;
if ( player->m_flSwimSoundTime <= 0 ) { player->m_flSwimSoundTime = 1000; PlaySwimSound(); }
return false; }
if ( player->m_Local.m_bSlowMovement ) return false;
if ( mv->m_nOldButtons & IN_JUMP ) return false;
if ( player->m_Local.m_bDucking && ( player->GetFlags() & FL_DUCKING ) ) return false;
if ( player->m_Local.m_flDuckJumpTime > 0.0f ) return false;
float startz = 0.0f; float starty = 0.0f; float startx = 0.0f;
float flMul;
if ( g_bMovementOptimizations ) { Assert( sv_gravity.GetFloat() == 800.0f ); flMul = 268.3281572999747f; } else { flMul = sqrt(2 * sv_gravity.GetFloat() * GAMEMOVEMENT_JUMP_HEIGHT); }
if (player->GetGroundEntity() == NULL) { int i = 0; Vector EndPoint; trace_t tr;
EndPoint[2] = player->GetAbsOrigin()[2];
startx = mv->m_vecVelocity[0]; starty = mv->m_vecVelocity[1]; startz = mv->m_vecVelocity[2];
if( mv->m_nButtons & IN_MOVERIGHT ) { 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 ) { for(i = 0; i < 2; i++) mv->m_vecVelocity[i] = m_vecRight[i] * 275 * 1.1;
mv->m_vecVelocity[2] += flMul; } else { mv->m_nOldButtons |= IN_JUMP; return false; } } else if( mv->m_nButtons & IN_MOVELEFT ) { 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 ) { for(i = 0; i < 2; i++) mv->m_vecVelocity[i] = m_vecRight[i] * -275 * 1.1;
mv->m_vecVelocity[2] += flMul; } else { mv->m_nOldButtons |= IN_JUMP; return false; } } } else { 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; }
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();
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;
if ( gpGlobals->maxClients == 1 ) { player->m_Local.m_flJumpTime = GAMEMOVEMENT_JUMP_TIME; player->m_Local.m_bInDuckJump = true; }
mv->m_nOldButtons |= IN_JUMP; 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:
| | |
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:
| | | EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CGameMovement, IGameMovement,INTERFACENAME_GAMEMOVEMENT, g_GameMovement );
|
Below that line add this line:
| | | extern bool g_bMovementOptimizations;
|
Next open up c_baseplayer.h and scroll down to line 401, it should look similar to this:
| | |
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:
| | | 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! |
|
User Comments
prev ( [1] 2 ) next
Showing comments 1-20
|
jumping off of walls while in the air |
|
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 22 2004, 21:33:51
|
|
|
Wow, thanks for the contribution, hopper! I'll edit the article and add your name to the special thanks list :) |
|
|
ibutsu i send you a PM about 2 weeks ago...do you check those or do you ignore? |
|
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 04 2005, 19:22:18
|
|
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 |
|
|
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. |
|
|
great explanation hopper, That was very very helpful, i appreciate it. |
|
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, 15:03:53
|
|
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. |
|
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"? |
|
|
also, what exactly is "pogo jumping?" i've deleted the code that disables it, and i can't see any difference |
|
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. |
|
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. |
|
|
This doesnt work for the hl2dm sdk right? :( |
|
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 |
|
|
What can I do if I want this into the DM SDK? |
|
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. |
|
prev ( [1] 2 ) next You must register to post a comment. If you have already registered, you must login.
|
297 Approved Articless
6 Pending Articles
3940 Registered Members
0 People Online (7 guests)
|
|