Graphics Programming using Allegro

Sprite Animation using draw_sprite

Published:  September 21, 2008
by Richard G. Baldwin

File:  Allegro00170


Preface

General

This lesson is part of a series (see Resources) designed to teach you how to use Allegro to do graphics programming in C++.  My purpose in writing the series is to provide lecture and lab material for a course titled Game Development Using C++ that I teach at Austin Community College in Austin, Texas.  However, if you have stumbled upon this series and you find it useful, you are welcome to study it.

Viewing tip

I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.

Figures

Listings

Supplemental material

I recommend that you also study the other lessons in my extensive collection of online programming tutorials.  You will find a consolidated index at www.DickBaldwin.com.

Preview

In an earlier lesson dealing with the draw_sprite function (see Resources), you learned how to create images with magic pink backgrounds such as those shown in Figure 1.  Images like this are often referred to as sprites.

Figure 1. Four views of the fish sprite.

You also learned how to use the draw_sprite function to display such sprites in front of other images as shown in Figure 2. 

Figure 2. Fish sprite in front of starfish image.

Note that in Figure 2, the magic pink background that surrounds the image of the fish is transparent allowing the image of the starfish to show through.

Sprite animation program

In this lesson, I will explain a program that uses the four sprites in Figure 1 to animate a small fish swimming back and forth in front of a starfish as shown in Figure 2.  When the fish reaches either side of the aquarium, it turns and swims in the opposite direction.

The four sprites

The top right sprite in Figure 1 faces directly to the viewer's left causing the left side of the fish to be visible. The top left sprite faces directly to the viewer's right causing the right side of the fish to be visible.

The bottom right sprite in Figure 1 faces the viewer but is turned slightly to the viewer's left.  The bottom right sprite faces the viewer but is turned slightly to the viewer's right.

The two sprites on the right in Figure 1 are actually mirror images of the two sprites on the left.

Behavior of the fish sprite

When the program starts, the fish is facing in the direction of the viewer's right (top left image in Figure 1) and is swimming towards the right.  When the fish reaches the right side of the aquarium, it flips around and swims towards the viewer's left.  As it flips around, two front views of the fish visible, each for a short period of time.

When the fish reaches the left side of the aquarium, it flips around again and swims towards the viewer's right.  Once again, as the fish flips around, two front views of the fish become visible for a short period of time.

When the front views of the fish are visible, there is no horizontal motion.  During those periods, the fish pauses and looks out in the general direction of the viewer.

Controlling the fish's behavior with the mouse

If the user points inside the Allegro graphics window and clicks the left mouse button while the fish is swimming towards the right, it will flip around and swim towards the left.  If the user clicks the right mouse button while the fish is swimming towards the left, it will flip around and swim towards the right.

Clicking the right mouse button while the fish is swimming towards the right or clicking the left mouse button while the fish is swimming towards the left has no effect.

The fish continues swimming back and forth and behaving in this manner until the user presses the Esc key, at which time the program terminates.

Discussion and sample code

As usual, I will explain this program in fragments.  A complete listing of the program is provided in Listing 9 near the end of the lesson.

Declaration of working variables

The program begins in Listing 1 with the declaration and initialization of several working variables.

Listing 1. Declaration of working variables.
#include <allegro.h>
#include <math.h>

//Declare a pointer variable named buffer that can be
// used to point to a BITMAP. This will point to the main
// memory buffer containing an image of a starfish.
BITMAP *buffer = NULL;

//Declare a pointer variable named saveBuffer that will
// point to a buffer used to save a rectangular portion of
// the background image each time the fish moves so that
// the image of the fish can be erased during the next
// iteration of the animation loop.
BITMAP *saveBuffer = NULL;

//Declare a pointer variable named spriteLeftBuffer that
// will point to a buffer used to store the left-facing
// fish sprite.
BITMAP *spriteLeftBuffer = NULL;

//Declare a pointer variable named spriteRightBuffer that
// will point to a buffer used to store the right-facing
// fish sprite.
BITMAP *spriteRightBuffer = NULL;

