Game Programming for Teens

[ LiB ]

We have used single bitmaps extensively throughout the book so far. A single bitmap only contains one frame of one static image. However, an image that supports frames contains numerous imagesimages that are usually related to one another.

Take, for example, Figure 8.1. As you can see, this is a single image.

Figure 8.1. A single static image.

Now, let's put this boy into a program.

;demo08-01.bb - A moving static image Graphics 800,600 SetBuffer BackBuffer() AutoMidHandle True playerimage = LoadImage("staticboy.bmp") Type player Field x,y End Type player.player = New player ;Create the player player\x = 400 player\y = 300 While Not KeyDown(1) ;While user does not press Esc Cls Locate 0,0 Print "X Coordinate: " + player\x Print "Y Coordinate: " + player\y If KeyDown (203) ;If player presses left player\x = player\x - 5 EndIf If KeyDown(205) ;If player presses right player\x = player\x + 5 EndIf If KeyDown (200) ;If player presses up player\y = player\y -5 EndIf If KeyDown (208) ;If player presses down player\y = player\y + 5 EndIf DrawImage playerimage, player\x,player\y Flip Wend

This program loads an image and displays it on the screen. The coordinates are changed based on the keypresses of the player: if he presses up, down, left, or right, the boy moves accordingly . Even though this program runs smoothly, it's very boring. All that you see is a moving imagethe boy doesn't even move his legs. The image almost looks as if it is floating.

To fix this problem, we are going to make the image appear to walk. To do this, we will use an image with eight frames. Figure 8.2 shows the image.

Figure 8.2. The frames of the walking image.

As you can see, each frame is slightly different from the previous frame. When we put these frames together, as we did with the main loop, we will create the effect of animation.

Some important parts of the program must change. First off, we have to load the image. Loading an animated image is not quite the same as loading a static image: for one, we use the function LoadAnimImage() instead of LoadImage() .

LoadAnimImage() is defined like this:

LoadAnimImage (filename$, width, height, first, count)

NOTE

Notice that the width and height values of each frame are exactly the same in the above example. Make sure you remember that all of the frames of an image must be the same; otherwise your program will not run.

There are a few more parameters than LoadImage() . The first parameter, filename$ , acts just as the parameter with the same name in LoadImage() . Filename$ is just the filename of the image you wish to load. The next two parameters, width and height , are the measurements of the width and height of each of the frames. For example, in Figure 8.3, the measurement of each frame is 71 x 95.

Figure 8.3. The demo08-02.bb program.

The parameter first tells which frame you want to begin loading. You almost always want to begin with the first frame, so you will set this value to 0, because, in computer languages, counting begins with 0. Rarely, you may want to load the images starting with a later frame than the first one. If this is the case, you will use a different value for first . The final parameter, count , informs LoadAnimImage() how many total frames you are loading.

Now, we can load our animated image using the function

playerimage = LoadAnimImage("animatedboy.bmp", 95,71,0,8)

Alright, loading now looks good. In the following program, demo08-02.bb, we will be creating a type with the player's x and y coordinates. We are also going to need to add another variable to the type, frame . Frame tells the program which frame should be drawn at that specific time. Following is the entire initialization section of the new program, demo08-02.bb.

;demo08-02.bb - A moving animated image Graphics 800,600 ;Set up BackBuffer() and AutoMidHandle SetBuffer BackBuffer() AutoMidHandle True ;IMAGES ;Load the animated image of the boy playerimage = LoadAnimImage("animatedboy.bmp",95,71,0,8) ;TYPES ;Load the player type Type player Field x,y ;The x and y coordinate position Field frame ;The frame that should be drawn End Type ;Create the player player.player = New player ;Give the player its starting values player\x = 400 player\y = 300 player\frame = 0

We have changed the loading call to make it load the animated image. Also, the player type now includes a field frame , which is initialized to 0.

Now we enter the main loop. In order to make the image move, we must increment the frame whenever a key is pressed. Therefore, we add the line

player\frame = player\frame + 1

under the key tests that move the player up and right, and we add

player\frame = player\frame - 1

to the tests that move the player down and left. In other words, whenever the player presses a button, the image moves to the next frame, and in doing so, seems to walk.

