Game Programming for Teens

[ LiB ]

Okay, now that we have learned how to use bounding circles, let's learn how to use bounding boxes. Bounding boxes are just like bounding circles, except that instead of comparing overlapping circles, they compare overlapping rectangles. If you check out Figure 9.7, you will notice that a collision does not always occur even though a collision is reported . This is usually not a big deal, though, because the collision is pretty close.

Figure 9.7. An imperfect collision.

Unlike using bounding circles, Blitz Basic provides a way to test for collisions using bounding boxes. We will go over this in a minute, after I show you how to do it manually.

We have to use ImageHeight() and ImageWidth() again, but this time in a different way. The bounding box for our rectangle is going to be the outer edge of our image. See Figure 9.8 for an example.

Figure 9.8. A bounding box.

Now, how are we going to go about finding this bounding box? First of all, remember that when we use images, the handling point is directly in the center of the image. This is defined by AutoMidHandle . Since it is in the center, we need to get the upper and lower cor-ners to find the bounding box.

If the mid handle had been set to the top-left corner of the image, then this would be an easy problem. We would begin with the mid handle for the upper corner. The mid handle's x coordinate plus ImageWidth() would be the lower-right corner's x coordinate, and the lower-right corner's y coordinate would be the mid handle's y coordinate plus ImageHeight() .

Well, now, here's the thing. Since we aren't at the top-left-hand corner, we need to use another formula. Basically, the bounding box will have an upper-left -hand corner of:

1/2 * ImageWidth(), 1/2 * ImageHeight()

And a lower-right-hand corner of:

1/2 * ImageWidth(), 1/2 * ImageHeight().

Figure 9.9 illustrates this.

Figure 9.9. A bounding box with mid handle at the center.

How does this work? Well, AutoMidHandle sets up the handling point directly in the center of the image rectangle. We need to move the handling point to the top-left corner of the image so that we can draw a rectangle around the bitmap. Because the handling point is directly in the center, we need to move the handling point 1/2 of the height of the rectangle up, and 1/2 of the width of the rectangle left. This allows you to grab the rectangle by the top-left corner.

Okay, now, before we write our collision detection program, let's write a program that demonstrates the bounding box technique. The following program, demo09-03.bb, draws a rectangle around the bounding box of a spaceship.

;demo09-03.bb - Draws a bounding box Graphics 800,600 ;Set default backbuffer and automidhandle to true SetBuffer BackBuffer() AutoMidHandle True ;IMAGES ;Load the ship image Global shipimage = LoadImage("ship.bmp") ;Give the ship default parameters Global x = 400 Global y = 300 ;CONSTANTS ;The key code constants Const UPKEY = 200, DOWNKEY = 208, LEFTKEY = 203, RIGHTKEY = 205 ;These constants define how many pixels are moved per frame Const MOVEX = 5 Const MOVEY = 5 ;MAIN LOOP While Not KeyDown(1) ;Clear the screen Cls ;Find out if any important keys on the keyboard have been pressed TestKeys() ;Draw the bounding box around the player DrawPlayerRect() ;Draw the image of the ship DrawImage shipimage,x,y Flip Wend ;END OF MAIN LOOP ;FUNCTION DrawPlayerRect() - Draws a bounding rectangle Function DrawPlayerRect() ;find the width of the image iw = ImageWidth(shipimage) ;Find the upper-left-hand coordinates x1# = ((-ImageWidth(shipimage)/2) +x) y1# = ((-ImageHeight(shipimage)/2) + y) ;Draw the entire bounding box Rect x1#,y1#,ImageWidth(shipimage),ImageHeight(shipimage), 0 End Function ;FUNCTION TestKeys() - Tests all of the keys to see if they were hit Function TestKeys() ;If up is hit, move player up If KeyDown(UPKEY) y = y - MOVEY EndIf ;If down is hit, move player down If KeyDown(DOWNKEY) ;If down was hit y = y + MOVEY EndIf ;If left is hit, move player left If KeyDown(LEFTKEY) x = x - MOVEX EndIf ;If right is hit, move player right If KeyDown(RIGHTKEY) x = x + MOVEX EndIf End Function