//Declare a pointer variable named spriteFrontRightBuffer
// that will point to a buffer used to store the
// front-right facing fish sprite.
BITMAP *spriteFrontRightBuffer = NULL;

//Declare a pointer variable named spriteFrontLeftBuffer
// that will point to a buffer used to store the
// front-left facing fish sprite.
BITMAP *spriteFrontLeftBuffer = NULL;

//Note that the sizes of all the images were known before
// the program was written.
int width = 324;//width of window
int height = 330;//height of window
int spriteHalfWidth = 120/2;//half width of the sprites
int spriteHalfHeight = 90/2;//half height of the sprites

int x = 162;//initial position of the sprite
int y = 165;//initial position of the sprite

int tempX;//used to save the current location of sprite
int tempY;//used to save the current location of sprite

//Keep track of direction of motion here.
//left = 0, right = 1
int dir;

//Variables used to handle the turns.
int turnRight = 0;
int turnLeft = 0;
int turnLim = 100;//length of the turn

There is nothing new in Listing 1, so no explanation beyond the embedded comments should be required.

Beginning of the main function

The main function begins in Listing 2.

Listing 2. Beginning of the main function.
int main(){

  allegro_init();
  install_mouse();
  install_keyboard();
  set_color_depth(32);
  set_gfx_mode(GFX_AUTODETECT_WINDOWED,width,height,0,0);
  show_mouse(screen);

  //Load an image file from the current directory for the
  // background image.
  buffer = load_bitmap("starfish324x330.pcx", NULL);
  
  //Load four image files that will be turned into sprites
  // with transparent backgrounds.
  spriteLeftBuffer =
                  load_bitmap("fishleft120x90.pcx", NULL);
  spriteRightBuffer =
                 load_bitmap("fishright120x90.pcx", NULL);
  spriteFrontRightBuffer =
            load_bitmap("fishfrontright120x90.pcx", NULL);
  spriteFrontLeftBuffer =
             load_bitmap("fishfrontleft120x90.pcx", NULL);

I have explained code similar to the code in Listing 2 in earlier lessons (see Resources), so I won't repeat that explanation here.

Set the sprite backgrounds to magic pink

The images of the small fish were created using the Alice program (see Resources) as jpeg files with a background color equal to 255,0,255 (magic pink).  The program named LView (see Resources) was used to decompress the jpeg files and write the images into pcx files.

As I explained in an earlier lesson, compressing and decompressing the jpeg files can cause the colors to become slightly corrupted so that the background color in the pcx files is no longer exactly magic pink.  If the background color is not exactly magic pink, the pink background shown in Figure won't become transparent when displayed using the draw_sprite function as shown in Figure 2.

The code in Listing 3 scans the four images of the fish and changes the color of all pixels that are "close to" magic pink to be exactly equal to magic pink.

Listing 3. Set the sprite backgrounds to magic pink.
  double base = sqrt(255*255 + 255*255);
  double color = 0;
  int pixel = 0;
  int red = 0;
  int green = 0;
  int blue = 0;

  for(int row = 0;row < spriteHalfHeight*2;row++){
    for(int column = 0;column < spriteHalfWidth*2;
                                                column++){
      //First process the fish that is facing left
      pixel = getpixel(spriteLeftBuffer,column,row);
      red = getr(pixel);
      green = getg(pixel);
      blue = getb(pixel);
      color = sqrt(red*red + green*green + blue*blue);
      //Compare the actual color with the desired color.
      // If it is close, change it to the desired color.
      // Note that this causes the fish eyes to become
      // transparent, which is an undesired side effect of
      // the process.
      if(abs((int)color - (int)base) < 20){
        putpixel(spriteLeftBuffer,column,row,
                                      makecol(255,0,255));
      }//end if

      //Now process the fish that is facing right
      pixel = getpixel(spriteRightBuffer,column,row);
      red = getr(pixel);
      green = getg(pixel);
      blue = getb(pixel);
      color = sqrt(red*red + green*green + blue*blue);
      //Compare the actual color with the desired color.
      if(abs((int)color - (int)base) < 20){
        putpixel(spriteRightBuffer,column,row,
                                      makecol(255,0,255));
      }//end if
      
      //Now process the fish that is facing front-right
      pixel = getpixel(spriteFrontRightBuffer,column,row);
      red = getr(pixel);
      green = getg(pixel);
      blue = getb(pixel);
      color = sqrt(red*red + green*green + blue*blue);
      //Compare the actual color with the desired color.
      if(abs((int)color - (int)base) < 20){
        putpixel(spriteFrontRightBuffer,column,row,
                                      makecol(255,0,255));
      }//end if
      
      //Now process the fish that is facing front-left
      pixel = getpixel(spriteFrontLeftBuffer,column,row);
      red = getr(pixel);
      green = getg(pixel);
      blue = getb(pixel);
      color = sqrt(red*red + green*green + blue*blue);
      //Compare the actual color with the desired color.
      if(abs((int)color - (int)base) < 20){
        putpixel(spriteFrontLeftBuffer,column,row,
                                      makecol(255,0,255));
      }//end if

    }//end loop on row
  }//end loop on column

Although the code in Listing 3 is long and tedious, there is nothing in Listing 3 that I haven't explained in earlier lessons.  Therefore, I won't repeat the explanation here.

Prepare and execute the animation loop

Listing 4 does some preparation and then executes an animation loop in which the moveSprite function is called once during each iteration of the animation loop.

Listing 4. Prepare and execute the animation loop.
  //Create an empty bitmap and store its address in
  // saveBuffer. Make the width and height equal to the
  // size of the sprite plus two pixels.
  saveBuffer = create_bitmap(spriteHalfWidth*2 + 2,
                             spriteHalfHeight*2 + 2);
  
  //Save a rectangular area of the background at the
  // current location of the sprite. Each side of the
  // rectangle is two pixels larger than the size of the
  // sprite to allow for the possibility that the sprite
  // isn't perfectly centered in the rectangle.
  blit(buffer,saveBuffer,
       x-spriteHalfWidth-1,y-spriteHalfHeight-1,
       0,0,
       spriteHalfWidth*2+2,spriteHalfHeight*2+2);

  //Set the initial direction of motion to the right.
  dir = 1;
  //Loop until the user presses the Esc key.
  while( !key[KEY_ESC]){
    moveSprite();
  }//end while loop

  destroy_bitmap(buffer);
  destroy_bitmap(spriteLeftBuffer);
  destroy_bitmap(spriteRightBuffer);
  destroy_bitmap(saveBuffer);
  
  return 0;
}//end main
END_OF_MAIN();