Of course, because there are only 8 frames total, we need to make sure that player\frame never goes above 7 (remember that frame begins at 0). We also must make sure that if the user goes below frame 0, his frame is reset to 7, so that the animated image resets itself and continues to animate. This is accomplished with this block of code.

If player\frame > 7 player\frame = 0 ElseIf player\frame < 0 player\frame = 7 EndIf

Following is the full source for the main loop.

;MAIN LOOP While Not KeyDown(1) ;Clear the screen Cls ;Position text at the top left corner of the screen Locate 0,0 Print "X Coordinate: " + player\x Print "Y Coordinate: " + player\y ;If player presses left, move him left and decrement the frame number If KeyDown (203) player\x = player\x - 5 player\frame = player\frame - 1 EndIf ;If player presses right, move him right and increment the frame number If KeyDown(205) player\x = player\x + 5 player\frame = player\frame + 1 EndIf ;If player presses up, move him up and increment the frame number If KeyDown (200) player\y = player\y -5 player\frame = player\frame + 1 EndIf ;If player presses down, move him down and decrement the frame number If KeyDown (208) player\y = player\y + 5 player\frame = player\frame - 1 EndIf ;If the frame gets too high, reset it back to zero. If player\frame > 7 player\frame = 0 ;If the frame gets too low, reset it to 3 ElseIf player\frame < 0 player\frame = 7 EndIf ;Draw the player at the correct position and the correct frame DrawImage playerimage, player\x,player\y, player\frame ;Wait a while Delay 100 Flip Wend ;END OF MAIN LOOP

And there we have it. Figure 8.3 is a screenshot from this program. There is one thing I want you to notice in the loop. See the DrawImage command? There is an extra parameter that we haven't seen before.

If you remember from long ago, the declaration of DrawImage is as follows :

DrawImage handle, x, y, [frame]

We have not used the final optional parameter until now. The [frame] parameter allows you to change which frame of an animated image is drawn, as we did in the previous program. Cool, huh?

Making Bitmaps

Now that you know how to load bitmaps, you probably want to know how to create them. First off, decide what the animated image will look like. Usually, each frame will look almost the same, with only one or two small changes.

Take a look at Figure 8.4. This image, as you can see, is a rectangle. Let's say we wanted to animate this rectangle.

Figure 8.4. A soon-to-be animated rectangle.

Now, we want to animate this image. Let's rotate it 45 degrees ( 1 / 8 of a complete turn ). It looks like Figure 8.5.

Figure 8.5. The second frame of the animated rectangle.

As you can see, this rectangle has been turned a little sideways . Now, to put these together in a bitmap, we need to use our favorite paint program. (I use Paint Shop Pro, which is included on the CD.) I created both images, and put them together in one single image. The final image is shown in Figure 8.6.

Figure 8.6. The double-framed image.

NOTE

Make sure that you put the frames back to back, with absolutely no space in between. If you happen to add space, the frames will become distorted and you will end up with a Not enough frames in image error. If your frames overlap, the program will display some of frame two in frame one, some of frame three in frame two, and so on.

Now here is the trick: the width and height of each frame is the width and height of the largest frame. In Figure 8.5, each frame is 250 pixels by 250 pixels, but only because the larger frame (frame 2) requires that size. Take a looksee the first frame? There is a lot of black space around it. The first frame is closer to 200 x 200, but it ends up larger because of the next rotated frame.

Now that we have this image ready to go, we need to write a program around it. The following listing is from demo08-03.bb. We begin with the initialization.

;demo08-03.bb - Demonstrates rotation a rectangle Graphics 800,600 ;Handle images from the center AutoMidHandle True ;Load the animated rectangles rectanglesimage = LoadAnimImage("rectangles.bmp",250,250,0,2) ;Create variable that counts how many rotations occurred rotationcount = 0

Obviously, this section just sets up the graphics and loads the image. Make sure you notice that the LoadAnimImage() command states that rectanglesimage has 2 frames, each being 250 x 250 pixels. Also, the variable rotationcount is created to count how many times the rotation occurs.

We now get on to the important part of this program.

