XFactorDev.net Article   XFactorDev.net Article

 

Prt-6- GamePad..

 

Its going to be used all over the place, the gamepad will act as our main input for our various games....its name CGamepad!

 

Be prepared to be amazed....now up to now you've really not coded much of a game engine, but with the CGamePad class that we'll now construct and add in, this will allow us to move objects around.....

 

Lets start by outlining the simple way to use the CGamePad class....well first we'll put the code in gamepad.h and gamepad.cpp, and it won't need any other dependent classes.  There is only 3 parts to the gamepad class as follows:

 

-1- Create an instance of the class

CGamePad g;

 

-2- Initilize it once by calling InitGamePad();

g.InitGamePad();

 

-3- Check for button presses then see if any of them are what you needed:

g.GetIntput();

if ( g.bBlackPressed() )

    ... do something

else

   ... wasn't pressed

 

 

Below is a list of all the button test functions in the CGamePad class

 

 

 

// default is first gamepad

bool bBlackButtonPressed(int iWhichGamePad = 0); 

bool bWhiteButtonPressed( int iWhichGamePad = 0);

bool bYellowButtonPressed( int iWhichGamePad = 0);
bool bRedButtonPressed( int iWhichGamePad = 0);
bool bBlueButtonPressed( int iWhichGamePad = 0);
bool bGreenButtonPressed( int iWhichGamePad = 0);

bool bStartButton( int iWhichGamePad = 0);
bool bBackButton( int iWhichGamePad = 0);

//-------------------------------------------------------------
float iAnalogStickUp ( int iWhichGamePad = 0);
float iAnalogStickDown ( int iWhichGamePad = 0);
float iAnalogStickLeft ( int iWhichGamePad = 0);
float iAnalogStickRight( int iWhichGamePad = 0);
//-------------------------------------------------------------
bool bButtonPadUp ( int iWhichGamePad = 0);
bool bButtonPadDown ( int iWhichGamePad = 0);
bool bButtonPadRight( int iWhichGamePad = 0);
bool bButtonPadLeft ( int iWhichGamePad = 0);
//-------------------------------------------------------------
float iRightStickUp ( int iWhichGamePad = 0);  
float iRightStickDown ( int iWhichGamePad = 0);
float iRightStickLeft ( int iWhichGamePad = 0);
float iRightStickRight( int iWhichGamePad = 0);

 

 

 

 

Now if you compile and run the demo code for the gamepad section, it will let you move a 3D cube around the screen using the top left analog gamepad controller....I've only set it to test for this gamepad 0 and use that one Analog strick, but it gives you an idea of the possibilities....with a few extra collision detection features you could throw a game such as table tennis or pong together in minutes :)

 

 

So what does it all look like inside?  Well your about to find out...its complicated because we wanted the ability to check for input from all 4 gamepad inputs....a definite must for any game!

I've put a copy and paste of gamepad.h below, see if you can understand the various parts...

 

/***************************************************************************/

/*                                                                         */

/*  gamepad.h                                                              */

/*                                                                         */

/***************************************************************************/

/*

     *****************************************************************

  ***                                                                 *** 

***        | iAnalogStick                                  Y   B        ***

*       ___|___               xfactordev.net                               *

*          |                                             X    A            *

  *        |                                                              *

  *                                                                      *

   *          x bButtonPad                                  |           *

    *         x                                          ___|___       *

     *    xxxxxxxxx    *****************************        |         *

      *       x       *                             *       |        *

        *       x      *    start         back         * iRightStick  *

         *             *                               *             *

          *           *                                 *           *

            *********                                     *********

 

 

*/

/***************************************************************************/

/*                                                                         */

/*  How the class works?                                                   */

/*                                                                         */

/***************************************************************************/

/*

      CGamePad p;             // Create global instance

      p.InitGamePad();    // Initilise it once.

 

      // Every time you check for button-presses, first call the member function,

      // GetInput().  The member variable will contain the changes and

      // can be tested for as follows.

      p.GetInput();

     

      // Then we can test for button presses using the functions such as

     

      p.bBlackButtonPressed();

      p.iRightStickUp();

      ...etc..etc

 

      You can pass an integer to them, e.g. 0, 1, 2, 3...for the various

      gamepads, if you don't pass a number, the default gamepad is the first

      one, gamepad 0 (very left one).

 

 

/***************************************************************************/

 

 

#include <xtl.h>

 

 

// Deadzone for thumbsticks

