Creating a game application – Stage 1

Now that we can write characters to the GLCD screen, some interesting possibilities present themselves. The first one to consider is a simple character-based game application known as PONG. Pong was one of the first arcade video games featuring 2D graphics, originally marketed by ATARI Inc. (http://en.wikipedia.org/wiki/Pong). We'll develop the game in stages, as this is a good development strategy. We'll start by describing a simple recipe named Bounce with limited functionality. The idea of this recipe is just to animate a ball so that it appears to bounce around the screen. Provided we can redraw the ball more than 25 times a second (25 Hz), it will appear to move. The ball is represented by a character bitmap.

How to do it…

  1. As usual, we'll start our development by making a new folder named helloBounce_c2v0. Create a project, and configure the RTE to include software support for the Graphic LCD board feature (that is, clone the folder helloLCD_c2v0, from the previous recipe).
  2. Create a new file, enter the following code, name the file helloBounce.c, and include it in the project.
    /*--------------------------------------------------
     * Recipe:  helloBounce_c2v0
     * Name:    helloBounce.c
     * Purpose: Pong Game Prototype
     *--------------------------------------------------
     *
     * Modification History
     * 06.02.14 Created
     * 08.12.15 Updated uVision5.17 + DFP2.6.0
     *
     * Dr Mark Fisher, CMP, UEA, Norwich, UK
     *--------------------------------------------------*/
    
    #include "stm32f4xx_hal.h"
    #include "GLCD_Config.h"
    #include "Board_GLCD.h"
    
    #define wait_delay HAL_Delay
    
    /* Globals */
    extern GLCD_FONT     GLCD_Font_16x24;
    
    #ifdef __RTX
    ______________________________________________________
    /* Function Prototypes */
    void SystemClock_Config(void);
    
    /**
      * System Clock Configuration
      */
    void SystemClock_Config(void) {
    ______________________________________________________
    /**
      * Main function
      */
    int main (void) {
      unsigned int dirn = 1;
      /* initial ball position */
      unsigned int x = (GLCD_WIDTH-GLCD_Font_16x24.width)/2; 
      unsigned int y = (GLCD_HEIGHT-
                                  GLCD_Font_16x24.height)
      unsigned long num_ticks = 5;
    	
      HAL_Init ( );
      SystemClock_Config ( );
      
      GLCD_Initialize();             
      GLCD_SetBackgroundColor (GLCD_COLOR_WHITE);
      GLCD_ClearScreen (); 
      GLCD_SetForegroundColor (GLCD_COLOR_BLUE);
      GLCD_SetFont (&GLCD_Font_16x24);
      GLCD_DrawChar (x, y, 0x81); 	       /* Draw Ball */
    
      for (;;) {                             /* superloop */
        wait_delay(num_ticks);        /* update ball pstn */
        /* add code to update ball position
           and check for collisions here */ 
        GLCD_DrawChar (x, y, 0x81); 	    /* Redraw Ball */
      } /* end for */
    }
  3. Build the project (just to check that there are no syntax errors).

    Include the following code fragment in the superloop of bounce.c . This code updates the position of the ball on each iteration.

          /* update ball position */
          switch (dirn) {
            case 0: x++;
                    break;
            case 1: x++;
                    y--;
                    break;
            case 2: y--;
                    break;
            case 3: x--;
                    y--;
                    break;
            case 4: x--;
                    break;
            case 5: x--;
                    y++;
                    break;
            case 6: y++;
                    break;
            case 7: x++;
                    y++;
          }

    Extend the superloop of bounce.c by including the code fragment that is designed to detect collisions between the ball and the edges of the screen. The ball direction is changed accordingly when a collision occurs.

        /* check collision with vertical screen edge */
        if ((x==0) || 
            (x==GLCD_WIDTH-GLCD_Font_16x24.width) ) {    
          switch (dirn)                          
          {
            case 0: dirn = (dirn+4)%8;
                    break;
            case 1: dirn = (dirn+2)%8;
                    break;
            case 3: dirn = (dirn+6)%8;
                    break;
            case 4: dirn = (dirn+4)%8;
                    break;
            case 5: dirn = (dirn+2)%8;
                    break;
            case 7: dirn = (dirn+6)%8;
                   break;
          }
        }
      /* check collision with horizontal screen edge */
        if ((y==0) || 
            (y==GLCD_HEIGHT-GLCD_Font_16x24.height) ) { 
          switch (dirn) {
            case 1: dirn = (dirn+6)%8;
                    break;
            case 2: dirn = (dirn+4)%8;
                    break;
            case 3: dirn = (dirn+2)%8;
                    break;
            case 5: dirn = (dirn+6)%8;
                    break;
            case 6: dirn = (dirn+4)%8;
                    break;
            case 7: dirn = (dirn+2)%8;
                    break;
          }
        }
  4. Build the project; download and run the program. Observe the ball bouncing around the screen. Note that the argument passed to the function delay( ) controls the ball's speed. Experiment by changing the value.

How it works…

The direction of the ball is encoded by a number, 0-7, as shown in the following diagram. The ball's behavior when it strikes the edge of the screen depends on the angle of collision (in a similar manner to those on a pool table). Adding a value to the direction code (modulo-8) will change the ball's direction.

How it works…

Characters we write to the GLCD are represented by bitmaps. Each character bitmap is represented as a 16 x 24 grid of cells. Each row of cells in the grid is encoded as two bytes, represented in hexadecimal. For example, the bitmap representation of the '&' character is illustrated in the following image:

How it works…

A good bitmap representation for the ball is a 'Circle – Full' character (0x81 = 12910). We can display this character in any position on the GLCD screen using the function GLCD_DrawChar(). This function takes three args: screen coordinates (x, y), and the ASCII code for the character. The code fragment

GLCD_SetFont (&GLCD_Font_16x24);
GLCD_DrawChar (0, 0, 0x81);

will draw the ball in the top-left corner of the screen. GLCD_DrawChar ( ) interprets the ASCII character code as an index into GLCD_Font_16x24. The 'Circle – Full' character is the 97th character (of a total of 112) stored in the array named GLCD_ Font_24x16. Parameters for the font are stored in the file GLCD_Fonts.c.

GLCD_FONT GLCD_Font_16x24 = {
  16,                                   ///< Character width
  24,                                   ///< Character height
  32,                                   ///< Character offset
  112,                                  ///< Character count
  Font_16x24_h                          ///< Characters bitmaps
};

If we add the Character offset (3210) to the character's position in the character bitmap (9710), we get its code (12910).

Finally, since the character bitmap is not declared in bounce.c, we need to tell the compiler what type Font_16x24_h is, and that it is declared elsewhere. The statement

extern GLCD_FONT     GLCD_Font_16x24;

in file bounce.h achieves this. This file also uses the #define preprocessor directive to declare global constants (such as CHAR_W and CHAR_H). Conventionally, these are capitalized.

The superloop comprises statements that animate the ball by updating its position (x,y) and redrawing the bitmap. Position updates depend on direction (encoded as, 0,1,2,3,4,5,6, or 7). These eight cases are identified by the switch statement in step 7 of the recipe. Our trusty delay function provides some control over the speed of the ball. Further code in the superloop checks for collisions between the ball and the vertical and horizontal edges of the screen, and updates the balls direction appropriately. The last statement in the superloop is a further call to the function GLCD_Draw_Char() to redraw the ball in its new location. Because the bitmap represents a solid circle shape surrounded by a border of background pixels, and since the ball position is only incremented by a single pixel each time there, is no need to erase the ball before it is redrawn.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.150.89