;MAIN LOOP While Not KeyDown(1) ;Clear the screen Cls ;Position text at top left of screen Locate 0,0 ;Print the number of rotations Print "Number of Rotations: " + rotationcount ;Draw the rectangle image with the proper frame DrawImage rectanglesimage,400,300,rotationcount Mod 2 ;Increment the rotation count variable rotationcount = rotationcount + 1 ;Wait a while Delay 100 Wend ;END OF MAIN LOOP Print "Press any Key to Exit" ;Clear key buffer FlushKeys ;Wait for player to press a key before exiting. WaitKey

Okay, let's start from the top. As usual, the Cls clears the screen, so the rotation does not leave streaks. Figure 8.7 shows what the program will look like if you remove the Cls command.

Figure 8.7. Removing Cls from demo08-03.bb.

Next, the program calls the Locate function in order to display the Print command. The Print command displays how many rotations have occurred in the program using the rota- tioncount function.

The program then draws the actual image. The parameters here are pretty clear, except for the final one. As you know, the last frame is the [frame] parameter. We want the program to alternate between 1 and 2 for [frame] , and to do this, we use the Mod operator.

If you remember from long ago, the Mod operator returns the remainder of the first operand divided by the second. In other words, 1 Mod 2 returns 1, because 1 divided by 2 leaves a remainder of 1, and 2 Mod 2 returns 0, because 2 divided by 2 leaves a remainder of 0.

In other words, depending on the value of rotationcounter (if it is even or odd), it will display the first or second frame. If you wanted to expand the image to three frames, you would make the [frame] parameter equal to rotationcount Mod 3 .

The next two lines of the code update the value of rotation count and delay the program by 100 milliseconds , respectively. If you remove the Delay command, the program runs so fast that the frame changes can't even be seen!

The last part of the code readies the user for exit, except it includes a special function: FlushKeys . This function clears the buffer of any keypresses, so if the user pressed Esc

before the end of the program, the program will wait for the user to press another key before exiting.

Alright, that's how you make a bitmap. Let's go on to something else nowmovement.

Displaying Movement

If you remember the previous chapter, you will remember that we learned how to have Blitz Basic create all of our rotations for us. However, this does not always work. Sometimes, you will decide to put brightness or lighting on one area of the image, but you won't want that lighting rotated. Other times, you may want to have an image walk in numerous directions.

The first thing we need to do is to create the bitmap. We will start with the image in Figure 8.8.

Figure 8.8. The about-to-be moved image.

Okay, now that we have the base, we also need to have the animations. Since this is not going to be rotated, but rather turned around, Blitz Basic cannot do our work for us. Figure 8.9 shows the 8 frames of the image.

Figure 8.9. The 8 frames of movement.

Excellent, huh? Now we are going to put the images together into one bitmap that will be used in the program, as shown in Figure 8.10. Notice that the bitmap is split up into four sections: one section contains the animation for moving left, another for moving up, one more for moving right, and the last for moving down.

Figure 8.10. The loaded player image.

Okay, now that we have the image ready, we need to get into the program. We begin with the actual coding for demo08-04.bb. As usual, we first create the back buffer and set the graphics.

;demo08-04.bb - Demonstrates sprite movement Graphics 800,600 ;Set up backbuffer and automidhandle SetBuffer BackBuffer() AutoMidHandle True

After this, we write in the constants that will be used in the program.

;CONSTANTS ;These constants define the direction that is being faced Const DIRECTIONLEFT = 1 ;When direction is left Const DIRECTIONUP = 2 ;When direction is up Const DIRECTIONRIGHT = 3 ;When direction is right Const DIRECTIONDOWN = 4 ;When direction is down ;These constants define how many pixels are moved per frame Const MOVEX = 5 ;How many pixels moved left/right per frame? Const MOVEY = 5 ;How many pixels moved up/down per frame? ;These are key code constants Const LEFTKEY = 203, UPKEY = 200, RIGHTKEY = 205, DOWNKEY = 208

These constants are used throughout the program and are very useful. Basically, the DIRECTION* constants allow the player to have a different direction value based on which direction he is going. For example, if the user is heading up, his direction will be 2 and, if he is heading right, his direction will be 3.

The MOVE* parameters define the number of pixels the player will be moved per frame. Feel free to change them if you want.