#define XBINPUT_DEADZONE 0.24f

const SHORT XINPUT_DEADZONE = (SHORT)( 0.24f * FLOAT(0X7FFF) );

 

class CGamePad

{

public:

//---------------------------------------------------------------------------

// These few methods will be the means of getting our feedback!  Testing for

// for button presses etc.

//---------------------------------------------------------------------------

// Default gamepad is 0...so if you dont' specify which one, it will assume

// the very left gamepad.

 

bool bBlackButtonPressed(int iWhichGamePad = 0);

bool bWhiteButtonPressed( int iWhichGamePad = 0);

 

bool bYellowButtonPressed( int iWhichGamePad = 0);

bool bRedButtonPressed( int iWhichGamePad = 0);

bool bBlueButtonPressed( int iWhichGamePad = 0);

bool bGreenButtonPressed( int iWhichGamePad = 0);

 

bool bStartButton( int iWhichGamePad = 0);

bool bBackButton( int iWhichGamePad = 0);

 

//---------------------------------------------------------------------------

float iAnalogStickUp   ( int iWhichGamePad = 0);

float iAnalogStickDown ( int iWhichGamePad = 0);

float iAnalogStickLeft ( int iWhichGamePad = 0);

float iAnalogStickRight( int iWhichGamePad = 0);

//---------------------------------------------------------------------------

bool bButtonPadUp   ( int iWhichGamePad = 0);

bool bButtonPadDown ( int iWhichGamePad = 0);

bool bButtonPadRight( int iWhichGamePad = 0);

bool bButtonPadLeft ( int iWhichGamePad = 0);

//---------------------------------------------------------------------------

float iRightStickUp   ( int iWhichGamePad = 0); // default is first gamepad

float iRightStickDown ( int iWhichGamePad = 0);

float iRightStickLeft ( int iWhichGamePad = 0);

float iRightStickRight( int iWhichGamePad = 0);

//---------------------------------------------------------------------------

 

public:

//----------------------------------------------------------------------------

// Name: struct XBGAMEPAD

// Desc: structure for holding Game pad data

//----------------------------------------------------------------------------

struct XBGAMEPAD : public XINPUT_GAMEPAD

{

    // The following members are inherited from XINPUT_GAMEPAD:

    //    WORD    wButtons;

    //    BYTE    bAnalogButtons[8];

    //    SHORT   sThumbLX;

    //    SHORT   sThumbLY;

    //    SHORT   sThumbRX;

    //    SHORT   sThumbRY;

 

    // Thumb stick values converted to range [-1,+1]

    FLOAT      fX1;

    FLOAT      fY1;

    FLOAT      fX2;

    FLOAT      fY2;

   

    // State of buttons tracked since last poll

    WORD       wLastButtons;

    BOOL       bLastAnalogButtons[8];

    WORD       wPressedButtons;

    BOOL       bPressedAnalogButtons[8];

 

    // Rumble properties

    XINPUT_RUMBLE   Rumble;

    XINPUT_FEEDBACK Feedback;

 

    // Device properties

    XINPUT_CAPABILITIES caps;

    HANDLE     hDevice;

 

    // Flags for whether game pad was just inserted or removed

    BOOL       bInserted;

    BOOL       bRemoved;

};

 

public:

 

      void InitGamePad();   // ~1~

 

      void GetInput();      // ~2~

 

      void CheckResetCall();

 

protected:

      HRESULT CreateGamepads();

 

      XINPUT_STATE                  m_InputStates[4];

 

      XBGAMEPAD m_Gamepads[4];

 

};

 

 

Now for the body...the part that actually makes it accomplish its task!....gamepad.cpp......now it looks like a lot of code, but most of it is for simple boolean button checks....e.g. bCheckRedButton, bCheckGreenButton etc. etc......then we have a couple of functions to initialise and test for gamepad button presses, which are stored in our XINPUT_STATE structure array.

 

/***************************************************************************/

/*                                                                         */

/*  gamepad.cpp                                                            */

/*                                                                         */

/***************************************************************************/

 

#include "gamepad.h"

 

/***************************************************************************/

/*                                                                         */

/* Details: Determines if the keypad buttons have been pressed             */

/*                                                                         */

/* Auth: x-factor development (http://www.xfactordev.net)                  */

/*                                                                         */

/* Main functions:                                                         */

/* InitGamePad(); - Called at the beginning of the game, to inilize the    */

/*                  gamepads.                                              */

