Пятница, 04.10.2024, 02:13
Приветствую Вас Guest | RSS
Главная страница | Статьи | Регистрация | Вход
Меню сайта

Случайный рисунок

Категории каталога
Туториалы по маппингу (HL2) [68]
Туториалы по маппингу для Half-Life
Туториалы по текстурированию (HL2) [10]
Туторы по текстурированию для Half-Life
Туториалы по моделированию (HL2) [9]
Туторы по моделированию для Half-Life
Туториалы по программированию (HL2) [53]
Туторы по прагроммированию для Half-life
Другие туториалы (HL1 и HL2) [4]
Туторы которые не вошли в другие категории
Half-Life 2 Beta [1]
Статьи о npc и weapon в бете Half-Life 2, а так же мануалы и FAQ.
Туториалы по маппингу (HL1) [14]
Туторы по маппингу для Half-Life 1
Туториалы по текстурированию (HL1) [1]
Туторы по текстурированию для Half-Life 1
Туториалы по моделированию (HL1) [1]
Туторы по моделированию для Half-Life 1
Туториалы по программированию (HL1) [30]
Туторы по программированию для Half-Life 1

Наш опрос
Очистить ли форум от всех сообщений и начать всё с чистого листа?
Всего ответов: 563

Начало » Статьи » Туториалы по программированию (HL2)

Динамический Разброс Пуль
Вам наверное всегда было интересно сделать динамический конус разброса как в Counter-Strike:Source ...
Ну вот и пришло время этим заняться :) Для рассмотрения пусть будет weapon_357.cpp

Взглянув на класс, мы видим такую картину :
 
class CWeapon357 : public CBaseHLCombatWeapon
{
DECLARE_CLASS( CWeapon357, CBaseHLCombatWeapon );
public:

CWeapon357( void );

void PrimaryAttack( void );
void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );

DECLARE_SERVERCLASS();
DECLARE_DATADESC();
};
 
Чтож, добавим сразу после Operator_HandleAnimEvent метод :
 
virtual const Vector& GetBulletSpread( void );
 
И проимплементурем его где-то ниже в cpp'шнике чтобы было вот так:
 
const Vector &CWeapon357::GetBulletSpread( void )
{
// Lolmen : Берём указатель на игрока
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
if ( !pPlayer ){ return vec3_origin; } // если он нулевой ничего не делаем

static Vector cone = vec3_origin;
// Игрок стоит на земле
if ( ( pPlayer->GetFlags() & FL_ONGROUND ) != 0 )
{
if ( ( pPlayer->GetFlags() & FL_DUCKING ) != 0 )
{ // игрок сидит
cone = VECTOR_CONE_1DEGREES;
}
else
{
if ( pPlayer->GetAbsVelocity().Length2D() > 120 )
{ // игрок двигается быстро
cone = VECTOR_CONE_5DEGREES;
}
else
{ // Игрок медленно двигается или стоит
cone = VECTOR_CONE_3DEGREES;
}
}
} // Игрок в прыжке
else
{
cone = VECTOR_CONE_6DEGREES;
}

return cone;
}
 

Это отлично подходит для медло стрелокового типа оружия, что делать со скорострельным, например автомат или тому подобное? Тогда для примера возьмём SMG1 weapon_smg1.cpp

И увидим мы следующее :
 
class CWeaponSMG1 : public CHLSelectFireMachineGun
{
DECLARE_DATADESC();
public:
DECLARE_CLASS( CWeaponSMG1, CHLSelectFireMachineGun );

CWeaponSMG1();

DECLARE_SERVERCLASS();

void Precache( void );
void AddViewKick( void );
void SecondaryAttack( void );

int GetMinBurst() { return 2; }
int GetMaxBurst() { return 5; }

virtual void Equip( CBaseCombatCharacter *pOwner );
bool Reload( void );

float GetFireRate( void ) { return 0.075f; } // 13.3hz
int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; }
int WeaponRangeAttack2Condition( float flDot, float flDist );
Activity GetPrimaryAttackActivity( void );

virtual const Vector& GetBulletSpread( void )
{
static const Vector cone = VECTOR_CONE_5DEGREES;
return cone;
}

const WeaponProficiencyInfo_t *GetProficiencyValues();

void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
{
(...) // Троеточие подразумевает код который нам видить не надо
}

DECLARE_ACTTABLE();

protected:

Vector m_vecTossVelocity;
float m_flNextGrenadeCheck;
};

Кстати, GetMinBurst() и GetMaxBurst() это минимальное и максимально кол-во выстрелов для NPC, т.е если вы хотите чтобы комбин пулял как бешеный например из weapon_pistol то добавьте эти методы если их нет, либо поменяйте значение, например 10-15 вместо 2.

Вернёмся к нашим апельсинам.

добавим после
 
extern ConVar    sk_plr_dmg_smg1_grenade;
дефайн:
 
#define SMG_REACH_FULL_SPREAD_TIME 2.0f // Lolmen : время достижения максимального разброса
 
и после
 
int GetMaxBurst() { return 5; }
 
методы :
 
 // Lolmen : Возвращает конус разброса от мин к макс по времени
Vector GetDynamicSpread( const Vector &min, const Vector &max );
void UpdateAccuracy( void ); // обновляет точность
void ItemPreFrame( void ); // пре кадровая функа
void PrimaryAttack( void ); // видоизменим от базового класса
 
естественно не забудем про переменные и после переменной :
 