Once again, I have explained code similar to the code in Listing 4 in previous lessons so I won't repeat that explanation here.

Beginning of the moveSprite function

In an earlier lesson involving the animation of a bouncing ball (see Resources), you learned how to use a switch statement to control the direction of motion of an animated object.  In another earlier lesson, you learned how to detect that the left or right mouse button has been pressed by the user.

Listing 5 uses a switch statement along with those two capabilities to control the animated motion described earlier.

Listing 5. Beginning of the moveSprite function.
void moveSprite(){
  //Save current location of sprite.
  tempX = x;
  tempY = y;

  //Control direction and orientation of the sprite.
  switch(dir){
    case 0://Direction is left.
      if((x <= spriteHalfWidth) || (mouse_b & 2)){
        //Sprite has collided with the left wall or the
        // right mouse button has been pressed.
        // Change direction to right
        dir = 1;
        //Set the turn counter to cause the front views
        // of the fish to be visible for ten
        // iterations of the animation loop.
        turnRight = turnLim;
      }else{
        //No collision, move further to left if no turn
        if(turnLeft == 0){
          --x;
        }//end if
      }//end else
    break;
    case 1://Direction is right.
      if((x >= (width-spriteHalfWidth)) || (mouse_b & 1)){
        //Sprite has collided with the right wall or the
        // left mouse button has been pressed.
        // Change direction to left
        dir = 0;
        //Set the turn counter.
        turnLeft = turnLim;
      }else{
        //No collision, move further to right if no turn
        if(turnRight == 0){
          ++x;
        }//end if
      }//end else
  }//end switch

An additional feature

Listing 5 contains one additional feature that was not included in the bouncing-ball animation.  Depending on the new direction for the fish sprite, Listing 5 sets the value of a variable named turnRight or a variable named turnLeft to the value of the variable named turnLim.

The non-zero value that is set in the variable named turnRight or the variable named turnLeft is used later to cause first one and then the other of the two bottom images in Figure 1 to become visible as the fish makes the turn.

No horizontal motion

During the period that these two images are visible, there is no horizontal motion for the fish.  In other words, the fish flips around, pauses, and looks slightly to the left or right of the viewer.  Then it flips a little further around, pauses again, and looks slightly to the left or the right of the viewer.  Finally it flips all the way around and swims off in the opposite direction.

Erase current fish image and save background

Regardless of the outcome of the code in Listing 5, the code in Listing 6 begins by erasing the current image of the fish.  This is done by drawing a rectangular section of the background image that was saved during the previous iteration at the current location of the fish.

Listing 6. Erase current fish image and save background.
  //Erase the current image of the sprite by drawing the
  // saved background over the sprite.
  blit(saveBuffer,buffer,
       0,0,
       tempX-spriteHalfWidth-1,tempY-spriteHalfHeight-1,
       spriteHalfWidth*2+2,spriteHalfHeight*2+2);

  //Save a rectangular area of the background at the new
  // location of the sprite before the sprite is drawn
  // there. Each side of the rectangle is two pixels
  // larger than the size of the sprite to allow for the
  // possibility that the sprite isn't perfectly centered
  // in the rectangle.
  blit(buffer,saveBuffer,
       x-spriteHalfWidth-1,y-spriteHalfHeight-1,
       0,0,
       spriteHalfWidth*2+2,spriteHalfHeight*2+2);

Save a new rectangular section of the background

Then the code in Listing 6 saves a rectangular section of the background image at the new location of the fish before the fish is drawn at that location.  This section of the background image will be used to erase the fish during the next iteration.

Draw the fish in the new location

Listing 7 implements the logic required to draw the fish in the new location with the correct orientation and to produce the sprite behavior described above.

Listing 7. Draw the fish in the new location.
  //Draw the sprite in the new location with the correct
  // orientation.
  if(turnRight > turnLim/2){
    //Decrement turnRight
    --turnRight;
    //Display a front-left view of the fish.
    draw_sprite(buffer,spriteFrontLeftBuffer,
                x-spriteHalfWidth-1,y-spriteHalfHeight-1);
  }else if((turnRight > 0) && (dir == 1)){
    //Decrement turnRight
    --turnRight;
    //Display a front-right view of the fish.
    draw_sprite(buffer,spriteFrontRightBuffer,
                x-spriteHalfWidth-1,y-spriteHalfHeight-1);

  }else if((turnLeft > turnLim/2) && (dir == 0)){
    //Decrement turnLeft
    --turnLeft;
    //Display a front-right view of the fish.
    draw_sprite(buffer,spriteFrontRightBuffer,
                x-spriteHalfWidth-1,y-spriteHalfHeight-1);
  }else if((turnLeft > 0) && (dir == 0)){
    //Decrement turnLeft
    --turnLeft;
    //Display a front-left view of the fish.
    draw_sprite(buffer,spriteFrontLeftBuffer,
                x-spriteHalfWidth-1,y-spriteHalfHeight-1);
  }else if(dir == 0){
    //Draw a side view of the fish.
    draw_sprite(buffer,spriteLeftBuffer,
                x-spriteHalfWidth-1,y-spriteHalfHeight-1);
  }else{
    //Draw the other side view of the fish.
    draw_sprite(buffer,spriteRightBuffer,
                x-spriteHalfWidth-1,y-spriteHalfHeight-1);
  }//end else

Once again, while the code in Listing 7 is rather long and tedious, it is straightforward and shouldn't require an explanation beyond the embedded comments.

Copy composite image to the screen and pause

Listing 8 uses code that is similar to code you have seen in previous lessons to copy the composite image of the starfish and the small fish sprite to the screen.

Listing 8. Copy composite image to the screen and pause.
  //Call the blit function to copy the off-screen buffer
  // contents to the screen.
  blit(buffer,screen,0,0,0,0,width,height);

  rest(5);//Delay for five milliseconds
}// end moveSprite function.