/*                                                                         */

/* GetInput(); - Called each time through the main                         */

/* game loop, it checks for any button presses etc, and fills in the       */

/* m_Gamepad structure                                                     */

/*                                                                         */

/***************************************************************************/

 

/***************************************************************************/

/*                                                                         */

/* XBInput_CreateGamepads()                                                */

/* Creates the gameapad devices                                            */

/*                                                                         */

/***************************************************************************/

 

HRESULT CGamePad::CreateGamepads()

{

 

    // Get a mask of all currently available devices

    DWORD dwDeviceMask = XGetDevices( XDEVICE_TYPE_GAMEPAD );

 

    // Open the devices

    for( DWORD i=0; i < XGetPortCount(); i++ )

    {

        ZeroMemory( &m_InputStates[i], sizeof(XINPUT_STATE) );

        ZeroMemory( &m_Gamepads[i], sizeof(XBGAMEPAD) );

        if( dwDeviceMask & (1<<i) )

        {

            // Get a handle to the device

            m_Gamepads[i].hDevice = XInputOpen( XDEVICE_TYPE_GAMEPAD, i,

                                                XDEVICE_NO_SLOT, NULL );

 

            // Store capabilities of the device

            XInputGetCapabilities( m_Gamepads[i].hDevice, &m_Gamepads[i].caps );

        }

    } 

    return S_OK;

}

 

/***************************************************************************/

/*                                                                         */

/* Name: XBInput_GetInput()                                                */

/* Desc: Processes input from the gamepads                                 */

/*                                                                         */

/***************************************************************************/

 

VOID CGamePad::GetInput( )

{

 

 

    XBGAMEPAD* pGamepads = m_Gamepads;

 

    // TCR 3-21 Controller Discovery

    // Get status about gamepad insertions and removals. Note that, in order to

    // not miss devices, we will check for removed device BEFORE checking for

    // insertions

    DWORD dwInsertions, dwRemovals;

    XGetDeviceChanges( XDEVICE_TYPE_GAMEPAD, &dwInsertions, &dwRemovals );

 

    // Loop through all gamepads

    for( DWORD i=0; i < XGetPortCount(); i++ )

    {

        // Handle removed devices.

        pGamepads[i].bRemoved = ( dwRemovals & (1<<i) ) ? TRUE : FALSE;

        if( pGamepads[i].bRemoved )

        {

            // if the controller was removed after XGetDeviceChanges but before

            // XInputOpen, the device handle will be NULL

            if( pGamepads[i].hDevice )

                XInputClose( pGamepads[i].hDevice );

            pGamepads[i].hDevice = NULL;

            pGamepads[i].Feedback.Rumble.wLeftMotorSpeed  = 0;

            pGamepads[i].Feedback.Rumble.wRightMotorSpeed = 0;

        }

 

        // Handle inserted devices

        pGamepads[i].bInserted = ( dwInsertions & (1<<i) ) ? TRUE : FALSE;

        if( pGamepads[i].bInserted )

        {

            // TCR 1-14 Device Types

            pGamepads[i].hDevice = XInputOpen( XDEVICE_TYPE_GAMEPAD, i,

                                               XDEVICE_NO_SLOT, NULL );

 

            // if the controller is removed after XGetDeviceChanges but before

            // XInputOpen, the device handle will be NULL

            if( pGamepads[i].hDevice )

                XInputGetCapabilities( pGamepads[i].hDevice, &pGamepads[i].caps );

        }

 

        // If we have a valid device, poll it's state and track button changes

        if( pGamepads[i].hDevice )

        {

            // Read the input state

            XInputGetState( pGamepads[i].hDevice, &m_InputStates[i] );

 

            // Copy gamepad to local structure

            memcpy( &pGamepads[i], &m_InputStates[i].Gamepad, sizeof(XINPUT_GAMEPAD) );

 

            // Put Xbox device input for the gamepad into our custom format

            FLOAT fX1 = (pGamepads[i].sThumbLX+0.5f)/32767.5f;

            pGamepads[i].fX1 = ( fX1 >= 0.0f ? 1.0f : -1.0f ) *

                               max( 0.0f, (fabsf(fX1)-XBINPUT_DEADZONE)/(1.0f-XBINPUT_DEADZONE) );

 

            FLOAT fY1 = (pGamepads[i].sThumbLY+0.5f)/32767.5f;

            pGamepads[i].fY1 = ( fY1 >= 0.0f ? 1.0f : -1.0f ) *

                               max( 0.0f, (fabsf(fY1)-XBINPUT_DEADZONE)/(1.0f-XBINPUT_DEADZONE) );

 

            FLOAT fX2 = (pGamepads[i].sThumbRX+0.5f)/32767.5f;

            pGamepads[i].fX2 = ( fX2 >= 0.0f ? 1.0f : -1.0f ) *

                               max( 0.0f, (fabsf(fX2)-XBINPUT_DEADZONE)/(1.0f-XBINPUT_DEADZONE) );

 

            FLOAT fY2 = (pGamepads[i].sThumbRY+0.5f)/32767.5f;

            pGamepads[i].fY2 = ( fY2 >= 0.0f ? 1.0f : -1.0f ) *

                               max( 0.0f, (fabsf(fY2)-XBINPUT_DEADZONE)/(1.0f-XBINPUT_DEADZONE) );

 

            // Get the boolean buttons that have been pressed since the last

            // call. Each button is represented by one bit.

            pGamepads[i].wPressedButtons = ( pGamepads[i].wLastButtons ^ pGamepads[i].wButtons ) & pGamepads[i].wButtons;

            pGamepads[i].wLastButtons    = pGamepads[i].wButtons;

 

            // Get the analog buttons that have been pressed or released since

            // the last call.

            for( DWORD b=0; b<8; b++ )

            {

                // Turn the 8-bit polled value into a boolean value

                BOOL bPressed = ( pGamepads[i].bAnalogButtons[b] > XINPUT_GAMEPAD_MAX_CROSSTALK );

 

                if( bPressed )

                    pGamepads[i].bPressedAnalogButtons[b] = !pGamepads[i].bLastAnalogButtons[b];

                else

                    pGamepads[i].bPressedAnalogButtons[b] = FALSE;

               

                // Store the current state for the next time

                pGamepads[i].bLastAnalogButtons[b] = bPressed;

            }

        }

    }

 

    CheckResetCall();   

}

 

