Gaming

  Home arrow Gaming arrow Page 5 - Improving Input with Joysticks
Watch our Tech Videos 
Dev Hardware Forums 
Computer Cases  
Computer Processors  
Computer Systems  
Digital Cameras  
Flat Panels  
Gaming  
Hardware Guides  
Hardware News  
Input Devices  
Memory  
Mobile Devices  
Motherboards  
Networking Hardware  
Opinions  
PC Cooling  
PC Speakers  
Peripherals  
Power Supply Units  
Software  
Sound Cards  
Storage Devices  
Tech Interviews  
User Experiences  
Video Cards  
Weekly Newsletter
 
Developer Updates  
Free Website Content 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Contact Us 
Site Map 
Privacy Policy 
Support 
 USERNAME
 
 PASSWORD
 
 
  >>> SIGN UP!  
  Lost Password? 
GAMING

Improving Input with Joysticks
By: Sams Publishing
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: 3 stars3 stars3 stars3 stars3 stars / 14
    2004-09-27

    Table of Contents:
  • Improving Input with Joysticks
  • Calibrating Joysticks
  • Tracking Joystick Movements
  • Revamping the Game Engine for Joysticks
  • Developing the Joystick Code
  • Building the UFO 2 Example
  • Testing the Finished Product

  • Rate this Article: Poor Best 
      ADD THIS ARTICLE TO:
      Del.ici.ous Digg
      Blink Simpy
      Google Spurl
      Y! MyWeb Furl
    Email Me Similar Content When Posted
    Add Developer Shed Article Feed To Your Site
    Email Article To Friend
    Print Version Of Article
    PDF Version Of Article
     
     

    SEARCH DEV HARDWARE

    Improving Input with Joysticks - Developing the Joystick Code


    (Page 5 of 7 )

    As you now know, games interact with the game engine primarily through a series of functions that are called by the game engine at certain times throughout the game. In order to add joystick support to the game engine, it's important to add a new function that is going to receive joystick notifications. This function is called HandleJoystick(), and its prototype follows:

    void HandleJoystick(JOYSTATE jsJoystickState);

    The HandleJoystick() function accepts as its only argument a custom data type called JOYSTATE. The JOYSTATE data type is a custom type used to convey the state of a joystick at any given time. Listing 7.1 contains the code for the JOYSTATE data type.

    Listing 7.1 -- The JOYSTATE Data Type Includes Constant Flags that Describe the State of the Joystick

    typedef WORD  JOYSTATE;
    const JOYSTATE JOY_NONE = 0x0000L,
            JOY_LEFT = 0x0001L,
            JOY_RIGHT = 0x0002L,
            JOY_UP  = 0x0004L,
            JOY_DOWN = 0x0008L,
            JOY_FIRE1 = 0x0010L,
            JOY_FIRE2 = 0x0020L;

    The JOYSTATE data type is a WORD value capable of containing one or more constant flags that indicate(s) the state of various aspects of a joystick. For example, if the joystick handle is currently in the left position, the JOY_LEFT flag will appear in a JOYSTATE value. Multiple flags can be combined in the JOY_STATE data type, which makes sense when you consider that a joystick could simultaneously be in several of the states listed in the code.

    You learned earlier that a joystick is identified by a unique ID, which is basically a number. You also learned that a joystick movement can be simplified into a simple direction by analyzing the range of motion for the joystick handle. This is accomplished by establishing a trip rectangle for the joystick, which is an area that determines how far the joystick handle must move in order for it to count as a directional event (up, down, left, right, or a combination). The purpose of the trip rectangle is to only cause joystick movement events to be generated if the handle moves a certain minimum distance, as shown in Figure 7.5.

    morrison

    Figure 7.5 -- A trip rectangle for the joystick helps to ensure that a joystick movement event is only generated if the joystick handle moves a certain minimum distance.

    You now know that the game engine needs to keep track of two pieces of information in order to support a joystick: the joystick's ID and a trip rectangle for interpreting joystick movement. The following are the two member variables added to the game engine that account for this information:

    UINT m_uiJoystickID;
    RECT m_rcJoystickTrip;

    In addition to these member variables, the game engine also requires some support methods for managing joystick input. More specifically, it needs to properly initialize the Win32 joystick input system, which involves making sure that a joystick is connected and retrieving its ID, as well as calculating the trip rectangle. You also need methods to capture and release the joystick, which you learn about in a moment. Finally, you need a method to check the state of the joystick and convert numeric joystick movements into more meaningful directions. The following are the methods added to the game engine that accomplish all of these tasks:

    BOOL InitJoystick();
    void CaptureJoystick();
    void ReleaseJoystick();
    void CheckJoystick();

    The InitJoystick() method must be called by a game in order to initialize the joystick, retrieve its ID, and determine the trip rectangle. Its code is shown in Listing 7.2.

    Listing 7.2 -- The GameEngine::InitJoystick() Method Checks to Make Sure that a Joystick Is Present and Then Initializes It

    BOOL GameEngine::InitJoystick()
    {
     // Make sure joystick driver is present
     UINT uiNumJoysticks;
     if ((uiNumJoysticks = joyGetNumDevs()) == 0)
      return FALSE;


     // Make sure the joystick is attached
     JOYINFO jiInfo;
     if (joyGetPos(JOYSTICKID1, &jiInfo) != JOYERR_UNPLUGGED)
      m_uiJoystickID = JOYSTICKID1;
     else
      return FALSE;

     // Calculate the trip values
     JOYCAPS jcCaps;
     joyGetDevCaps(m_uiJoystickID, &jcCaps, sizeof(JOYCAPS));
     DWORD dwXCenter = ((DWORD)jcCaps.wXmin + jcCaps.wXmax) / 2;
     DWORD dwYCenter = ((DWORD)jcCaps.wYmin + jcCaps.wYmax) / 2;
     m_rcJoystickTrip.left = (jcCaps.wXmin + (WORD)dwXCenter) / 2;
     m_rcJoystickTrip.right = (jcCaps.wXmax + (WORD)dwXCenter) / 2;
     m_rcJoystickTrip.top = (jcCaps.wYmin + (WORD)dwYCenter) / 2;
     m_rcJoystickTrip.bottom = (jcCaps.wYmax + (WORD)dwYCenter) / 2;

     return TRUE;
    }

    The code in this method should look reasonably familiar from the discussion earlier where you found out how to interact with joysticks. The joystick driver is first queried to make sure that it exists. A test is then performed to make sure that the joystick is plugged in and ready to go—after which, the ID of the joystick is stored in the m_uiJoystickID member variable. The trip rectangle is then calculated as a rectangle half the size of the joystick bounds in each direction. This size is somewhat arbitrary, so you could feasibly tweak it if you wanted, meaning that the user has to push the joystick handle half of its total possible distance in a given direction in order for it to register as a directional move.

    Listing 7.3 contains the code for the CaptureJoystick() and ReleaseJoystick() methods, which are quite important. In order for a program to receive joystick input, it must first capture the joystick, which means that the joystick is only going to communicate with that program. When a program is deactivated, it's important to release the joystick so that it is no longer captured; this enables another program to capture the joystick, if necessary.

    Listing 7.3 -- The GameEngine::CaptureJoystick() and GameEngine::ReleaseJoystick() Methods Are Responsible for Capturing and Releasing the Joystick, Respectively

    void GameEngine::CaptureJoystick()
    {
     // Capture the joystick
     if (m_uiJoystickID == JOYSTICKID1)
      joySetCapture(m_hWindow, m_uiJoystickID, NULL, TRUE);
    }

    void GameEngine::ReleaseJoystick()
    {
     // Release the joystick
     if (m_uiJoystickID == JOYSTICKID1)
      joyReleaseCapture(m_uiJoystickID);
    }

    Capturing and releasing a joystick are as simple as calling the joySetCapture() and CheckJoystick() Win32 functions. Keep in mind that it's up to a program to call these two methods at the appropriate times (upon activation and deactivation) in order for joystick input to work properly.

    Listing 7.4 contains the last of the new game engine joystick methods, CheckJoystick(), which is the method that is repeatedly called by a program to analyze the current joystick state and see if anything interesting has happened.

    Listing 7.4 -- The GameEngine::CheckJoystick() Method Checks the State of the Joystick and Passes It Along to the HandleJoystick() Function

    void GameEngine::CheckJoystick()
    {
     if (m_uiJoystickID == JOYSTICKID1)
     {
      JOYINFO jiInfo;
      JOYSTATE jsJoystickState = 0;
      if (joyGetPos(m_uiJoystickID, &jiInfo) == JOYERR_NOERROR)
      {
       // Check horizontal movement
       if (jiInfo.wXpos < (WORD)m_rcJoystickTrip.left)
        jsJoystickState |= JOY_LEFT;
       else if (jiInfo.wXpos > (WORD)m_rcJoystickTrip.right)
        jsJoystickState |= JOY_RIGHT;

       // Check vertical movement
       if (jiInfo.wYpos < (WORD)m_rcJoystickTrip.top)
        jsJoystickState |= JOY_UP;
       else if (jiInfo.wYpos > (WORD)m_rcJoystickTrip.bottom)
        jsJoystickState |= JOY_DOWN;

       // Check buttons
       if(jiInfo.wButtons & JOY_BUTTON1)
        jsJoystickState |= JOY_FIRE1;
       if(jiInfo.wButtons & JOY_BUTTON2)
        jsJoystickState |= JOY_FIRE2;
      }

      // Allow the game to handle the joystick
      HandleJoystick(jsJoystickState);
     }
    }

    The CheckJoystick() method looks kind of complicated, but it's really not too bad. Understand that the idea behind this method is to quickly look at the state of the joystick, determine if enough movement has occurred to qualify as a directional movement (based on the trip rectangle), and then pass the results along to the HandleJoystick()function for game-specific joystick processing.

    The standard JOYINFO structure is used to retrieve the joystick state via the joyGetPos() function. Different members of this structure are then compared against the trip rectangle to see if the joystick movement qualifies as a directional movement. If so, the appropriate directional flag is set on a JOYSTATE variable that is eventually passed to the HandleJoystick() function. The joystick buttons are also checked, and appropriate flags are set for those as well. The bottom line is that the HandleJoystick() function gets called with information that is easily analyzed by game-specific code to determine how to react to the joystick.


    Supporting Two Joysticks in the Game Engine - The code you worked through in this section focused on adding support to the game engine for a single joystick. Likewise, the remainder of the book focuses on games that use a single joystick. However, it isn't too terribly difficult to modify the game engine to support multiple joysticks, and you might design a game that requires two joysticks. You just need to make a few changes throughout the joystick code in the game engine to support two joysticks. Here are some steps to put you on the right track in modifying the game engine:

    • Change the m_uiJoystickID member variable in the game engine into an array with two values (one ID for each joystick).

    • Everywhere you see the m_uiJoystickID variable in the game engine code, modify it to deal with two IDs instead of one—joystick 1 is JOYSTICKID1, and joystick 2 is JOYSTICKID2.

    • Add a new parameter to the HandleJoystick() function to indicate which joystick it is being called for.

    • Change the GameEngine::CheckJoystick() method to check both joysticks and call the HandleJoystick() function for each of them.

    • In your game-specific code, use the new parameter in HandleJoystick() to distinguish between the two joysticks, like this:

      void HandleJoystick(UINT uiJoystickID, JOYSTATE jsJoystickState)
      {
       if (uiJoystickID == JOYSTICKID1)
       {
        // Handle joystick 1
       }
       else
       {
        // Handle joystick 2
       }
      }

    Although not exactly trivial, this enhancement to the game engine is definitely within your abilities as a maturing Windows game developer.


    SamsThis chapter is from Beginning Game Programming, by Michael Morrison (Sams, ISBN: 0672326590). Check it out at your favorite bookstore today.

    Buy this book now.

    More Gaming Articles
    More By Sams Publishing

    blog comments powered by Disqus

    GAMING ARTICLES

    - An Ugly Side to Gaming`s Boy`s Club
    - Wii U Offers Secretly Cool Features
    - OUYA Raises Millions for Open Console Game P...
    - OUYA Kickstarter Project: Bring Back Great G...
    - WWE 13 Video Game: First Look
    - Game Review: Max Payne 3
    - The Top MUD Games
    - Game Review: Tiger Woods PGA Tour 13
    - Game Review:MLB 12 The Show
    - Game Review: Twisted Metal
    - The Top PS Vita Games
    - PlayStation Vita Review
    - Game Review: Star Wars The Old Republic
    - Game Review: WWE 12
    - Video Game Review: X-Men Destiny

    Developer Shed Affiliates

     




    © 2003-2019 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
    KEITHLEE2zdeconfigurator/configs/INFUSIONSOFT_OVERLAY.phpzdeconfigurator/configs/ OFFLOADING INFUSIONSOFTLOADING INFUSIONSOFT 1debug:overlay status: OFF
    overlay not displayed overlay cookie defined: TI_CAMPAIGN_1012_D OVERLAY COOKIE set:
    status off