Finally, Listing 8 pauses for five milliseconds and then returns control back to the animation loop in Listing 4.

Listing 8 also signals the end of the moveSprite function and the end of this discussion.

Summary

In this lesson, you learned how to use capabilities from earlier lessons to animate a sprite of a small fish and to cause the fish to swim back and forth in front of a larger image of a starfish.

Complete program listing

A complete listing of the program discussed in this lesson is shown in Listing 9 below.

Listing 9. Source code for the program SpriteAnimation01.
/*Project SpriteAnimation01
This program turns four images of a fish into sprites and
causes the fish to swim back and forth in front of a large
image of a starfish.

One of the fish sprites faces to the viewer's left.Another
faces to the viewer's right. One faces the viewer but is
turned slightly to the viewer's left. The other faces the
viewer but is turned slightly to the viewer's right.

When the program starts, the fish is facing the viewers
right and swimming to the right. When it hits the right
side of the aquarium, it flips around and swims to the
viewer's left. As it flips around, two front views of the
fish become visible.

When the fish hits the left side of the aquarium, it
flips around and swims to the viewer's right. Once again,
as it flips around, two front views of the fish become
visible.

If the user clicks the left mouse button while the fish is
swimming toward the right, it will flip around and swim
toward the left.

If the user clicks the right mouse button when the fish is
swimming toward the left, it will flip around and swim
toward the right.

Clicking the right mouse button while the fish is
swimming toward the right or clicking the left mouse
button while the fish is swimming toward the left has no
effect.

The fish continues swimming back and forth until the user
presses the Esc key.
*/

