Ru/Duck Jump Fix

== Введение ==
Эта статья покажет вам, как исправить Прыжок в сидячем положение от Valve. В стандартном коде от Valve (в Orange Box Source SDK), игрок перемещается вверх на 32 юнита за 1 кадр. Это вызывает огромные пробелы с вычислением хитбокса и синхронизацией сервера с клиентом. Это даже может заставить игрока зависнуть в воздухе.
Для решения этой проблемы мы добавим интерполяции приседания и вставания в воздухе. У нас имеется небольшой промежуток времени для применения этих интерполяций, мы ускорим темпы приседания во время прыжка в два раза при нормальной скорости приседания.
== Требования ==
*Нормальные знания C++.
*Знания движка Source SDK.
*Общее знания о движении игрока.
== Код ==
На самом деле не так уж и много писать. нам всего-лишь нужно добавить две функции и два условных оператора. Так что просто копируйте и вставляйте код в определенные разделы.
=== GameMovement.h ===
Добавьте объявления функции CGameMovement в GameMovement.h около линии 205:
virtual void	DoDuckJump( float flFraction );
virtual void	DoUnDuckJump( float flFraction );
=== GameMovement.cpp ===
Сначала мы должны определить разницу между наивысшей точкой прыжка в сидячем положение и положение сидя. Вы можете изменить это число для вашего мода, т.к. мы будем изменять высоту прыжка (не является частью этого урока).
Добавьте дэфейн сразу же после инлудов (include):
#define DUCKJUMP_SCALING 0.2f
Далее мы напишем функции котоыре объявили в заголовке (читайте комментарии к описанию). Просто вставьте эти функции где-нибудь рядом с функциями приседания (ducking) для того, чтобы всё было по порядку.
void CGameMovement::DoDuckJump( float flFraction )
{
	if ( flFraction >= 1.0f )
	{
		// Since we accelerate the ducking time artificially say that we are ducking so we don't fly up in the air
		player->AddFlag( FL_DUCKING );
		player->m_Local.m_bDucked = true;
		player->m_Local.m_bDucking = false;
		// Force the view offset to be "fully ducked"
		player->SetViewOffset( GetPlayerViewOffset( true ) );
	}
	else
	{
		// Move our view down
		SetDuckedEyeOffset( flFraction );
		// Move our body up a fraction of the difference between fully crouched and fully standing
		Vector hullSizeNormal = VEC_HULL_MAX - VEC_HULL_MIN;
		Vector hullSizeCrouch = VEC_DUCK_HULL_MAX - VEC_DUCK_HULL_MIN;
		Vector viewDelta = ( hullSizeNormal - hullSizeCrouch ) * DUCKJUMP_SCALING * flFraction;
		Vector out;
		VectorAdd( mv->GetAbsOrigin(), viewDelta, out );
		mv->SetAbsOrigin( out );
		// See if we are stuck?
		FixPlayerCrouchStuck( true );
		// Recategorize position since ducking can change origin
		CategorizePosition();
	}
}
void CGameMovement::DoUnDuckJump( float flFraction )
{
	if ( flFraction <= 0.0f )
	{
		// Since we accelerate the ducking time artificially say that we are not ducking so we don't go through the floor
		player->m_Local.m_bDucked = false;
		player->RemoveFlag( FL_DUCKING );
		player->m_Local.m_bDucking = false;
		player->m_Local.m_bInDuckJump = false;
		// Set our view offset to fully standing
		player->SetViewOffset( GetPlayerViewOffset( false ) );
		player->m_Local.m_flDucktime = 0;
	}
	else
	{
		// Move our view up
		SetDuckedEyeOffset( flFraction );
		// Move our body down a fraction of the difference between fully crouched and fully standing
		Vector hullSizeNormal = VEC_HULL_MAX - VEC_HULL_MIN;
		Vector hullSizeCrouch = VEC_DUCK_HULL_MAX - VEC_DUCK_HULL_MIN;
		Vector viewDelta = ( hullSizeNormal - hullSizeCrouch ) * DUCKJUMP_SCALING * flFraction;
		viewDelta.Negate();
		Vector out;
		VectorAdd( mv->GetAbsOrigin(), viewDelta, out );
		mv->SetAbsOrigin( out );
		// See if we are stuck?
		FixPlayerCrouchStuck( true );
		// Recategorize position since ducking can change origin
		CategorizePosition();
	}
}
В конце концов, настроим наши функции для игрока. Я не могу точно сказать в какой строчке нужно делать эти изменения, т.к. мой gamemovement.cpp сильно изменён под мой мод. 
СТАРЫЙ КОД (ПРИСЕДАНИЯ):
// The player is in duck transition and not duck-jumping.
if ( player->m_Local.m_bDucking && !bDuckJump && !bDuckJumpTime )
{
	float flDuckMilliseconds = max( 0.0f, GAMEMOVEMENT_DUCK_TIME - ( float )player->m_Local.m_flDucktime );
	float flDuckSeconds = flDuckMilliseconds * 0.001f;
	
	// Finish in duck transition when transition time is over, in "duck", in air.
	if ( ( flDuckSeconds > TIME_TO_DUCK ) || bInDuck || bInAir )
	{
		FinishDuck();
	}
	else
	{
		// Calc parametric time
		float flDuckFraction = SimpleSpline( flDuckSeconds / TIME_TO_DUCK );
		SetDuckedEyeOffset( flDuckFraction );
	}
}
НОВЫЙ КОД (ПРИСЕДАНИЯ):
// The player is in duck transition and not duck-jumping.
if ( player->m_Local.m_bDucking && !bDuckJump && !bDuckJumpTime )
{
	float flDuckMilliseconds = max( 0.0f, GAMEMOVEMENT_DUCK_TIME - ( float )player->m_Local.m_flDucktime );
	float flDuckSeconds = flDuckMilliseconds * 0.001f;
	
	// Finish in duck transition when transition time is over, in "duck", in air.
	if ( (( flDuckSeconds > TIME_TO_DUCK ) || bInDuck) && !bInAir )
	{
		FinishDuck();
	}
	else if ( bInAir )
	{
		// Speed up our duck transition by two times if we are duck jumping
		float flDuckFraction = clamp( SimpleSpline( flDuckSeconds / TIME_TO_DUCK )*2.0f, 0, 1.0f );
		DoDuckJump( flDuckFraction );
	}
	else
	{
		// Calc parametric time
		float flDuckFraction = SimpleSpline( flDuckSeconds / TIME_TO_DUCK );
		SetDuckedEyeOffset( flDuckFraction );
	}
}
СТАРЫЙ КОД (ВСТАВАНИЯ):
// Check to see if we are capable of unducking.
if ( CanUnduck() )
{
	// or unducking
	if ( ( player->m_Local.m_bDucking || player->m_Local.m_bDucked ) )
	{
		float flDuckMilliseconds = max( 0.0f, GAMEMOVEMENT_DUCK_TIME - (float)player->m_Local.m_flDucktime );
		float flDuckSeconds = flDuckMilliseconds * 0.001f;
		
		// Finish ducking immediately if duck time is over or not on ground
		if ( flDuckSeconds > TIME_TO_UNDUCK || ( bInAir && !bDuckJump ) )
		{
			FinishUnDuck();
		}
		else
		{
			// Calc parametric time
			float flDuckFraction = SimpleSpline( 1.0f - ( flDuckSeconds / TIME_TO_UNDUCK ) );
			SetDuckedEyeOffset( flDuckFraction );
			player->m_Local.m_bDucking = true;
		}
	}
}
НОВЫЙ КОД (ВСТАВАНИЯ):
// Check to see if we are capable of unducking.
if ( CanUnduck() )
{
	// or unducking
	if ( ( player->m_Local.m_bDucking || player->m_Local.m_bDucked ) )
	{
		float flDuckMilliseconds = max( 0.0f, GAMEMOVEMENT_DUCK_TIME - (float)player->m_Local.m_flDucktime );
		float flDuckSeconds = flDuckMilliseconds * 0.001f;
		// Finish ducking immediately if duck time is over or not on ground
		if ( flDuckSeconds > TIME_TO_UNDUCK && !bInAir )
		{
			FinishUnDuck();
		}
		else if ( bInAir )
		{
			// Reverse our process
			float flDuckFraction = clamp( SimpleSpline( 1.0f - (flDuckSeconds / TIME_TO_UNDUCK) )*2.0f, 0, 1.0f );
			DoUnDuckJump( flDuckFraction );
		}
		else
		{
			// Calc parametric time
			float flDuckFraction = SimpleSpline( 1.0f - ( flDuckSeconds / TIME_TO_UNDUCK ) );
			SetDuckedEyeOffset( flDuckFraction );
			player->m_Local.m_bDucking = true;
		}
	}
}
Вот и все, теперь когда вы прыгаете (bInAir == TRUE) ваш вид и позиция (а так же bounding и хитбоксы) буду зависить от DoDuckJump / DoUnDuckJump и когда вы находитесь на земле, положение сидя будет зависить от SetDuckedEyeOffset ()
== Примечания и Дальнейшая работа ==
Бета-тестеры обнаружили, что этот код заставляет игрока терять скорость во время бега и прыжка. Это не страшно для нашего мода, так как наша задача состоит в устранении bunny hopping (Распрыжка), но если вы хотите bunny hopping как в CSS, как движение, то распрыжка не будет работать без модификации этого кода.
Один из способов сохранить скорость игрока было расчёт нового origin'а, а также добавление вектора движения на основе скорости игрока (а не только движение по оси Z).
Перевод --Slam12f 05:39, 12 May 2013 (PDT)