Finally, the *KEY parameters give the key codes for Left, Up, Right, and Down. Table 8.1 summarizes these parameters.

Table 8.1. Demo08-04.bb's Constants

Constant

Value

Description

DIRECTIONLEFT

1

The direction value for the player heading left.

DIRECTIONUP

2

The direction value for the player heading up.

DIRECTIONRIGHT

3

The direction value for the player heading right.

DIRECTIONDOWN

4

The direction value for the player heading down.

MOVEX

5

The number of pixels the player can move left or right per frame.

MOVEY

5

The number of pixels the player can move up or down per frame.

LEFTKEY

203

The key code for Left.

UPKEY

200

The key code for Up.

RIGHTKEY

205

The key code for Right.

DOWNKEY

208

The key code for Down.

Alright, next we move on to the player type.

;TYPES ;The player type is used for the character on the screen Type player Field x,y ;The coordinate position Field direction ;The direction that is being faced (one of the DIRECTIONXXX constants) Field frame ;The frame that should be drawn Field image ;The image that should be drawn End Type

x and y tell the coordinate position of the player, direction identifies which direction the player is facing , and frame chooses which frame of the player image will be drawn. Image tells the program which image will be loaded and animated.

Now we need to set up the player type.

;Create the player player.player = New player ;Give the player starting variables player\x = 400 player\y = 300 player\direction = DIRECTIONLEFT player\frame = 0 ;Load the player's image player\image = LoadAnimImage("monkeyanim.bmp",48,40,0,8)

As usual, when creating a type, you must create an instance of the type by calling the New command. Here, we create player , based upon the player type. We then get into the actual fields.

The player begins existence directly in the center of the screen (400,300). I then decided to begin the player heading left, so player\direction is set to DIRECTIONLEFT . The frame is then set to 0, so that the player will begin facing the correct direction with the correct starting point.

Next, AutoMidHandle is set to true. This allows the object to be centered and displayed correctly. Notice that I did this right before the following LoadAnimImage() command. LoadAnimImage() loads the player picture with the proper parameters: each frame is 48 ? 40, and there are 8 frames (beginning with 0 and ending with 7).

Okay, now that that is over with, we move on to the actual loop. At this point, the player is facing left, and is displaying frame 0. In the game loop, we want the player to be able to move the image around.

First off, we begin the loop with some setup.

;MAIN LOOP While Not KeyDown(1) ;Clear the screen Cls ;Place the text in top-left-hand corner Locate 0,0 ;Print player info Print "Player X: " + player\x Print "Player Y: " + player\y Print "Player Direction: " + player\direction Print "Frame: " + player\frame

These lines display the values of all of the fields of the player type (besides image , of course).The Locate command ensures that the writing will occur at the top-left corner of the screen.

Now, I want to stop you for a moment. The next part of the code is going to be extremely hard to comprehend, so I'm going to only show you one part of it and explain it to you before showing you the rest.

We now have to allow the player to change the direction of the character on the screen. To do this, we first test to see what has been pressed.

If KeyDown(LEFTKEY)

Therefore, the following lines of code will only occur if the user presses left. Now we actually need to move the user left, by changing his x coordinate.

player\x = player\x MOVEX

As you might expect, this pushes the user a bit left. Next, we change the direction the user is facing.

player\direction = DIRECTIONLEFT

This just tells the computer that the player is facing left.

The next line is probably the most difficult to understand. It computes the frame that will be displayed based on the direction that the player is facing.

player\frame = (player\frame + 1 )Mod (2) + (2 * (player\direction)-2)

Whew! That's a big math problem. Let me show you what happens.

  1. player\frame is incremented by 1. In our example, player\frame, which began the program as 0, is now equal to 1.

  2. player\frame is divided by 2, and the remainder is returned using the Mod function. In our example, player\frame , which is equal to 1, is divided by 2. Since 1 / 2 leaves a remainder of 1, ( player\frame + 1 )Mod (2) returns 1.

  3. 2 multiplied by the direction of the player, minus 2, is added to the frame value. This expression gives the appropriate value of the frame depending on the direction of the player. In our example, 2 * player\direction (which is equal to 1), 2 = 0, which is added to player\frame (which, according to step 2, is equal to 1). Thus, player\frame is equal to 1.