/***************************************************************************/

/*                                                                         */

/* "FIRST" function to be called, this function initilises all the         */

/* gamepads, should be called only once at the beginning                   */

/*                                                                         */

/***************************************************************************/

 

void CGamePad::InitGamePad()

{ 

      XInitDevices( 0, 0);

 

      //Create the gamepad devices    

      CreateGamepads();

}

 

/***************************************************************************/

/*                                                                         */

/* This function checks for the reset call on controller 1 (ONLY!)         */

/* Call: Left Trigger, Right Trigger and Black Button                      */

/*                                                                         */

/***************************************************************************/

void CGamePad::CheckResetCall()

{

    // Handle Reset to Dash (L Trig, R Trig + Black)

    if( m_Gamepads[0].bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER] > 0 )

    {

        if( m_Gamepads[0].bAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER] > 0 )

        {

            if( m_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_BLACK] )

            {

                LD_LAUNCH_DASHBOARD LaunchData = { XLD_LAUNCH_DASHBOARD_MAIN_MENU };

                XLaunchNewImage( NULL, (LAUNCH_DATA*)&LaunchData );

            }

        }

    }

}

 

/***************************************************************************/

 

bool CGamePad::bBlackButtonPressed(int iWhichGamePad)

{

      if( m_Gamepads[iWhichGamePad].bPressedAnalogButtons[XINPUT_GAMEPAD_BLACK] )

            return true;

      else

            return false;

}

bool CGamePad::bWhiteButtonPressed( int iWhichGamePad)

{

      if( m_Gamepads[iWhichGamePad].bPressedAnalogButtons[XINPUT_GAMEPAD_WHITE] )

            return true;

      else

            return false;

}

 

bool CGamePad::bYellowButtonPressed( int iWhichGamePad)

{

      if( m_Gamepads[iWhichGamePad].bPressedAnalogButtons[XINPUT_GAMEPAD_Y] ) // Y button

            return true;

      else

            return false;

}

bool CGamePad::bRedButtonPressed( int iWhichGamePad)

{

      if( m_Gamepads[iWhichGamePad].bPressedAnalogButtons[XINPUT_GAMEPAD_B] )  // B button

            return true;

      else

            return false;

}

bool CGamePad::bBlueButtonPressed( int iWhichGamePad)

{

      if( m_Gamepads[iWhichGamePad].bPressedAnalogButtons[XINPUT_GAMEPAD_X] ) // X Buton

            return true;

      else

            return false;

}

