Двойное нажатие

Материал из Наша Wiki - Наша энциклопедия Half-Life
Перейти к: навигация, поиск

Вам хотелось, когда нибудь сделать удары ногой, рукой и использовать их в виде комбо, например по нажатию 2 раза какой-то кнопки за определённое время вызвать ту или иную функцию? Вот и решил я наваять какой, никакой код :D

Приступаем:

// m_iState: 0 = Нет нажатия
//           1 = Нажато 1 раз
//           2 = Нажато дважды
//           3 = Готово к использованию

struct TapData_s 
{
	TapData_s( int key = 0, float dmin = 0, float dmax = 0 )
	:m_nKey(key), m_iState(0), 
	m_flPressTime1(gpGlobals->curtime), 
	m_flPressTime2(gpGlobals->curtime+1), 
	m_flDelayBetweenPressesMin(dmin),
	m_flDelayBetweenPressesMax(dmax)
	{}

	int m_iState;
	int m_nKey;

	float m_flPressTime1;
	float m_flPressTime2;
	float m_flDelayBetweenPressesMin;
	float m_flDelayBetweenPressesMax;

};

class CTapHandler
{
public:
	CTapHandler(){  }
        ~CTapHandler(){ m_vpTapDataList.PurgeAndDeleteElements(); }

	void AddKeyToTrackList( const int &nKey, const float &flTimeToPressTwiceMin, const float &flTimeToPressTwiceMax )
	{
		bool noMatches = true; // Lolmen : Проверка на наличие такой клавиши в списке
		FOR_EACH_VEC( m_vpTapDataList, i )
		{
			if ( m_vpTapDataList[ i ]->m_nKey == nKey )
			{
				noMathces = false;
				break;
			}
		}

		if ( noMatches )
			m_vpTapDataList.AddToTail( new TapData(nKey, flTimeToPressTwiceMin, flTimeToPressTwiceMax) );
	}

	void HandleKeysTaps( const CBasePlayer *pPlayer )
	{
		if (!pPlayer)
			return;
		FOR_EACH_VEC( m_vpTapDataList, i )
		{
			TapData_s *pCurTap = m_vpTapDataList[ i ];

			switch( pCurTap->m_iState )
			{
			case 0:
			{	// Lolmen : Первое нажатие игроком
				if ( pPlayer->m_afButtonPressed & pCurTap->m_nKey )
				{
					pCurTap->m_iState = 1;
					pCurTap->m_flPressTime1 = gpGlobals->curtime;
				}
			}
			break;
			case 1:
			{	// Lolmen : Второе нажатие игроком
				if ( pPlayer->m_afButtonPressed & pCurTap->m_nKey )
				{
					pCurTap->m_iState = 2;
					pCurTap->m_flPressTime2 = gpGlobals->curtime;
				}
			}
			break;
			case 2:
			{
				float dt = pCurTap->m_flPressTime2 - pCurTap->m_flPressTime1;
				// Lolmen : Больше наше dt или равно минимальному времени нажатия, 
				// или же, меньше, а может и равно максимальному времени?
				if ( dt >= pCurTap->m_flDelayBetweenPressesMin && dt <= pCurTap->m_flDelayBetweenPressesMax )
					pCurTap->m_iState = 3;	
				else
				{	// Lolmen : Если не прокатило сбрасываем статус на начало
					pCurTap->m_iState = 1;
					pCurTap->m_flPressTime1 = gpGlobals->curtime;
				}
			}
			break;
			default:
			{	// Lolmen : На следующем кадре опять сбрасываем статус, если достигнут результ
				if ( pCurTap->m_iState >= 3 )
				{
					pCurTap->m_iState = 1;
					pCurTap->m_flPressTime1 = gpGlobals->curtime;
				}
			}
			}
		}
	}
	void Update( void )
	{	// Lolmen : Покадровый обновитель
		CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
		if ( pPlayer != NULL )
		{
			HandleKeysTaps( pPlayer );
		}
	}
	// Эта функция вернёт true только 1 раз за кадр
	bool KeyPressedTwice( const int &nKey )
	{
		FOR_EACH_VEC( m_vpTapDataList, i )
		{
			TapData_s *pCurTap = m_vpTapDataList[ i ];

			if ( pCurTap->m_nKey == nKey && pCurTap->m_iState >= 3 )
				return true;
		}
		return false;
	}
private:
	CUtlVector< TapData_s* > m_vpTapDataList;

};

Это был класс для определения функциональности, как его применять?

// Lolmen : Создадим где-то главный экземпляр:
CTapHandler gTapHandler;
// NOTE: в других файлах используем ссылку на главный экз "extern CTapHandler gTapHandler;" 

Теперь давайте попробуем использовать наш экземпляр например в оружии SMG1

В конструктор добавим такое :

CWeaponSMG1::CWeaponSMG1()
{
  // какойто инициализирующий код тут
  // Lolmen : наш отлавливатель
  gTapHandler.AddKeyToTrackList( IN_FORWARD, 0.1f, 0.3f );
  gTapHandler.AddKeyToTrackList( IN_SPEED, 0.015f, 0.5f );
  // Lolmen : Примечаение : ( Кнопка, минимальное время, максимальное время ) за которое мона нажать 2жды
}

Так, мы определили, за какими кнопками нужно установить наблюдение, теперь будем это использовать :

CWeaponSMG1::ItemPostFrame( )
{
  // Lolmen: Разместим где-то покадровую обновлялку
  gTapHandler.Update();
  
  // Какой-то SMG'шный код тут :

  // Lolmen: Теперь смотрим были-ли нажаты 2жды след кнопки :

  if ( gTapHandler.KeyPressedTwice( IN_FORWARD ) )
  {
        // Вызываем какой-то метот тут:
  }
  if ( gTapHandler.KeyPressedTwice( IN_SPEED ) )
  {
       // Делаем что-то еще
  }
}

Если возникнут проблемы, обращаемся в форум.

Автор: Lolmen