PC Gaming
  Home arrow PC Gaming arrow Page 7 - Controlling Games with the Keyboard an...
Dev Hardware Forums 
Computer Cases  
Computer Processors  
Computer Systems  
Digital Cameras  
Flat Panels  
Hardware Guides  
Hardware News  
Input Devices  
Memory  
Mobile Devices  
Motherboards  
Networking Hardware  
Opinions  
PC Cooling  
PC Gaming  
PC Speakers  
Peripherals  
Power Supply Units  
Software  
Sound Cards  
Storage Devices  
Tech Interviews  
User Experiences  
Video Cards  
Mobile Linux 
APP Generation ROI 
IBM® developerWorks 
Sun Developer Network 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us Get Paid 
Request Media Kit
Contact Us 
Site Map 
Privacy Policy 
Support 
 USERNAME
 
 PASSWORD
 
 
  >>> SIGN UP!  
  Lost Password? 
PC GAMING

Controlling Games with the Keyboard and Mouse
By: Sams Publishing
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: 2 stars2 stars2 stars2 stars2 stars / 30
    2004-10-11

    Table of Contents:
  • Controlling Games with the Keyboard and Mouse
  • Taking a Look at User Input Devices
  • Mouse and Joystick
  • Tracking the Mouse
  • Revamping the Game Engine for Input
  • Sprucing Up the Bitmap Class
  • Building the UFO 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
     
     
    ADVERTISEMENT


    Controlling Games with the Keyboard and Mouse - Building the UFO Example


    (Page 7 of 8 )

    In order to really get a feel for how keyboard and mouse input works in games, it's helpful to work through a complete example. The remainder of this chapter focuses on an example called UFO, which is a suitable follow-up to the Crop Circles example from Chapter 3. Although this program isn't technically a game, it's by far the closest thing you've seen to a game yet. It involves a flying saucer that you control with the keyboard and/or mouse. You're able to fly the flying saucer around a bitmap background image. Perhaps most important is the fact that the UFO program demonstrates how good of a feel you can create for game controls. More specifically, the arrow keys on the keyboard are surprisingly responsive in the UFO program.

    Although you haven't really learned about animation yet, the UFO example makes use of animation to allow you to fly the flying saucer. Fortunately, the program is simple enough that you can get by without knowing the specifics about animation. All you really need to know is that you can alter the position of a bitmap image to simulate movement on the screen. This occurs thanks to the game engine, which redraws the bitmap every game cycle. So, by altering the position of an image and redrawing it repeatedly, you create the effect of movement. The UFO example reveals how this task is accomplished, as well as how the keyboard and mouse fit into the picture.


    Note - You learn the details of how animation works in Chapter 9, "Making Things Move with Sprite Animation."


    Writing the Program Code

    The header file for the UFO example lays the groundwork for the meat of the program, which carries out the details of the flying saucer animation and user input. Listing 5.1 contains the code for the UFO.h header file, which declares global variables used to control the flying saucer.

    Listing 5.1 The UFO.h Header File Declares Global Variables Used to Keep Track of the Flying Saucer

    #pragma once
    //————————————————————————————————-
    // Include Files
    //————————————————————————————————-
    #include <windows.h>
    #include "Resource.h"
    #include "GameEngine.h"
    #include "Bitmap.h"
    //————————————————————————————————-
    // Global Variables
    //————————————————————————————————-
    HINSTANCE  g_hInstance;
    GameEngine* g_pGame;
    const int  g_iMAXSPEED = 8;
    Bitmap*   g_pBackground;
    Bitmap*   g_pSaucer;
    int     g_iSaucerX, g_iSaucerY;
    int     g_iSpeedX, g_iSpeedY;

    The first thing of interest in this code is the g_iMAXSPEED constant, which establishes the maximum speed of the flying saucer. The speed of the flying saucer is how many pixels it can travel in a given direction in each game cycle. So, the value of the g_iMAXSPEED constant means that the flying saucer can never travel more than 8 pixels in a horizontal or vertical direction in a game cycle.

    The g_pBackground and g_pSaucer global variables store the two bitmaps used in the program, which correspond to a night sky background image and the flying saucer image. The remaining variables pertain to the flying saucer and include its XY position and XY speed. The XY position of the flying saucer is specified relative to the game screen. The XY speed, on the other hand, simply tells the program how many pixels the flying saucer should be moved per game cycle; negative values for the speed variables indicate that the flying saucer is moving in the opposite direction.

    With the global variables in place, we can move on to the game functions. The first game function to consider is GameInitialize(), which creates the game engine and establishes the frame rate. The frame rate for the program is set to 30 frames per second. This is a relatively high frame rate for games, but it results in much smoother motion for the flying saucer, as you soon find out.

    Next on the game function agenda is the GameStart() function, which creates and loads the flying saucer bitmaps, as well as sets the initial flying saucer position and speed (Listing 5.2).

    Listing 5.2 The GameStart() Function Performs Startup Tasks for the UFO Example

    void GameStart(HWND hWindow)
    {
    // Create and load the background and saucer bitmaps
    HDC hDC = GetDC(hWindow);
    g_pBackground = new Bitmap(hDC, IDB_BACKGROUND, g_hInstance);
    g_pSaucer = new Bitmap(hDC, IDB_SAUCER, g_hInstance);
    // Set the initial saucer position and speed
    g_iSaucerX = 250 - (g_pSaucer->GetWidth() / 2);
    g_iSaucerY = 200 - (g_pSaucer->GetHeight() / 2);
    g_iSpeedX = 0;
    g_iSpeedY = 0;
    }

    The GameStart() function is used to initialize data pertaining to the program, such as the bitmaps and other global variables. The flying saucer position is initially set to the middle of the game screen, and then the speed of the saucer is set to 0 so that it isn't moving.

    You might think that a program with an animated flying saucer cruising over a background image would require a complex GamePaint() function. However, Listing 5.3 shows how this simply isn't the case.

    Listing 5.3 The GamePaint() Function Draws the Background and Flying Saucer Bitmaps

    void GamePaint(HDC hDC)
    {
    // Draw the background and saucer bitmaps
    g_pBackground->Draw(hDC, 0, 0);
    g_pSaucer->Draw(hDC, g_iSaucerX, g_iSaucerY, TRUE);
    }

    As the code reveals, the GamePaint() function for the UFO program is painfully simple; all the function does is draw the background and flying saucer bitmaps. The background bitmap is drawn at the origin (0, 0) of the game screen, whereas the flying saucer is drawn at its current position. Notice that TRUE is passed as the last argument to the Draw() method when drawing the flying saucer, which indicates that the saucer is to be drawn with transparency using the default transparent color (magenta).

    Figure 5.1 shows the flying saucer bitmap image, including the transparent color filled around the saucer; I realize that you're seeing this image in black and white on the printed page, but you can either visualize the hot purple transparent color or open the Saucer.bmp file for yourself from the accompanying CD-ROM.

    morrison

    Figure 5.1-- The flying saucer bitmap image uses the default transparent color (magenta) in the filled area around the saucer to indicate where the image is transparent.

    The GameCycle() function is a little more interesting than the others you've seen because it is actually responsible for updating the position of the flying saucer based on its speed. Listing 5.4 shows how this is accomplished in the code for the GameCycle() function.

    Listing 5.4 The GameCycle() Function Updates the Saucer Position and then Repaints the Game Screen

    void GameCycle()
    {
    // Update the saucer position
    g_iSaucerX = min(500 - g_pSaucer->GetWidth(), max(0, g_iSaucerX + g_iSpeedX));
    g_iSaucerY = min(320, max(0, g_iSaucerY + g_iSpeedY));
    // Force a repaint to redraw the saucer
    InvalidateRect(g_pGame->GetWindow(), NULL, FALSE);
    }

    The GameCycle() function updates the position of the flying saucer by adding its speed to its position. If the speed is negative, the saucer will move to the left and/or up, whereas positive speed values move the saucer right and/or down. The seemingly tricky code for setting the position must also take into account the boundaries of the game screen so that the flying saucer can't be flown off into oblivion. Granted, the concept of flying off the screen might sound interesting, but it turns out to be quite confusing! Another option would be to wrap the saucer around to the other side of the screen if it goes over the boundary, which is how games such as Asteroids solved this problem, but I opted for the simpler solution of just stopping it at the edges. After updating the position of the flying saucer, the GameCycle() function forces a repaint of the game screen to reflect the new saucer position.

    The flying saucer is now being drawn and updated properly, but you still don't have a way to change its speed so that it can fly. This is accomplished first by handling keyboard input in the HandleKeys() function, which is shown in Listing 5.5.

    Listing 5.5 The HandleKeys() Function Checks the Status of the Arrow Keys, Which Are Used to Control the Flying Saucer

    void HandleKeys()
    {
    // Change the speed of the saucer in response to arrow key presses
    if (GetAsyncKeyState(VK_LEFT) < 0)
    g_iSpeedX = max(-g_iMAXSPEED, --g_iSpeedX);
    else if (GetAsyncKeyState(VK_RIGHT) < 0)
    g_iSpeedX = min(g_iMAXSPEED, ++g_iSpeedX);
    if (GetAsyncKeyState(VK_UP) < 0)
    g_iSpeedY = max(-g_iMAXSPEED, --g_iSpeedY);
    else if (GetAsyncKeyState(VK_DOWN) < 0)
    g_iSpeedY = min(g_iMAXSPEED, ++g_iSpeedY);
    }

    The HandleKeys() function uses the Win32 GetAsyncKeyState() function to check the status of the arrow keys (VK_LEFT, VK_RIGHT, VK_UP, and VK_DOWN) and see if any of them are being pressed. If so, the speed of the flying saucer is adjusted appropriately. Notice that the newly calculated speed is always checked against the g_iMAXSPEED global constant to make sure that a speed limit is enforced. Even flying saucers are required to stay within the speed limit!


    Note - The GetAsyncKeyState() function is part of the Win32 API, and it provides a means of obtaining the state of any key on the keyboard at any time. You specify which key you're looking for by using its virtual key code; Windows defines virtual key codes for all the keys on a standard keyboard. Common key codes for games include VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN, VK_CONTROL, VK_SHIFT, and VK_RETURN.


    If you thought handling keyboard input in the UFO program was easy, wait until you see how the mouse is handled. To make things a little more interesting, both mouse buttons are used in this program. The left mouse button sets the flying saucer position to the current mouse cursor position, whereas the right mouse button sets the speed of the flying saucer to 0. So, you can use the mouse to quickly get control of the flying saucer; just right-click to stop it and then left-click to position it wherever you want. Listing 5.6 shows the code for the MouseButtonDown() function, which makes this mouse magic possible.

    Listing 5.6 The MouseButtonDown() Function Uses the Left and Right Mouse Buttons to Move the Flying Saucer to the Current Mouse Position and Stop the Flying Saucer, Respectively

    void MouseButtonDown(int x, int y, BOOL bLeft)
    {
    if (bLeft)
    {
    // Set the saucer position to the mouse position
    g_iSaucerX = x - (g_pSaucer->GetWidth() / 2);
    g_iSaucerY = y - (g_pSaucer->GetHeight() / 2);
    }
    else
    {
    // Stop the saucer
    g_iSpeedX = 0;
    g_iSpeedY = 0;
    }
    }

    The first step in this code is to check and see which one of the mouse buttons was pressed—left or right. I know, most PC mouse devices these days have three buttons, but I wanted to keep the game engine relatively simple, so I just focused on the two most important buttons. If the left mouse button was pressed, the function calculates the position of the flying saucer so that it is centered on the current mouse cursor position. If the right button was pressed, the speed of the flying saucer is set to 0.


    Note - If you determine that supporting two mouse buttons isn't enough for the game engine, considering that three-button mouse devices are sometimes used, feel free to modify it on your own. It primarily involves changing the third argument of the MouseButtonDown() function so that it can convey more than two values—one for each of the three mouse buttons.


    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 PC Gaming Articles
    More By Sams Publishing


     

    PC GAMING ARTICLES

    - WoW-ing Online Gamers: What to Expect From t...
    - Age of Conan Review
    - Harnessing Video Game Power for Good
    - Grand Theft Auto IV Review
    - PC Games, a Dying Breed?
    - The Art and Psychology of Gaming
    - Halo 3 Hands On
    - GTA IV: Going Too Far?
    - FEAR Combat Review
    - Prey Review
    - Elder Scrolls IV Oblivion Review
    - PS3: Playing at a Whole New Level
    - F.E.A.R. Video Game Review
    - They Don`t Have to See It to Frag It
    - Do Violent Games Make Violent People?






    © 2003-2008 by Developer Shed. All rights reserved. DS Cluster 5 hosted by Hostway
    Stay green...Green IT