bool CGamePad::bGreenButtonPressed( int iWhichGamePad)

{

      if( m_Gamepads[iWhichGamePad].bPressedAnalogButtons[XINPUT_GAMEPAD_A] ) // A Button

            return true;

      else

            return false;

}

 

bool CGamePad::bStartButton( int iWhichGamePad)

{

      if(   m_Gamepads[iWhichGamePad].wButtons &  XINPUT_GAMEPAD_START)

            return true;

      else

            return false;

}

bool CGamePad::bBackButton( int iWhichGamePad)

{

      if(   m_Gamepads[iWhichGamePad].wButtons &  XINPUT_GAMEPAD_BACK)

            return true;

      else

            return false;

}

 

//---------------------------------------------------------------------------

 

float CGamePad::iAnalogStickUp( int iWhichGamePad)

{

      if(m_Gamepads[iWhichGamePad].fY1 > XBINPUT_DEADZONE)

            return m_Gamepads[iWhichGamePad].fY1;

      else

            return 0.0f;

}

float CGamePad::iAnalogStickDown(int iWhichGamePad)

{

      if(   m_Gamepads[iWhichGamePad].fY1 < -XBINPUT_DEADZONE)

            return  m_Gamepads[iWhichGamePad].fY1;

      else

            return 0.0f;

 

}

float CGamePad::iAnalogStickLeft(int iWhichGamePad)

{

      if(   m_Gamepads[iWhichGamePad].fX1 < -XBINPUT_DEADZONE)

            return  m_Gamepads[iWhichGamePad].fX1;

      else

            return 0.0f;

}

float CGamePad::iAnalogStickRight(int iWhichGamePad)

{

      if(   m_Gamepads[iWhichGamePad].fX1 > XBINPUT_DEADZONE)

            return  m_Gamepads[iWhichGamePad].fX1;

      else

            return 0.0f;

}

 

//---------------------------------------------------------------------------

 

bool CGamePad::bButtonPadUp(int iWhichGamePad)

{

      if(  m_Gamepads[iWhichGamePad].wButtons & XINPUT_GAMEPAD_DPAD_UP)

            return true;

      else

            return false;

}

bool CGamePad::bButtonPadDown( int iWhichGamePad)

{

      if(   m_Gamepads[iWhichGamePad].wButtons &  XINPUT_GAMEPAD_DPAD_DOWN)

            return true;

      else

            return false;

}

bool CGamePad::bButtonPadRight( int iWhichGamePad)

{

      if(   m_Gamepads[iWhichGamePad].wButtons &     XINPUT_GAMEPAD_DPAD_RIGHT)

            return true;

      else

            return false;

}

bool CGamePad::bButtonPadLeft( int iWhichGamePad)

{

      if(   m_Gamepads[iWhichGamePad].wButtons &     XINPUT_GAMEPAD_DPAD_LEFT)

            return true;

      else

            return false;

}

 

//--------------------------------------------------------------------------- 

 

float CGamePad::iRightStickUp( int iWhichGamePad)

{

      if( m_Gamepads[iWhichGamePad].fY2 > XBINPUT_DEADZONE)

            return  m_Gamepads[iWhichGamePad].fY2;

      else

            return 0.0f;

}

float CGamePad::iRightStickDown( int iWhichGamePad)

{

      if( m_Gamepads[iWhichGamePad].fY2 < -XBINPUT_DEADZONE)

            return  m_Gamepads[iWhichGamePad].fY2;

      else

            return 0.0f;

}

float CGamePad::iRightStickLeft( int iWhichGamePad)

{

      if( m_Gamepads[iWhichGamePad].fX2 < -XBINPUT_DEADZONE)

            return  m_Gamepads[iWhichGamePad].fX2;

      else

            return 0.0f;

}

float CGamePad::iRightStickRight( int iWhichGamePad)

{

      if( m_Gamepads[iWhichGamePad].fX2 > XBINPUT_DEADZONE)

            return  m_Gamepads[iWhichGamePad].fX2;

      else

            return 0.0f;

}

 

 

 

 

 

 

Things to remember....you can press the 2 front triggers...and the black button and it will reset your xbox.....really useful tool I thought.  And the top left joy stick lets you move the 3D cube around.  Enjoy yourself now :)

 

 

 

 

 

 

 

 

 

 

  XFactorDev.net Article



      
webmaster@xfactordev.net