Game Programming for Teens
[ LiB ] |
Handling the mouse is a lot easier than handling the keyboard. Just look at them: compared to the 105 keys on your keyboard, there are only 2 or 3 buttons on your mouse (maybe more, depending on the make). Thus, you only have to test the input of three keys maximum. However, when using the mouse, you also have to test the coordinate position on the screen.
Unlike a keyboard, which is ever-present, the mouse only exists onscreen at a certain location. By moving the mouse, you move the mouse cursor on your screen (usually designated by an arrow), and you change what your mouse is pointed at. This pointer technology allows you to select anything onscreen by moving your mouse to the location and clicking.
Unfortunately, Blitz Basic does not provide a mouse cursor that allows you to see where your mouse is at the current time. There is an easy way to circumvent this problem, and we take it head on in the next section.
Displaying the Mouse Cursor
At most times while you're on your computer, you use the mouse to perform whatever actions you want to err perform. Figure 10.5 shows an example of a standard mouse cursor.
Figure 10.5. A mouse cursor.
Blitz Basic does not have support for displaying mouse cursors . Obviously, we do need a mouse cursor to function; otherwise , any program that utilizes the mouse will act something like the program from demo10-07.bb. Figure 10.6 shows a screenshot from that program.
Figure 10.6. The demo10-07.bb program.
NOTE
If you happen to run your program in windowed mode (by calling Graphics xxx,yyy,zzz,2 ), the default mouse cursor, the one you see at most times while using your computer, will be shown.
Pretty stupid, huh? You have no idea where the mouse is, so the program is pretty much worthless. What we need to do is figure out a way to draw the mouse cursor.
What we are going to do is draw an image containing the mouse cursor image at the mouse's x and y coordinates. How do we begin this? First off, we make an image that we want to be used for our mouse cursor. We will use the cursor shown in Figure 10.7.
Figure 10.7. The mouse cursor.
I made the cursor white so that it can be seen against the black backgrounds often used in games . I made the cursor white inside Paint Shop Pro, which you can find on the CD.
Now that we have the mouse image, all we need to do is draw the image at the mouse's position. Before we can do that, we need to know how to find the mouse's current position. But before we can do that, we need to know one thing.
When using mouse images, it is important that you never set the mid handle to the center; instead, the handle should be at the top-left-hand corner of the image. This is because you want the user to select something from the tip of the mouse cursor, not the center. Keeping the handle may be difficult when using the function AutoMidHandle , as it sets every handle to the center automatically. The trick here is to use the function HandleImage and give it the coordinates (0,0). For example, if you have a mouse image named mouseimage , you would call HandleImage like this.
HandleImage mouseimage,0,0
By the way, in case you didn't know, HandleImage sets the handle of the image to the position you give it via x and y coordinates.
Okay, now that we have that down, we need to figure out how to find out the mouse's coordinate position. Fortunately, Blitz Basic provides two functions for this purpose.
These two functions are called MouseX() and MouseY() . Their declarations follow.
MouseX() MouseY()
What could possibly be easier? Anyway, each function returns the position of the mouse's coordinate position: MouseX() returns the mouse's x coordinate, and MouseY() returns the mouse's y coordinate.
Okay, now let's put all of this into a program. Following is the listing for demo10-08.bb. In addition to checking the mouse, I added a scrolling background, because scrolling backgrounds are cool.
;demo10-08.bb - Demonstrates drawing a mouse cursor Graphics 640,480 ;Set default drawing surface to back buffer SetBuffer BackBuffer() ;IMAGES ;Load the background and the mouse cursor backgroundimage = LoadImage("stars.bmp") mouseimage = LoadImage("mouseimage.bmp") ;Set handle to top left for mouseimage HandleImage mouseimage,0,0 ;Create an indicator variable for scrolling background scrolly = 0 ;MAIN LOOP While Not KeyDown(1) ;Scroll background a bit by incrementing scrolly scrolly = scrolly + 1 ;Tile the background TileBlock backgroundimage,0,scrolly ;Reset scrolly if the number grows too large If scrolly > ImageHeight(backgroundimage) scrolly = 0 EndIf ;Reset printing commands to top left hand corner Locate 0,0 Print "Mouse is easier to find now, huh" ;Print X and Y coordinates Print "MouseX: " + MouseX() Print "MouseY: " + MouseY() ;draw the mouse image DrawImage mouseimage,MouseX(),MouseY() ;Flip front and back buffers Flip Wend ;End of Main loop
Not too terribly difficult, eh? The DrawImage line of code draws the mouse at the mouse's current position, which is given by MouseX() and MouseY() .
We are making excellent progress! Now we know how to track and draw an object to represent the position of the mouse cursor. The two important functions to determine the position of the mouse were: MouseX() and MouseY() . We also learned how to change the mouse image with HandleImage . Next up, we're going to learn how to detect keypresses.
What Was That? Handling Mouse Keypresses
Like a keyboard, a mouse also has keys that can be clicked on the screen. You might use the mouse for many actions throughout your games. For example, say you have a side- scroller game, like Super Mario Brothers . You might allow the user to move onscreen by clicking with the left mouse button, and allow the player to jump by using the right mouse button.
Figure 10.8 shows an average mouse. Notice that the pictured mouse has a mouse wheel. Many mice have mouse wheels, and we will learn how to use the mouse wheel as well as the other two mouse buttons.
Figure 10.8. A common mouse.
Anyway, on to the functions.
MouseDown()
Blitz Basic offers mouse input functions that are similar to the keyboard input functions. The function that we will discuss in this section, MouseDown() , acts just like its keyboard counterpart KeyDown() .
MouseDown() has the declaration as follows .
MouseDown (button)
Button is the button that you are checking for: either the left mouse button, the right mouse button, or the middle mouse button. Table 10.2 lists all the possibilities for button .
Table 10.2. MouseDown()'s Button Possibilities
Button | Key Code |
---|---|
Left mouse button | 1 |
Right mouse button | 2 |
Middle mouse button | 3 |
Easy, huh? How can we use MouseDown() ? Well, for example, to test if the left mouse button was hit, you would do something like this.
If MouseDown(1) ;perform actions Endif
Whatever you want to happen when the left mouse button is hit would be placed between the If and the Endif statements.
MouseDown() returns true (1) if the mouse key was hit, and false (0) if it was not hit.
I'm neglecting to write a sample program for MouseDown() right now; instead, I will use it in a sample program with the next function: MouseHit() .
MouseHit()
I bet you can guess the difference between this function and MouseDown() , huh? While you can hold down MouseDown() , you must tap the mouse button over and over when using MouseHit() to initiate the action.
This difference is the same as is in KeyDown() versus KeyHit() , the keyboard input functions. Just like KeyHit() , MouseHit() also records the number of times you hit the button.
MouseHit() is declared like this:
MouseHit (button)
Button can be any of those listed in Table 10.2.
Anyway, let's rewrite demo10-05.bb to use mouse input. Instead of using keys to move the player's ship, the ship is located at the coordinates of the mouse. For this program, we do not need a mouse cursor, because the ship serves as a sign of the mouse's position.
Also, the mouse buttons have been changed. While pressing the left mouse button still creates a bullet, holding down the right mouse button creates a laser. Let's try it out.
Most of the program has changed, so I am going to copy the source section by section. We will begin with the initialization section of demo10-09.bb.
;demo10-09.bb - A Space Simulation with MouseDown() and KeyDown() Graphics 800,600 ;Set automidhandle to true AutoMidHandle True ;Set up Backbuffer SetBuffer BackBuffer() ;TYPES ;Bullet type = hold the information for each bullet Type bullet Field x,y ;the coordinates of the bullet Field bullettype ;LASER or NORMALBULLET (see constants) End Type ;Player type - holds the actual player Type player Field x,y ;the coordinates of the player End Type ;Create player and initialize field Global player.player = New player player\x = 400 player\y = 500 ;CONSTANTS ;The following constants are used for testing key presses (mouse and keyboard) Const ESCKEY = 1, LEFTMOUSEBUTTON = 1, RIGHTMOUSEBUTTON = 2 ;The following constants are used for the bullets, BULLET is a regular bullet, LASER is a laser Const NORMALBULLET = 1, LASER = 2 ;IMAGES playerimage = LoadImage("ship.bmp") Global bulletimage = LoadImage("bullet.bmp") Global laserimage = LoadImage("laser.bmp") backgroundimage = LoadImage("stars.bmp") HandleImage laserimage, ImageWidth(laserimage)/2, ImageHeight(laserimage) ;VARIABLES ;Create a scrolling indicator variable scrolly = 0 ;Number of times left and mouse buttons were hit Global leftmouseclicks = 0 Global rightmouseclicks = 0
Okay, let's go through this section. The program begins just as it did in demo10-09.bb with the setting of the graphics mode, the creation of the back buffer, and setting AutoMidHandle to true. In the next part, the types have changed a bit.
The bullet type looked like this in demo10-05.bb:
Type bullet Field x,y ;the coordinates of the bullet End Type
We have added a new field: bullettype . This type defines whether the bullet is a normal bullet or laser. We assign this field at the time of the bullet's creation, depending on whether the player clicks the left mouse button or the right mouse button.
The next major change in the program takes place in the constants section. As you can see, we have deleted all of the key code constants besides Esc. Esc remains because we use it to test if the program should exit in the main loop.
In the key codes place, we created a set of new constants. The first two new constants are LEFTMOUSEBUTTON and RIGHTMOUSEBUTTON . These two constants are used in the MouseHit() and MouseDown() tests later in the programthey tell the program which mouse buttons were clicked. The other two constants, NORMALBULLET and LASER , are used in the bullettype field of the bullet type. If bullettype is equal to NORMALBULLET , the bullets are regular, run-of-the-mill bullets. If bullettype is LASER , the bullet is a laser.
We loaded a new image, laserimage , which is the image of each laser bullet shot, by clicking the right mouse button. Figure 10.9 shows what the laser looks like. It is the straight line down the middle.
Figure 10.9. The laser image.
The laser is very long because it extends from one side of the screen to the other. Thus, the height of the laser is the height of the screen.
We then set the handle to the bottom center of the image with the line
HandleImage laserimage, ImageWidth(laserimage)/2, ImageHeight(laserimage)
This line may be a little difficult to understand, so let's go over it. First off, we have to know what HandleImage does.
HandleImage allows you to choose where the handling point of an image is. AutoMidHandle automatically assigns the handling point of any image to the direct center. What does the handling point do? Well, when you move the image around, it is moved by the handling point. Imagine picking up a playing card. If you pick it up in the exact center, you will notice that the card extends in all directions from your finger. This is what AutoMidHandle does. See Figure 10.10 as an example. In the figure, the handling point, which is where your finger is, is directly in the center of the card. The card's points extend in all directions from the center point. When you move your hand around, the card is still grasped from the center, and thus, the edges of the card always extend from (0,0).
Figure 10.10. AutoMidHandle on a playing card.
When using the laser image, however, we want the image to be grasped from the bottom. We will be making the laser extend from the front of the player's spaceship to the upper wall of the screen, and since it must begin right on the player, we have to set the handle to the bottom edge of the laser. Figure 10.11 shows what it would look like to set the handle to the bottom of the playing card.
Figure 10.11. The lower handle on a playing card.
HandleImage allows you to set the handle of the laser image to the coordinates you want. In the line
HandleImage laserimage, ImageWidth(laserimage)/2, ImageHeight(laserimage)
the handle is set to ImageWidth(laserimage)/2, ImageHeight(laserimage) . What does this mean? The x coordinate of the handle is located at ImageWidth(laserimage)/2 . This is half of the width of the image, which is in the center of the image. The y coordinate, ImageHeight(laserimage) , puts the handle at the bottom of the image. See Figure 10.12 for help.
Figure 10.12. The handle on the laser image.
Okay, hopefully we understand the laser image's handle now. Moving on in the initialization section of the program, we get to two new variables, leftmouseclicks and right- mouseclicks . These two variables record how many times each of their respective buttons were clicked.
Next up, we have the main loop. Let's check it out.
;MAIN LOOP While Not KeyDown(ESCKEY) ;Increment scrolling variable scrolly = scrolly + 1 ;Tile the background TileBlock backgroundimage,0,scrolly ;set up text Locate 0,0 Print "Player X: " + MouseX() Print "Player Y: " + MouseY() Print "Number of times left mouse button was hit: " + leftmouseclicks Print "Number of times right mouse button was hit: " + rightmouseclicks ;Reset the scrolling variable when it grows too large If scrolly > ImageHeight(backgroundimage) scrolly = 0 EndIf ;Test mouse buttons TestMouse() ;Update (move) each bullet UpdateBullets() ;Draw the player DrawImage playerimage, player\x, player\y ;Flip the front and back buffers Flip Wend ;END OF MAIN LOOP
This loop is almost exactly the same as the one in demo10-05.bb, except for two changes. We added some text to the screen that allows the user to know his position and how many times he has clicked the left and right mouse buttons. The second change is a change in name : TestKeys() has been changed to TestMouse() , which is the function we examine next.
;FUNCTIONS ;Function TestMouse() - Tests what mouse buttons have been pressed and where player is located Function TestMouse() ;set the player at the position of the mouse player\x = MouseX() player\y = MouseY() ;If the player hits left mouse button, create a bullet If MouseHit(LEFTMOUSEBUTTON) bullet.bullet = New bullet ;create bullet bullet\x = player\x ;place bullet at player's x coordinate bullet\y = player\y ;place bullet at player's y coordinate bullet\bullettype = NORMALBULLET ;make it a normal bullet ;increment left mouse clicks leftmouseclicks = leftmouseclicks + 1 EndIf ;If the player hits left, we will scroll the background left If MouseDown(RIGHTMOUSEBUTTON) bullet.bullet = New bullet ;create bullet bullet\x = player\x ;place bullet at player's x coordinate bullet\y = player\y ;place bullet at player's y coordinate bullet\bullettype = LASER ;make it a laser ;add number of right mouse clicks since last frame rightmouseclicks = rightmouseclicks + MouseHit(RIGHTMOUSEBUTTON) EndIf End Function
Whew, big difference, huh? This function had a massive overhaul , because we are no longer using the keyboard. The function begins by assigning the coordinates of the ship to the coordinates of the mouse using the functions MouseX() and MouseY() . If you remember, MouseX() and MouseY() return the coordinates of the mouse at the given time.
After this, we test to see if the player has hit any mouse buttons. If so, a bullet is created. Both the tests for the left and the right mouse button begin in the same way: a new bullet is created with the coordinates of the player. This creates the bullet directly under the player, giving the illusion that the player's ship actually fired the bullet. The next line marks a difference between the left mouse test and the right mouse test. If the player pressed the left mouse button, the bullet type of the bullet is set to NORMALBULLET , and if the right mouse button was pressed, the bullet type is set to LASER .
The last section of each of the tests increments either the left mouse-click counter or the right mouse-click counter, depending on what button was pressed. You can see that the actions taken to increment the counter are different in each test, and if you need help understanding why, see the accompanying note.
NOTE
Look at the end of each of the mouse input tests for both the left mouse button and the right mouse button. Do you notice how each line is different? Both lines increment their respective counters that detail how many times a laser or bullet has been fired, but they do so in different ways. The first test, MouseHit(LEFTMOUSEBUTTON) , adds 1 directly to the left mouse-click counter, whereas the second test, MouseDown(RIGHTMOUSEBUTTON) adds the return value of a MouseHit(RIGHTMOUSEBUTTON) to its counter. Why can't we just add 1 to the right mouse button counter?? Well, in the first test, we used MouseHit() to test to see if the left mouse button was clicked. If you remember, MouseHit() always returns 1 when the key (here, the left mouse key) is hit once. Because we are calling MouseHit() , we know for a fact that the key was hit once, so we add 1 to the counter. On the other hand, we use MouseDown() for the right mouse button test. MouseDown() returns 1 as long as the button is being held down, not only if the button is being pressed (like MouseHit() does). In other words, a new bullet may be created even though the key was not released and then pressed againthe new bullet is created just because the key is being held down. Because of this fact, we add KeyHit(RIGHTMOUSEBUTTON) to the counter, which will add 1 if the right key is released and then pressed again, and 0 if it is simply held down.
Anyway, we now move on to the final function: UpdateBullets() .
;Function UpdateBullets() - Moves each bullet on screen Function UpdateBullets() ;For every bullet, move it up 5 pixels. If it goes offscreen, delete it, otherwise, draw it For bullet.bullet = Each bullet bullet\y = bullet\y - 5 ;Move bullet up ;If bullet moves offscreen, delete it, otherwise, draw it onscreen. Draw laserim- age if it is a laser, bulletimage if it is a bullet If bullet\y < 0 Delete bullet ElseIf bullet\bullettype = NORMALBULLET DrawImage bulletimage, bullet\x, bullet\y ;Draw the bullet ElseIf bullet\bullettype = LASER If player\x <> bullet\x Delete bullet Else DrawImage laserimage, bullet\x, bullet\y ;Draw the laser EndIf EndIf Next ;move to next bullet End Function
This function begins by moving each bullet upward 5 pixels. The function then tests to see if the bullet is on the screen or if it has moved offscreen. If the bullet's y coordinate is less than 0, the bullet is offscreen. When this happens, the bullet is deleted using the Delete function. If the bullet wasn't deleted, the function tests to see what type the bullet is, using bullet\bullettype . If the bullet is a normal bullet, the program draws the bullet at the proper coordinates. If the bullet is a laser, the program must do a few more tests.
Because the laser follows the player around, and it stretches to the end of the screen, we do not want the player's x coordinate to be any different from the laser's x coordinate. Therefore, we test the player's x against the bullet's x using the Not Equal To operator which is <>. If player\x and bullet\x are not equal to one another, the laser is deleted. If the player's x and the bullet's x are equal to one another, the laser is drawn on the screen.
That is it for demo10-09.bb. Figure 10.13 is a screenshot taken from the program.
Figure 10.13. The demo10-09.bb program.
Alright, I hope you understand mouse input now. Before we move on to joystick input, I want to go over the middle mouse wheel.
The Middle Mouse Wheel
As you know, many mice have a middle mouse button in addition to the normal right and left mouse buttons. Often, the middle mouse button is a scrolling wheel, which can be used in programs such as Internet Explorer to scroll up and down. Blitz Basic provides support for the middle mouse wheel, both in clicking and in scrolling.
You already know how to test to see if the middle mouse button was clicked. To do this, just call MouseDown() with 3 as its parameter. You would write something like this in your program:
If MouseHit(3) ;perform actions EndIf
Not that difficult, eh? Testing to see if the mouse was scrolled is almost as easy.
Remember at the beginning of the mouse input section, where we used the two functions MouseX() and MouseY() ? If you remember, MouseX() and MouseY() gave the coordinate position of the mouse. Blitz Basic provides the function MouseZ() that tests the mouse wheel to see if it has scrolled.
The Blitz Basic program on the CD does not allow the function MouseZ() to be used. This is very unfortunate, because you cannot test to see if the mouse wheel has been scrolled on your demo program. The full version of Blitz Basic does allow the function MouseZ() to be used, however. You can buy the full version at http://www.blitzbasic.com.
The demo10-10.bb program will not work if you try to compile it from the Blitz Basic program. You will get a "Function not Found" error. The executable file however, does work, so just use that. This program shows you how you can use MouseZ() if and when you purchase the full version of Blitz Basic.
MouseZ() begins at 0 when your program begins. As you scroll the mouse wheel away from you (upward), MouseZ() increases . As you scroll the mouse wheel toward you (downward), MouseZ() increases.
Anyway, to test for what MouseZ() is, you simply call the function. There are no parameters or anything to look for. So, let's try a sample program, demo10-10.bb. This program scrolls the background 20 pixels as you scroll the mouse wheel.
;demo10-10.bb - Demonstrates use of MouseZ() ;Set up graphics and backbuffer Graphics 800,600 SetBuffer BackBuffer() ;Load images backgroundimage = LoadImage("stars.bmp") shipimage = LoadImage("ship.bmp") ;MAIN LOOP While Not KeyDown(1) ;Scroll the background 20 pixels with each mouse wheel scroll scrolly = MouseZ() * 20 ;Tile the background TileBlock backgroundimage,0,scrolly ;Draw the player DrawImage shipimage, MouseX(), MouseY() Flip Wend ;END OF MAIN LOOP
As you can see, the program sets scrolly to MouseZ() * 20 . Multiplying MouseZ() by 20 forces the scrolling variable to change by 20 pixels with each change in the mouse wheel. This means that the background will scroll faster and easier. Try changing 20 to a different number and see what happens. If you set 20 to a smaller number, you will notice that the background scrolls much slower, whereas making it larger makes the background scroll faster.
Okay, before we move on to the next section, there are a few miscellaneous mouse functions that you should know. Like FlushKeys() , Blitz Basic provides the function FlushMouse() . This function clears the computer's memory of buttons that have been pressed on the mouse.
WaitMouse() is another function that has a keyboard counterpart, WaitKeys() . This function waits for the player to press a button on the mouse before resuming the program's exe-cution.
GetMouse() can be used when you want to get a key that the player pressed, but do not know what it will be. GetMouse() has no parameters, but if a button is pressed, it returns the number of the pressed button. Therefore, if the left mouse button was pressed, 1 is returned; if the right mouse button was pressed, 2 is returned; and if the mouse wheel was pressed, 3 is returned.
Last, Blitz Basic provides the function MoveMouse() . This function has the declaration
MoveMouse x,y
This function moves the mouse to the coordinates you feed it. Therefore, if you type MoveMouse(0,0) , the mouse is moved to the top-left corner of the screen.
Alright, that is it for mouse input. Next up: joystick input.
[ LiB ] |