#include <allegro.h>
#include <math.h>

//Declare a pointer variable named buffer that can be
// used to point to a BITMAP. This will point to the main
// memory buffer containing an image of a starfish.
BITMAP *buffer = NULL;

//Declare a pointer variable named saveBuffer that will
// point to a buffer used to save a rectangular portion of
// the background image each time the fish moves so that
// the image of the fish can be erased during the next
// iteration of the animation loop.
BITMAP *saveBuffer = NULL;

//Declare a pointer variable named spriteLeftBuffer that
// will point to a buffer used to store the left-facing
// fish sprite.
BITMAP *spriteLeftBuffer = NULL;

//Declare a pointer variable named spriteRightBuffer that
// will point to a buffer used to store the right-facing
// fish sprite.
BITMAP *spriteRightBuffer = NULL;

//Declare a pointer variable named spriteFrontRightBuffer
// that will point to a buffer used to store the
// front-right facing fish sprite.
BITMAP *spriteFrontRightBuffer = NULL;

//Declare a pointer variable named spriteFrontLeftBuffer
// that will point to a buffer used to store the
// front-left facing fish sprite.
BITMAP *spriteFrontLeftBuffer = NULL;

//Note that the sizes of all the images were known before
// the program was written.
int width = 324;//width of window
int height = 330;//height of window
int spriteHalfWidth = 120/2;//half width of the sprites
int spriteHalfHeight = 90/2;//half height of the sprites

int x = 162;//initial position of the sprite
int y = 165;//initial position of the sprite

int tempX;//used to save the current location of sprite
int tempY;//used to save the current location of sprite

//Keep track of direction of motion here.
//left = 0, right = 1
int dir;

//Variables used to handle the turns.
int turnRight = 0;
int turnLeft = 0;
int turnLim = 100;//length of the turn
//------------------------------------------------------//