float m_flNextGrenadeCheck;
вставим такую вещь :
 
float m_flAccuracyPercent;
и естественно не забудем её продекларировать для SAVE/LOAD вещей.

найдём :

DEFINE_FIELD( m_flNextGrenadeCheck, FIELD_TIME ),
 
и после него впишем :
 
DEFINE_FIELD( m_flAccuracyPercent, FIELD_FLOAT ), // идёт как переменная с плавающей точкой
 
так. Теперь идём ниже (скроллим наш код) и начинаем после :
 
void CWeaponSMG1::AddViewKick( void )
{
... // опущено
}
 
Писать такой вот аццкий код :
 
void CWeaponSMG1::ItemPreFrame( void )
{
UpdateAccuracy();
BaseClass::ItemPreFrame();
}
void CWeaponSMG1::UpdateAccuracy( void )
{
// Lolmen : указатель на игрока
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
if ( !pPlayer ){ return; } // Если игрока нету то ничего не делаем

// Проверка на разъедание накопленной неточности
if ( !( pPlayer->m_nButtons & IN_ATTACK ) )
{
m_flAccuracyPercent -= clamp( gpGlobals->frametime, 0.1f, 0.2f );
m_flAccuracyPercent = clamp( m_flAccuracyPercent, 0.0f, SMG_REACH_FULL_SPREAD_TIME );
}
}
void CWeaponSMG1::PrimaryAttack( void )
{
BaseClass::PrimaryAttack();

// добавляем с каждой аттакой по процентной доле времени между выстрелами
m_flAccuracyPercent += GetFireRate();
}
Vector CWeaponSMG1::GetDynamicSpread( const Vector &min, const Vector &max )
{
float ramp = RemapValClamped( m_flAccuracyPercent, 0.0f, SMG_REACH_FULL_SPREAD_TIME, 0.0f, 1.0f );
Vector ret; VectorLerp( min, max, ramp, ret );
return ret;
}

Теперь найдём такой кусок кода :
 
bool CWeaponSMG1::Reload( void )
{
bool fRet;
float fCacheTime = m_flNextSecondaryAttack;

fRet = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD );
if ( fRet )
{
// Undo whatever the reload process has done to our secondary
// attack timer. We allow you to interrupt reloading to fire
// a grenade.
m_flNextSecondaryAttack = GetOwner()->m_flNextAttack = fCacheTime;

WeaponSound( RELOAD );
}

return fRet;
}
 
И видо изменим :
 
bool CWeaponSMG1::Reload( void )
{
bool fRet;
float fCacheTime = m_flNextSecondaryAttack;

fRet = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD );
if ( fRet )
{
// Undo whatever the reload process has done to our secondary
// attack timer. We allow you to interrupt reloading to fire
// a grenade.
m_flNextSecondaryAttack = GetOwner()->m_flNextAttack = fCacheTime;
// Lolmen : обнуляем щётчик
m_flAccuracyPercent = 0.0f;
WeaponSound( RELOAD );
}

return fRet;
}
 
Теперь находим кусок в начале :
 
 virtual const Vector& GetBulletSpread( void )
{
static const Vector cone = VECTOR_CONE_5DEGREES;
return cone;
}
 
И начинаем знакомую по началу тутора процедуру :
 
 virtual const Vector& GetBulletSpread( void )
{
// Lolmen : Берём указатель на игрока
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
if ( !pPlayer ){ return vec3_origin; } // если он нулевой ничего не делаем

static Vector cone = VECTOR_CONE_PRECALCULATED;
// Игрок стоит на земле
if ( ( pPlayer->GetFlags() & FL_ONGROUND ) != 0 )
{
if ( ( pPlayer->GetFlags() & FL_DUCKING ) != 0 )
{ // игрок сидит
cone = GetDynamicSpread( VECTOR_CONE_1DEGREES, VECTOR_CONE_3DEGREES );
}
else
{
if ( pPlayer->GetAbsVelocity().Length2D() > 120 )
{ // игрок двигается быстро
cone = GetDynamicSpread( VECTOR_CONE_5DEGREES, VECTOR_CONE_8DEGREES );
}
else
{ // Игрок медленно двигается или стоит
cone = GetDynamicSpread( VECTOR_CONE_3DEGREES, VECTOR_CONE_5DEGREES );
}
}
} // Игрок в прыжке
else
{
cone = GetDynamicSpread( VECTOR_CONE_7DEGREES, VECTOR_CONE_10DEGREES );
}

return cone;
}

Теперь, поэкспереминтировав с силой значений можно получить требуемый результат. главное что у GetDynamicSpread первый аргумент должен быть меньше второго но больше ноля...


Источник: http://wiki.hl2.ru/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9_%D0%A0%D0%B0
Категория: Туториалы по программированию (HL2) | Добавил: DetLeR (01.08.2007) | Автор: Lolmen
Просмотров: 1825 | Рейтинг: 5.0 |

Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Форма входа

Кто в Онлайн

Друзья сайта

Баннеры

  Сайт CrazyArts   Black   Сообщество сайтов о Half-Life   Самый   Только   Все   hl2 top 100     Rambler's Top100  

игры
игры

  Каталог сайтов Планета Топ 100 - Planet Top 100       ТОП ЛУЧШИХ ИГРОВЫХ САЙТОВ           Detroit Team Site :: Моды от Detroit Team, видео, новости.   Naruto-kun[Звезда Наруто]  


The idea of dising: Homie7