Comparison between bunnyhopping and ahopping.
Accelerated Hopping, or Ahop for short, is the main movement technique in the New Engine versions of Portal, Half-Life 2, and the episodes. It replaces bunnyhopping, which was patched together with the release of Portal and Half-Life 2: Episode Two. It is also significantly faster.
The glitch also works in Half-Life 2: Deathmatch in singleplayer, as well as in Half-Life: Alyx and The Lab: Robot Repair, when launched without VR.
In order to patch bunnyhopping, Valve implemented a speed cap into the games. This speed cap was implemented horribly, and worked by adding negative velocity to the player. However, instead of relying on the actual movement of the player, it relied on the input to determine the direction the player was going. It was quickly discovered that this could be abused. It can also only be applied 100% forwards or 100% backwards. Never to the side.
Ahop can be divided into three primary variants: Accelerated Back Hopping (ABH), Accelerated Side Hopping (ASH), and Accelerated Forwards Hopping (AFH). There's also a backwards version of ASH, that doesn't really have a proper name, as it's a pretty niche and unused version, cause you should just stick to ABH at this point.
The glitch itself was first introduced with the release of The Orange Box back on October 10, 2007. It was found by many since. It's quite easy to stumble upon and experience the speed boost by simply jumping backwards, which occasionally still happens even today with those who have never played the game before. And yet there are two names to be mentioned.
The first discovery dates back at least to October 17, 2007, when it was posted by Hlook on HL2DQ forum in the thread titled "Episode 2 Glitch…", along with the Episode Two demo file demonstrating it on ep2_outland_06a. The very same forum thread where SPD was first discussed:
Ok guys, you don’t need any object to get SUPER speed :)I found that while mapping for portal, and I tried it in episode 2, IT WORK !In addition, it’s easy to do, check this demo.
The term "ABH" was coined in the same thread on October 18, 2007 by DemonStrate. Although, since that particular forum is long gone, the posts were migrated to SourceRuns with some quirks (there's no text).
Another discovery was made concurrently on October 20, 2007 and posted on Speed Demos Archive by Spider-Waffle, in a thread dedicated to Portal speedruns:
I just figured out how I was able to get that super speed while bhopping backwards. You really do have to be going backwards for it to work.
He, in fact, experienced it a little earlier on October 10, 2007, as stated in the same thread, but didn't make anything of it then:
While bhoping around on the boss fight level with AHK I was able to have my speed suddenly start increasing exponentially at which point I would lose my air control I think. Funny I only had this happen when going backwards.
The glitch was also present in Garry's Mod, until it was fixed on October 10, 2016. The changelog under Community Contributions states:
Fixed backwards bunnyhopping
In order to perform an ahop, the player must be over the speed cap of the current movement type (walking, ducking, sprinting), while also tricking the game that they're moving in a different direction than they actually are.
Movement guide by Lyren:
https://www.youtube.com/watch?v=567z1uNkscY
The higher the base speed of the movement type, the higher the speed cap, meaning the game will apply less negative velocity to slow the player down, which in turn means that the speed boost will be smaller. A table of the speed caps in different movement types is available:
| Conditions | Speed limit | First possible ABH speed | ||
|---|---|---|---|---|
| With suit | Suitless | With suit | Suitless | |
| Crouching | 209 | 165 | 495 | 285 |
| Walking | 225 | 225 | 479 | n/a (2) |
| Running | 285 | 419 | ||
| Sprinting | 352 | n/a (1) | n/a (3) | |
Since the HEV suit isn't obtainable in Portal, the player can only crouch and walk.
Notes:
(1) You cannot sprint without a suit.
(2) The only states you can enter without the suit is walking and crouching.
(3) You cannot sprint while jumping.
In order to perform an ABH, the player needs to be going backwards over the speed cap without holding W. The game will by default assume that the player is going forwards, adding backwards speed to slow the player down, not knowing that they're already going backwards.
The easiest way to achieve this result is to sprint backwards, let go of s after jumping, and continuing to jump.
https://www.youtube.com/watch?v=vdNYggZr5nM
AFH is the opposite of ABH. It is significantly harder to perform, as when W and S are not held - the game assumes the player is moving forwards. This means that to trick the game into going backwards, S needs to be pressed whenever a jump is made. Alternatively, a singificantly harder to learn but faster method utilizing the +strafe command exists.
The +strafe command, available in the menu as "Strafe Modifier" allows the player to control their player with the mouse, with analogue input. The game will take this input into consideration when checking the direction of player movement.
By holding +strafe, and moving their mouse down at the same time, the player can sacrifice the ability to move their camera for an AFH with the same speed as an ABH.
https://www.youtube.com/watch?v=XI_-GHnOsfc
Accelerated Side hopping is a variant of AFH that doesn't require the player to quickly tap S or press +strafe whenever they jump.
This however, comes with downsides. The speed boost from ASH is noticeably smaller than the one from AFH, and the boost isn't applied in the same direction as the one the player is travelling. This leads to the player making arcs in air.
ASH is performed by holding S and one of the side directional keys at the same time, while also looking around 45° to the right, when holding A, or left when holding D.
https://www.youtube.com/watch?v=Lrnp88Dq7TU
TODO: most of the technical explanation was copy pasted with small fixes. Someone should verify if it doesn't need changing.
Accelerated hopping is a result of valve not taking into account the direction of the player's speed when capping it, and tying it to the Jumpboost code.
Whenever the player jumps, in the game, the game will apply a speed boost forward, if the player is holding W, or backwards when the player is holding S. In Old Engine, this resulted in bunnyhopping. Instead of installing a global speed cap for the player, valve simply (tried) to prevent the jumpboost speed from building up every jump.
This means that even if the code worked as intended, jumping sideways would have no speed cap regardless.
Pinsplash's video explaining the math behind the glitch:
https://www.youtube.com/watch?v=S8lriQJnnjs
The game goes through a few steps to decide how much to add to or subtract from the player's speed.
float flSpeedBoostPerc = ( !pMoveData->m_bIsSprinting && !player->m_Local.m_bDucked ) ? 0.5f : 0.1f;`
float flSpeedAddition = fabs( mv->m_flForwardMove * flSpeedBoostPerc );
//mv->m_flForwardMove is the normal speed we move while in the state we jumped in, so when we do a sprint jump, it is 320; a running jump is 190;...
3. Calculate the maximum speed flMaxSpeed for bounding the player's speed later on.
float flMaxSpeed = mv->m_flMaxSpeed + ( mv->m_flMaxSpeed * flSpeedBoostPerc );
float flNewSpeed = ( flSpeedAddition + mv->m_vecVelocity.Length2D() );
// If we're over the maximum, we want to only boost as much as will get us to the goal speed
if ( flNewSpeed > flMaxSpeed )
{
flSpeedAddition -= flNewSpeed - flMaxSpeed;
}
After all the steps above, the game takes the newly acquired flSpeedAddition and apply it onto the player's current speed.
ABH will be used for the primary explanation as it is the simplest form of ahop.
The most standard ABH is done by doing a backward sprintjump, crouching in midair, landing then continuing to jump without holding any directional keys. In the calculations below, we'll assume that inputs are frame-perfect without any loss of speed.
Let's imagine a player doing crouched ABHs in a straight line. When the player begins their run up by sprinting backwards and then jumping, their speed would be negative. Right before the next jump in the ABH sequence, their speed would be at 352 UPS. Ideally at this point, since they're crouched, mv->m_flForwardMove should be at 190; but because we are not holding any directional keys, it is 0 instead. This means our additional speed we get will also be 0.
float flSpeedAddition = fabs( mv->m_flForwardMove * flSpeedBoostPerc ) = fabs(0 * 0.1) = 0
As a result, our new speed will also be the same as the old which would be
float flNewSpeed = ( flSpeedAddition + mv->m_vecVelocity.Length2D() ) = 0 + 352 = 352
Because our speed is over the threshold when landing (we land at 352 UPS which is higher than the 209 UPS threshold when crouching), the game does the speed bounding routine. However, since our flSpeedAddition is 0, this will come out as negative.
flSpeedAddition -= flNewSpeed - flMaxSpeed
= flSpeedAddition - (flNewSpeed - flMaxSpeed)
= 0 - (352 - 209)
= -143
And since we're moving backwards and our speed is negative, our new speed will be increased. Our new speed in this case is 495. After 2 another jumps, the speed increase will be massive
//(2nd ABH jump)
flSpeedAddition -= flNewSpeed - flMaxSpeed
= flSpeedAddition - (flNewSpeed - flMaxSpeed)
= 0 - (352 + 143 - 209)
= -286
//(3rd ABH jump)
flSpeedAddition -= flNewSpeed - flMaxSpeed
= flSpeedAddition - (flNewSpeed - flMaxSpeed)
= 0 - (352 + 143 + 286 - 209)
= -579
After these 2 jumps, our speed would be 1360 UPS.
When S is held, or the player is moving backwards with +strafe, mv->m_flForwardMove is negative, which shouldn't interfere in the speed capping as the function uses its absolute value. However at the very bottom there's the following bit of code:
if ( mv->m_flForwardMove < 0.0f )
flSpeedAddition *= -1.0f;
Which effectively turns the speed reduction amount from being negative to positive, thus accelerating you.
//(before)
flSpeedAddition -= flNewSpeed - flMaxSpeed
= flSpeedAddition - (flNewSpeed - flMaxSpeed)
= 0 - (352 - 209)
= -143
//(after)
flSpeedAddition *= -1.0f
flSpeedAddition = -143 * -1
flSpeedAddition = 143
143 UPS is added to your previous positive speed instead of the -143 from before.