void moveSprite(){
  //Save current location of sprite.
  tempX = x;
  tempY = y;

  //Control direction and orientation of the sprite.
  switch(dir){
    case 0://Direction is left.
      if((x <= spriteHalfWidth) || (mouse_b & 2)){
        //Sprite has collided with the left wall or the
        // right mouse button has been pressed.
        // Change direction to right
        dir = 1;
        //Set the turn counter to cause the front-left
        // view of the fish to be visible for ten
        // iterations of the animation loop.
        turnRight = turnLim;
      }else{
        //No collision, move further to left if no turn
        if(turnLeft == 0){
          --x;
        }//end if
      }//end else
    break;
    case 1://Direction is right.
      if((x >= (width-spriteHalfWidth)) || (mouse_b & 1)){
        //Sprite has collided with the right wall or the
        // left mouse button has been pressed.
        // Change direction to left
        dir = 0;
        //Set the turn counter.
        turnLeft = turnLim;
      }else{
        //No collision, move further to right if no turn
        if(turnRight == 0){
          ++x;
        }//end if
      }//end else
  }//end switch

  //Erase the current image of the sprite by drawing the
  // saved background over the sprite.
  blit(saveBuffer,buffer,
       0,0,
       tempX-spriteHalfWidth-1,tempY-spriteHalfHeight-1,
       spriteHalfWidth*2+2,spriteHalfHeight*2+2);

  //Save a rectangular area of the background at the new
  // location of the sprite before the sprite is drawn
  // there. Each side of the rectangle is two pixels
  // larger than the size of the sprite to allow for the
  // possibility that the sprite isn't perfectly centered
  // in the rectangle.
  blit(buffer,saveBuffer,
       x-spriteHalfWidth-1,y-spriteHalfHeight-1,
       0,0,
       spriteHalfWidth*2+2,spriteHalfHeight*2+2);

  //Draw the sprite in the new location with the correct
  // orientation.
  if(turnRight > turnLim/2){
    //Decrement turnRight
    --turnRight;
    //Display a front-left view of the fish.
    draw_sprite(buffer,spriteFrontLeftBuffer,
                x-spriteHalfWidth-1,y-spriteHalfHeight-1);
  }else if((turnRight > 0) && (dir == 1)){
    //Decrement turnRight
    --turnRight;
    //Display a front-right view of the fish.
    draw_sprite(buffer,spriteFrontRightBuffer,
                x-spriteHalfWidth-1,y-spriteHalfHeight-1);

  }else if((turnLeft > turnLim/2) && (dir == 0)){
    //Decrement turnLeft
    --turnLeft;
    //Display a front-right view of the fish.
    draw_sprite(buffer,spriteFrontRightBuffer,
                x-spriteHalfWidth-1,y-spriteHalfHeight-1);
  }else if((turnLeft > 0) && (dir == 0)){
    //Decrement turnLeft
    --turnLeft;
    //Display a front-left view of the fish.
    draw_sprite(buffer,spriteFrontLeftBuffer,
                x-spriteHalfWidth-1,y-spriteHalfHeight-1);
  }else if(dir == 0){
    //Draw a side view of the fish.
    draw_sprite(buffer,spriteLeftBuffer,
                x-spriteHalfWidth-1,y-spriteHalfHeight-1);
  }else{
    //Draw the other side view of the fish.
    draw_sprite(buffer,spriteRightBuffer,
                x-spriteHalfWidth-1,y-spriteHalfHeight-1);
  }//else

  //Call the blit function to copy the off-screen buffer
  // contents to the screen.
  blit(buffer,screen,0,0,0,0,width,height);

  rest(5);//Delay for five milliseconds
}// end moveSprite function.
//------------------------------------------------------//

