Исправление Duck Jump (Прыжок + приседание)
Введение
Эта статья покажет вам, как исправить Прыжок в сидячем положение от 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)