To me, the most difficult thing to understand is the function DrawPlayerRect() .

DrawPlayerRect() draws the bounding box around the player's image. If you remember correctly, I said that the bounding box extends from 1/2 * ImageWidth() ,1/2 * ImageHeight() to 1/2 * ImageWidth() , 1/2 * ImageHeight() . However, the DrawPlayerRect() function seems to make the bounding box look a lot different.

;FUNCTION DrawPlayerRect() - Draws a bounding rectangle Function DrawPlayerRect() ;find the width of the image iw = ImageWidth(shipimage) ;Find the upper left hand coordinates x1# = ((-ImageWidth(shipimage)/2) +x) y1# = ((-ImageHeight(shipimage)/2) + y) ;Draw the entire bounding box Rect x1#,y1#,ImageWidth(shipimage),ImageHeight(shipimage), 0 End Function

First of all, take the variable x1# . As you can see, instead of being set to 1/2 * ImageWidth() , it is set to ImageWidth()/2 . Both 1/2 * ImageWidth() and ImageWidth()/ 2 are equal to one another. Multiplying something by 1/2 is the same as dividing something by 2. Therefore, 1/2 * ImageWidth() is the same as ImageWidth() / 2 .

Also, notice that I added the x coordinate to the rectangle when finding x1# .This puts the bounding box into the actual player spaceif I forgot to add it, the rectangle would begin at the top-left-hand corner of the screen. This is the same as global and local coordinates. Finding the bounding box is finding the local coordinates, but by adding the proper x value, you move it to the correct global coordinates. We do the same thing with the y1# variable.

Last, the Rect call may be a little confusing. Let me help you understand it by detailing the declaration of Rect .

Rect x, y, width, height, solid

Remember that? Anyway, as you know, the rectangle begins at x,y . We already figured out what x and y are in the previous two variables , x1# and y1# . We then need to figure out the width and height of the rectangle. The width and height are the width and height of the image. This is achieved by using ImageWidth() and ImageHeight() .

Of course, we don't want the rectangle to be filledit'll make the ship look ugly! So we set solid to 0, which leaves it unfilled.

By the way, there is a much easier way to grab the image by the top-left corner than using ImageHeight() and ImageWidth() . Blitz Basic provides a function named HandleImage that lets you choose where on the image you want your handle ( grabbing point) to be located. HandleImage is declared like this.

HandleImage image, x, y

To set the grabbing point to the top-left-hand corner, you would just call HandleImage as follows .

HandleImage shipimage, 0, 0.

Alright, we are now ready to check and see if an object has collided with our spaceship using bounding boxes. This program, demo09-04.bb, is the same as the one in demo09-02.bb, except it does not use bounding circles anymore. Notice that we got rid of the radius field.

Anyway, getting back to the program, we changed the TestCollisions function quite a bit.

;FUNCTION TestCollisions() - Tests the objects and the ship for collisions ;No input parameters ;Returns 1 if there was a collision, 0 if there was none Function TestCollisions() ;Test each point to see if it is within the player's radius For point.point = Each point ;Find player's bounding box x1 = -ImageWidth(player\image)/2 + player\x x2 = ImageWidth(player\image)/2 + player\x y1 = -ImageHeight(player\image)/2 + player\y y2 = ImageHeight(player\image)/2 + player\y ;If the point is within collision radius, return 1 If (point\x > x1) And (point\x < x2) And (point\y > y1) And (point\y < y2) Return 1 EndIf Next ;Move on to next point ;There were no collisions if the function makes it here, so return 0 Return 0 End Function ;END TestCollisions()

As you can see, the function begins by finding the size of the rectangle. Like what was said earlier, the bounding rectangle extends from ImageWidth()/2 + x , ImageHeight()/2 + y to ImageWidth()/2 + x , ImageHeight()/2 . The If statement tests to see if any of the points are within the bounding box, and if so, a collision is reported.

Also, one last major change. The FindRadius() and the Distance() functions are no longer necessary, so they have been deleted.

[ LiB ]

Категории