int main(){

  allegro_init();
  install_mouse();
  install_keyboard();
  set_color_depth(32);
  set_gfx_mode(GFX_AUTODETECT_WINDOWED,width,height,0,0);
  show_mouse(screen);

  //Load an image file from the current directory for the
  // background image.
  buffer = load_bitmap("starfish324x330.pcx", NULL);
  
  //Load four image files that will be turned into sprites
  // with transparent backgrounds.
  spriteLeftBuffer =
                  load_bitmap("fishleft120x90.pcx", NULL);
  spriteRightBuffer =
                 load_bitmap("fishright120x90.pcx", NULL);
  spriteFrontRightBuffer =
            load_bitmap("fishfrontright120x90.pcx", NULL);
  spriteFrontLeftBuffer =
             load_bitmap("fishfrontleft120x90.pcx", NULL);
  
  //The fish images were created using Alice as jpg files
  // with a background color equal to 255,0,255. However,
  // the color gets slightly corrupted in the conversion
  // from jpg to pcx.
  //Scan the images of the fish and make all pixels that
  // are close to 255,0,255 exactly equal 255,0,255.
  // Otherwise, those pixels won't be transparent.
  double base = sqrt(255*255 + 255*255);
  double color = 0;
  int pixel = 0;
  int red = 0;
  int green = 0;
  int blue = 0;

  for(int row = 0;row < spriteHalfHeight*2;row++){
    for(int column = 0;column < spriteHalfWidth*2;
                                                column++){
      //First process the fish that is facing left
      pixel = getpixel(spriteLeftBuffer,column,row);
      red = getr(pixel);
      green = getg(pixel);
      blue = getb(pixel);
      color = sqrt(red*red + green*green + blue*blue);
      //Compare the actual color with the desired color.
      // If it is close, change it to the desired color.
      // Note that this causes the fish eyes to become
      // transparent, which is an undesired side effect of
      // the process.
      if(abs((int)color - (int)base) < 20){
        putpixel(spriteLeftBuffer,column,row,
                                      makecol(255,0,255));
      }//end if

      //Now process the fish that is facing right
      pixel = getpixel(spriteRightBuffer,column,row);
      red = getr(pixel);
      green = getg(pixel);
      blue = getb(pixel);
      color = sqrt(red*red + green*green + blue*blue);
      //Compare the actual color with the desired color.
      if(abs((int)color - (int)base) < 20){
        putpixel(spriteRightBuffer,column,row,
                                      makecol(255,0,255));
      }//end if
      
      //Now process the fish that is facing front-right
      pixel = getpixel(spriteFrontRightBuffer,column,row);
      red = getr(pixel);
      green = getg(pixel);
      blue = getb(pixel);
      color = sqrt(red*red + green*green + blue*blue);
      //Compare the actual color with the desired color.
      if(abs((int)color - (int)base) < 20){
        putpixel(spriteFrontRightBuffer,column,row,
                                      makecol(255,0,255));
      }//end if
      
      //Now process the fish that is facing front-left
      pixel = getpixel(spriteFrontLeftBuffer,column,row);
      red = getr(pixel);
      green = getg(pixel);
      blue = getb(pixel);
      color = sqrt(red*red + green*green + blue*blue);
      //Compare the actual color with the desired color.
      if(abs((int)color - (int)base) < 20){
        putpixel(spriteFrontLeftBuffer,column,row,
                                      makecol(255,0,255));
      }//end if

    }//end loop on row
  }//end loop on column

  //Create an empty bitmap and store its address in
  // saveBuffer. Make the width and height equal to the
  // size of the sprite plus two pixels.
  saveBuffer = create_bitmap(spriteHalfWidth*2 + 2,
                             spriteHalfHeight*2 + 2);
  
  //Save a rectangular area of the background at the
  // current location of the sprite. Each side of the
  // rectangle is two pixels larger than the size of the
  // sprite to allow for the possibility that the sprite
  // isn't perfectly centered in the rectangle.
  blit(buffer,saveBuffer,
       x-spriteHalfWidth-1,y-spriteHalfHeight-1,
       0,0,
       spriteHalfWidth*2+2,spriteHalfHeight*2+2);

  //Set the initial direction of motion to the right.
  dir = 1;
  //Loop until the user presses the Esc key.
  while( !key[KEY_ESC]){
    moveSprite();
  }//end while loop

  destroy_bitmap(buffer);
  destroy_bitmap(spriteLeftBuffer);
  destroy_bitmap(spriteRightBuffer);
  destroy_bitmap(saveBuffer);
  
  return 0;
}//end main
END_OF_MAIN();

 

Resources

 


Copyright

Copyright 2008, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP).  His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments.  (TI is still a world leader in DSP.)  In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

Baldwin@DickBaldwin.com

-end-