email sol follow sol rss feed of the blog wishlist Sol::Tutorials

Sol's Graphics for Beginners

(ch08.cpp)

(prebuilt win32 exe)

08 - Some Interactivity

(Last revised 9. August 2005)

Feel free to make a copy of the project, or continue from the last one.

In this part we implement keyboard controls and a very simple physics model for the player object.

I'm calling the player's motion and reaction to the world 'physics', even if they're not following the physics rules of the real world. Even pac-man and frogger had "physics" of sorts - even if they're not in par with half-life 2. The more 'real' the physics model is, the more intuitive it tends to be, but one shouldn't forget that the main point of games is to be fun to play.

This leads to one of the hazards of making a game like this: when you build it, you tend to become rather good in playing it. Thus, you should always use external help in figuring out if the game is too difficult, too hard to control, and simply too frustrating.

Anyway, back to work.

First, we need a couple new constants. Paste these under the other #define lines.


// Player's thrust value
#define THRUST 0.1f
// Slowdown due to friction, etc.
#define SLOWDOWN 0.99f

These constants will be used to control the player's ball (which will use the rather simple physics model).

Next, we need a bunch of new variables. Paste them under the player's position variables.


// Player's motion vector
float gXMov;
float gYMov;

// Player's key status
int gKeyLeft;
int gKeyRight;
int gKeyUp;
int gKeyDown;

The player's motion vector will be added to player's current position on every iteration. Thus, for example, if the vector is 0,0, the player doesn't move; if the vector is 1,0, the player will move to the positive direction on X-axis, i.e. to the right.

The gKey variables contain the current state of player's cursor keys; the values are either 0 for not pressed or 1 for pressed.

Next, add the following lines to the init() function to initialize our new variables:


  gXMov = 0;
  gYMov = 0;

  gKeyLeft = 0;
  gKeyRight = 0;
  gKeyUp = 0;
  gKeyDown = 0;

Now that the variables are set up, we'll put them to use. Paste these near the beginning of render(), under the SDL_GetTicks() line, but before the SDL_MUSTLOCK() one:


  if (gKeyLeft) gXMov -= THRUST;
  if (gKeyRight) gXMov += THRUST;
  if (gKeyUp) gYMov -= THRUST;
  if (gKeyDown) gYMov += THRUST;

  gXMov *= SLOWDOWN;
  gYMov *= SLOWDOWN;

  gXPos += gXMov;
  gYPos += gYMov;

Now, every time render() gets called, we're adding or substracting from the motion vector based on which of the cursor keys are held down. Note that if you hold both left and right, the value will be first substracted and then added back, which will result (more or less) in the same value which we started off from.

("More or less", since floating point values are, by design, inaccurate; nevertheless, even if the result isn't exactly the same as the value we started from, the difference is insignificant in this case).

After the thrust has been added, we multiply the motion vector by the slowdown factor. This will cause the ball to slow down and, if no keys are pressed, to eventually stop.

Finally, we're adding the motion vector to the current position, causing the ball to move.

As the last thing in this chapter, we need to change the main() function to adjust the gKey variables based on the keyboard events. Here's the new main loop:


  // Main loop: loop forever.
  while (1)
  {
    // Render stuff
    render();

    // Poll for events, and handle the ones we care about.
    SDL_Event event;
    while (SDL_PollEvent(&event)) 
    {
      switch (event.type) 
      {
      case SDL_KEYDOWN:
        switch (event.key.keysym.sym)
        {
        case SDLK_LEFT:
          gKeyLeft = 1;
          break;
        case SDLK_RIGHT:
          gKeyRight = 1;
          break;
        case SDLK_UP:
          gKeyUp = 1;
          break;
        case SDLK_DOWN:
          gKeyDown = 1;
          break;
        }
        break;

      case SDL_KEYUP:          
        switch (event.key.keysym.sym)
        {
        case SDLK_ESCAPE:
          // If escape is pressed, return (and thus, quit)
          return 0;
        case SDLK_LEFT:
          gKeyLeft = 0;
          break;
        case SDLK_RIGHT:
          gKeyRight = 0;
          break;
        case SDLK_UP:
          gKeyUp = 0;
          break;
        case SDLK_DOWN:
          gKeyDown = 0;
          break;
        }
        break;

      case SDL_QUIT:
        return(0);
      }
    }
  }

Compile and run. Try to control the ball using cursor keys.

Depending on your machine speed, the ball is either very slow, very fast, or something in between. This is because the game is currently "frame rate locked" - the speed of the game depends on the frame rate.

We could fix this by tweaking the THRUST and SLOWDOWN values, but that wouldn't solve the problem. First off, the frame rate is different on just about every PC out there. Second, the speed is also different between the debug and the release builds of the application. Third, we'll be adding more stuff, which will eventually slow things down somewhat.

Another way to solve the problem would be to lock the framerate - don't let it run faster than, say, 60 frames per second. That solution still won't fix it for the machines that can't reach 60 frames per second.

A better solution shall be introduced in 09 - Frame-Rate Independence.

Having problems? Improvement ideas? Just want to discuss this tutorial? Try the forums!

Any comments etc. can be emailed to me.

Site design & Copyright © 2017 Jari Komppa
Possibly modified around: June 01 2010