Hopefully, most of this isn't that hard to comprehend, except for the expression 2 * player\direction 2 . Basically, think of this equation as analogous to global and local coordinates. If you remember, with global and local coordinates, you find the position of something at its own local space and add it to the position of the screen. The same thing is occurring here; you are finding what the difference in the frame should be (either 0 or 1, the local coordinates), and adding it to the 2 * player\direction 2 (between 0 and 7, the global coordinates). Table 8.2 lists all the possible values for player\frame , complete with the value of 2 * player\direction 2 for that frame.

Table 8.2. Each Frame's Values

Frame Number

Direction

2 * player\direction 2

1

1

1

1

2

2

2

3

2

3

4

3

4

5

3

5

6

4

6

7

4

7

NOTE

Make sure you understand that the expression 2 * player\direction 2 only works because there are two frames for each direction. If there were three frames for each animation (for a total of 12 frames, if there are still only 4 direc tions), the equation would be 3 * player\direction 3 . If there were five frames per direction, the expression would be 5 * player\direction 5 , and so on.

Now that you (hopefully) understand how we find the frame of the player, at least for when he moves left, let me show you the entire game loop.

;MAIN LOOP While Not KeyDown(1) ;Clear the screen Cls ;Place the text in top left hand corner Locate 0,0 ;Print player info Print "Player X: " + player\x Print "Player Y: " + player\y Print "Player Direction: " + player\direction Print "Frame: " + player\frame ;If player hits left, move him left, and find the correct direction and frame If KeyDown(LEFTKEY) player\x = player\x - MOVEX ;Move him left player\direction = DIRECTIONLEFT ;face him left player\frame = (player\frame + 1 )Mod (2) + (2 * (player\direction)-2) ;find frame ;If player hits up, move him up, and find the correct direction and frame ElseIf KeyDown(UPKEY) player\y = player\y - MOVEY ;Move him up player\direction = DIRECTIONUP ;face him up player\frame = (player\frame + 1 )Mod (2) + (2 * (player\direction)-2) ;find frame ;If player hits right, move him right, and find the correct direction and frame ElseIf KeyDown(RIGHTKEY) player\x = player\x + MOVEX ;move him right player\direction = DIRECTIONRIGHT ;face him right player\frame = (player\frame + 1 )Mod (2) + (2 * (player\direction)-2) ;find frame ;If player hits down, move him down, and find the correct direction and frame ElseIf KeyDown(DOWNKEY) player\y = player\y + MOVEY ;Move him down player\direction = DIRECTIONDOWN ;face him down player\frame = (player\frame + 1 )Mod (2) + (2 * (player\direction)-2) ;find frame EndIf ;Draw the player at correct position and frame DrawImage player\image,player\x,player\y, player\frame ;wait a (fraction of a) sec Delay 50 Flip Wend ;END OF MAIN LOOP

Cool, huh? The final parts of the program react just as you would expect them to. When you press Right, the player is moved 5 pixels to the right, as shown by the following line of code.

player\x = player\x + MOVEX

The same thing, only with y values, occurs when Up or Down is pressed.

At the end of the program, the player is drawn onscreen with the DrawImage command.

DrawImage player\image,player\x,player\y, player\frame

This draws the selected frame ( player\frame ) of the player's image ( player\image ) and the player's x and y coordinates ( player\x,player\y ).

The program ends by delaying for 50 milliseconds. Without the delay, the animation occurs very quicklysometimes so quickly, it is almost hard to see the actual movement!

Well, that's it for demo08-04.bb. Just for fun, I wrote demo08-05.bb. The program is exactly the same as demo08-04.bb, but this time the player is walking on grass instead of nothing. Check it out on the CD!

This chapter is nearly complete, so let me refresh some of the most important things to remember when creating bitmaps.

Also, remember that it is easier to understand animations when you make the bitmaps line up. For example, on demo08-04.bb (and also demo08-05.bb), I created 4 sets of 2 anima-tions. The same would be done for other rotations. For example, say you were rotating a ship 12 times. Put the first 4 rotations (from facing up to facing right) in one row, the next 4 rotations (facing right to facing down) in another row, and so on.

[ LiB ]

Категории