Lab5.doc

advertisement
Lab 5
Advanced Blitz Graphics
Pre-requisites
Read Chapter 7, 8, 9
Objectives
Translating ships
Detecting collisions
Animating Explosions
Dealing with multiple enemy fighters
Vocabulary
adding velocity to move tie
bounce vs rollover
detecting collision w/beam
damaged tie
reducing hitpoints
explosion
many tie fighters—lists
music?
AI – evasive strategy
Discussion and Procedure
This lab will bring our Star Wars demonstration program to a close. Next week we will
cover 3D Graphics. Today we are going to make the TIE fighters move, respond to laser
beams, explode, and multiply into vast swarms of evil intent!! Hang on for the ride, it's
all systems go!
Part 1. Adding velocity to move the Tie fighter
Start with the program StarWars4.bb, which we developed in the last class. This program
uses page flipping to speed up the animation, and lets the X-wing fire lasers toward a
common intersection point. The X-wing moves with the arrow keys. But we are not really
able to attack anything yet, and the Tie fighter does not move.
1. In this step, we're going to add member variables to the ship type to allow us to
represent velocity (speed) moving in the x and y directions. We will call these fields
vx and vy:
1
Type Ship
Field x,y ;the position of the ship
Field vx,vy ;the velocity of the ship
Field hitpoints ;how many hits left
End Type
 Add
2. When we initialize the Tie fighter we can add the following lines to give the ship an
initial random velocity:
Global enemy.ship = New ship
enemy\x = Rand(0,800)
enemy\y = Rand(0,50)
enemy\vx = Rand(-3,3)
enemy\vy = Rand(1,5)
enemy\hitpoints = 3
 Add
 Add
This means the Tie ship can be moving left or right (vx of -3 to 3) but will always head
down (vy of 1 to 5). You can modify these numbers to change the initial settings of the
ships velocity.
3. Now that we have defined the field and stock values into the variables, we can start to
modify the ship's position inside the main game loop. The x-position can be modified
with the statement x=x+vx and similarly for the y position.
If KeyDown(UPKEY)
player\y=player\y - 5
EndIf
If KeyDown(LEFTKEY)
player\x=player\x - 5
EndIf
If KeyDown(RIGHTKEY)
player\x=player\x + 5
EndIf
If KeyDown(DOWNKEY)
player\y=player\y + 5
EndIf
enemy\x= enemy\x + enemy\vx
enemy\y= enemy\y + enemy\vy
 Add
 Add
4. Better yet, since the main loop is getting cluttered let's make a function called
UpdatePosition( ) and copy all the statements from the above example code block
into it:
2
Function UpdatePosition()
If KeyDown(UPKEY) …
…ALL statements from previous example code block…
enemy\y = enemy\y + enemy\vy
End Function
5. And put a function call to UpdatePosition( ) at the appropriate place in the main game
loop. This is a practice that will serve you well in the future – cleaning up your code
using functions.
NOTES
A) Try modifying the initial random velocity settings of the enemy ship to x of -10
to 10 and y of -5 to 5. Then change to something you prefer.
B) Try changing the initial x, y position to random values as well: 0 to 800 in x, 0
to 600 in y
Part 2. Bounce vs Rollover
Now that you have a moving TIE fighter, you have to deal with what happens when the
ship goes off screen. You could just leave it off screen and not worry about it. You
could make it "roll over" to the other side of the screen, or you could make it "bounce"
off the edge back into the middle of the screen. In this section will explore how to set up
rollover verses bounce.
The rollover effect simply checks if the ship's position is out of bounds, and resets the
coordinate so it appears at the other edge. Games like asteroids use this method to give
the illusion of open space yet keeping the main objects engaged onscreen.
6. At the bottom of the UpdatePosition() function, add the lines marked "add" below,
which take care of the x-coordinate of the enemy:
enemy\x= enemy\x + enemy\vx
enemy\y= enemy\y + enemy\vy
If enemy\x>800 Then
enemy\x=0
EndIf
If enemy\x<0 Then
enemy\x=800
EndIf
ADD
ADD
ADD
ADD
ADD
ADD
NOTES
A) Add your own code to handle rollover in the vertical (y) coordinate.
B) Better yet, put this code into a function called Rollover() and replace the code in
UpdatePosition( ) with a function call to Rollover().
3
7. To model the BOUNCE effect, the test is similar but instead of resetting the x or y
position, we flip the sign on the velecity (x or y, depending on which edge is being
crossed). The following code sets up a Bounce( ) funciton to handle the bounce effect
on the x-axis. To use this code, comment out any reference or function call to the
Rollover code from above. Add this function to the bottom of the file, then put a
function call to it inside UpdatePosition()
Function Bounce()
If enemy\x>800 Or enemy\x<0
enemy\vx = -enemy\vx
EndIf
End Function
Then
NOTES
A) Notice how the code can be simplified with a combination test of both x>800 or
x<0 since the end result—reversing the velocity—is the same.
B) Add your own code to handle bouncing in the vertical (y) coordinate.
C) Now you can choose—Rollover or Bounce—simply by changing a function call
inside UpdatePosition()…another great use of functions.
Part 3. Using collision( ) and the damaged TIE image
We now have a TIE fighter that bounces or rolls over the edges, and an X-wing in pursuit
that can fire its laser beam. To allow them to interact, we need to tell if there is a collision
between the laser beam and the center of the TIE image.
8. Inside the Display function, we have already (last week) added code to check if the
spacebar is pressed, and draw red lines if it is:
If KeyDown(SPACE) Then
; DRAW LASER BEAMS
Color 255, 0, 0
; red = 255, 0, 0
Line player\x-40, player\y-30, player\x-5, player\y-80
Line player\x+35, player\y-30, player\x-5, player\y-80
Oval player\x-7, player\y-80, 5, 5, 1
Color 255,255,255
; white= 255,255,255 black= 0,0,0
EndIf
9. To see if there is a hit, simply add the marked lines to the if-statement as shown:
If KeyDown(SPACE) Then
; DRAW LASER BEAMS
Color 255, 0, 0
; red = 255, 0, 0
Line player\x-40, player\y-30, player\x-5, player\y-80
Line player\x+35, player\y-30, player\x-5, player\y-80
Oval player\x-7, player\y-80, 5, 5, 1
Color 255,255,255
; white= 255,255,255 black= 0,0,0
4
If Collision(player\x-7, player\y-80, enemy\x, enemy\y) Then ADD
Print "A Hit!"
ADD
Stop
ADD
EndIf
ADD
EndIf
NOTES
A) You can adjust the tolerance on your collision detection by modifying this line in the
Collision function:
If Distance(x,y,x1,y1) < 10 Then
B) The 10 is the size (radius) of the collision region. Making it larger makes it easier to
hit the TIE fighter.
The above code makes the program stop whenever you hit the TIE fighter. This is good
for debugging purposes to check where the laser is when a hit occurs. As for the game, a
more dramatic possibility (discovered by Qing Xu) is to switch the TIE fighter image for
one showing "damage" in red (like it's glowing red hot).
10. To make this work, you need to load in a new image, damagedTie4.bmp supplied in
the Lab5 Directory:
Global tieimg=LoadImage("Tie4black.bmp")
Global damagedtieimg=LoadImage("damagedTie4.bmp")
 ADD
11. Then modify your code in the Display( ) function to overlay the damaged TIE image
on the original image:
If Collision(player\x-7, player\y-80, enemy\x, enemy\y) Then
Print "A Hit!"
 DELETE
Stop
 DELETE
DrawImage damagedtieimg, enemy\x, enemy\y  ADD
EndIf
By the way, this is just one way of checking collisions. There is an entire chapter,
Chapter 9, that covers many different ways of dealing with collisions between bitmap
images.
Part 4. Checking hitpoints and the exploding animation
The next step is to entertain our destructive impulses by making the TIE fighter explode
after we've hit it with the laser a certain number of times. This is going to allow us to
explore animation because we will get to make a little film clip on how an explosion
should look. It will be crude, and you can certainly modify it with your own artistic
talents, but it will be a good start.
Since we don't want the enemy ship to explode the first time we headed with the laser,
we'll need to use another field in the Ship Type to keep track of how many times we hit
the ship. Well, it turns out we already have such a variable. It's called hitpoints.
5
If you look at the code where we're initializing the value for the enemy ship, you'll see we
already set the hitpoints field to 3:
Global enemy.ship = New ship
enemy\x = Rand(0,800)
enemy\y = Rand(0,50)
enemy\vx = Rand(-3,3)
enemy\vy = Rand(1,5)
enemy\hitpoints = 3
*** CHANGE NOTHING!!
***
12. What we're going to do is modify the collision detection code and add statements that
remove a point from hitpoints every time there is a collision. To blow up the ship,
we'll add another if statement to check whether hitpoints has reached zero and
respond accordingly.
Function Display()
…statements not shown…
If Collision(player\x-7, player\y-80, enemy\x, enemy\y) Then
DrawImage damagedtieimg, enemy\x, enemy\y
enemy\hitpoints = enemy\hitpoints – 1
 ADD
EndIf
EndIf
If enemy\hitpoints <= 0 Then
 ADD
Print "Boom"
 ADD
Stop
 ADD
EndIf
 ADD
End Function
NOTES
A) You may find that only 3 hitpoints allows a single hit before the ship goes boom. what
can you do to make the enemy ship survive longer?
Now for the explosion. In order to get an idea how animation works, try running the
demo08-01.bb and demo08-02.bb programs and then look at the staticboy.bmp and
animatedboy.bmp Images. What you can see is that an animated bitmap is a sequence of
images pact one after another inside a .bmp picture file. The program simply instructs
the computer which frame of the sequence to display at any given time.
In order to create an exploding TIE animation, we're going to need to work in Microsoft
Paint. If you're short on time, just simply use the ExplosionAnim.bmp file provided.
Otherwise, you can try to create your own exploding animation using the following
instructions.
13. Before we start, right-click on the damagedtie4.bmp file and note its size under
Properties/Summary (123 x 89). Do the same for explosionStart.bmp (264 x 148).
6
What we're going to do, is make a panel of images morphing from damaged TIE, to
the Full explosion (and maybe a tapering off if you like). However, since the images
are of different size, we'll make all the panels the same size as the largest one, in other
words, the full explosion.
14. Open the damagedtie4.bmp and explosionStart.bmp files in Paint and tile them so
you can see both at the same time.
15. Calculate 264x8 = 2112, the width of the new animation. Stretch the explosion image
out to that width, keeping the height at 148. Easier said than done, you have to keep
grabbing the lower right corner and stretching it a few pixels at a time.
16. Copy the Explosion image 7 more times, filling up the panes with a total of eight
copies. Or just use explosionAnim1.bmp.
17. using all the graphics technique you can muster, copy over reduced images of the
explosion, placing them on to the TIE fighters and redrawing the red lines as needed.
18. Save the file as MyExplosionAnim.bmp and modify the statements below
accordingly (they refer to explosionAnim.bmp which is provided for you).
Now we can modify our program to make use of the animation we just created.
19. First we have to load the animated image sequence right where we load all the other
images at the top of the program file:
Global dstarimg=LoadImage("DeathTrench.bmp")
Global dotfieldimage = CreateImage(LENGTH,HEIGHT)
;Load the animated image of explosion
Global explodingtie = LoadAnimImage("explosionAnim.bmp",264,148,0,8)
 ADD
 ADD
20. Then, in order to sequence frames during the explosion, we need to add another field
to the Ship Type to keep track of which frame we're supposed to show at any given
time.
Type Ship
Field
Field
Field
Field
End Type
x,y ;the position of the ship
vx,vy ;the position of the ship
hitpoints ;how many hits left
frame ; frame number used to display explosion
 ADD
21. Then when we create a ship, we will set the frame to 0, meaning we're ready to start
the animation at the beginning:
Global player.ship = New ship
7
…statements not shown…
player\hitpoints = 3
player\frame = 0
 ADD
Global enemy.ship = New ship
…statements not shown…
enemy\hitpoints = 10
enemy\frame = 0
 ADD
The next step is tricky. We need to add statements in the Display function that handle the
drawing of the exploding fighter. Specifically, when the hit points drops below zero, it's
time to launch the animation. But we have to keep the rest of the game going—if we
stopped everything to do the whole animation the game would look funny, everything
else would be static while the ship exploded. In reality, we want to slip in the correct
image from the eight slides while the game is running, and then make the ship disappear
completely.
22. The modification is shown below. What we're doing, is first, drawing the animation
frame indicated by the current value of the enemy\frame variable. Then adding one to
the frame variable so the next time we see the next frame. Then we have to check if
the animation is finished. If the frame variable is 8 ( or > 7), it's done. How do we
make the ship disappear? Well, there's a number of possibilities. In this case, we
move the ship way off the screen (X position 1000) and we set the horizontal velocity
to 0 so it can never come back. And we set the hitpoints to 1 so it never tries to run
the animation again:
If enemy\hitpoints <= 0 Then
Print "Boom"
 DELETE
Stop
 DELETE
DrawImage explodingtie, enemy\x, enemy\y, enemy\frame
enemy\frame = enemy\frame + 1
If enemy\frame > 7 Then
enemy\x = 1000
enemy\vx=0
enemy\hitpoints=1
EndIf
EndIf
ADD
ADD
ADD
ADD
ADD
ADD
ADD
OK, that should do it. Run the game, try to knock out a TIE fighter, and observe your
handiwork. But don't get too relaxed, because here comes…
Part 5. The Imperial Fleet—using a List of EnemyShips to represent many TIE
fighters
8
OK, so this part may not make a lot of sense. It uses a data structure called a list which is
something we cover in advanced C++ (CSIS 10B). The syntax is fairly odd looking as
well. Basically, we are going to modify the code to create a set of Tie fighters and
wherever we processed one enemy, we are now going to process the set.
The first thing we have to do is create a new data type to separate the enemy ships from
the player's ship.
23. Simply copy the type definition for the ship Type and paste it below, then change the
name to EnemyShip
Type Ship
Field
Field
all of the
Field
Field
End Type
 COPY
x,y ;the position of the ship
 COPY
vx,vy ;the position of the shipThen we have to create
ships we want
hitpoints ;how many hits left
 COPY
frame ; frame number being used to display  COPY
 COPY
Type EnemyShip
PASTE (Change name)
Field x,y ;the position of the ship
PASTE
Field vx,vy ;the position of the ship PASTE
Field hitpoints ;how many hits left
PASTE
Field frame ; frame number being used to display PASTE
End Type
PASTE
24. Then, we have to create all the ships we want using a for loop. To do this, we take
the code that created the regional enemy ship, and place a for loop around it. Inside
the for loop we create a new ship and when we are done, we say next, which repeats
the loop as many times as we want to. The loop is controlled by the counter going
from 0 to 10 (gives us 11 enemy ships). If you want more, change the number 10 to a
largernumber.
For counter= 0 To 10
enemy.EnemyShip=New EnemyShip
Global enemy.ship = New ship
enemy\x = Rand(0,800)
enemy\y = Rand(0,50)
enemy\vx = Rand(-3,3)
enemy\vy = Rand(1,5)
enemy\hitpoints = 10
enemy\frame = 0
Next
 ADD
 ADD
 DELETE
 ADD
9
25. Once we've created our fleet of enemy ships, we have to modify the rest of our code
to process the whole set instead of just one. To do this, we have to surround all the
enemy processing statements with a for-each-next loop. The display function will
look like below. Notice we've added three for loops, one to display the basic TIE
image for all the ships, one to check for collisions with the laser beam, and one to run
the explosion animation. Use copy-paste to paste the For enemy.EnemyShip =
Each EnemyShip Continued going through the code
Function Display()
; DrawImage dstarimg, 400,300
TileImage dotfieldimage
For enemy.EnemyShip = Each EnemyShip
 ADD
DrawImage tieimg, enemy\x, enemy\y
Next
 ADD
…statements not shown…
Color 255,255,255
; white= 255,255,255 black= 0,0,0
For enemy.EnemyShip = Each EnemyShip
 ADD
If Collision(player\x-7, player\y-80, enemy\x, enemy\y) Then
DrawImage damagedtieimg, enemy\x, enemy\y
enemy\hitpoints = enemy\hitpoints – 1
EndIf
Next
 ADD
EndIf
For enemy.EnemyShip = Each EnemyShip
 ADD
If enemy\hitpoints <= 0 Then
DrawImage explodingtie, enemy\x, enemy\y, enemy\frame
enemy\frame = enemy\frame + 1
If enemy\frame > 7 Then
enemy\x = 1000
DELETE
enemy\vx=0
DELETE
enemy\hitpoints=1
DELETE
Delete enemy
ADD
EndIf
EndIf
Next
 ADD
End Function
26. Continue going through the code adding the same for-each-next statements around all
the enemy processing steps. This is how the UpdatePosition function should look:
Function UpdatePosition()
If KeyDown(UPKEY)
…statements not shown…
If KeyDown(DOWNKEY)
player\y=player\y + 5
10
EndIf
For enemy.EnemyShip = Each EnemyShip
enemy\x= enemy\x + enemy\vx
enemy\y= enemy\y + enemy\vy
Next
Bounce()
 ADD
 ADD
End Function
27. This is how the Rollover function should look:
Function Rollover()
For enemy.EnemyShip = Each EnemyShip  ADD
…statements not shown…
Next
 ADD
End Function
28. And finally, this is how the Bounce function should look
Function Bounce()
For enemy.EnemyShip = Each EnemyShip
…statements not shown…
Next
End Function
 ADD
 ADD
You should now see a fleet of enemies, that you can knock out one by one.
29. However, when they are all deleted, you can add a final message using a
CheckGameOver() function
Function CheckGameOver()
For enemy.EnemyShip = Each EnemyShip
If enemy <> Null Then
Return 0
EndIf
Next
Return 1
End Function
And put a function call in the main game loop:
While Not KeyHit(1)
…statements not shown…
UpdatePosition()
If CheckGameOver() = 1 Then
Print " Congratulations LUKE!!"
 ADD
 ADD
11
Stop
EndIf
Wend
 ADD
 ADD
Congratulations! You can now start your X-wing pilot training program. This brings us
to the end of the Star Wars demonstration. By now you probably have a number of ideas
for modifying the code. For instance, just think about what would be involved in having
the enemies fire back at the player.
If you like, you can also trying switching back some of the code that we have comments
about. For instance, bring back the death star image instead of the star background. The
code is still in the program, only commented out. You can also switch from bounce to
rollOver and see how that affects the behavior of the game. Game programming is a very
challenging field, And you shouldn't feel discouraged if you can't succeed in making
changes to these sophisticated programs. The way to go about programming is to start
out small and work your way up. If you're interested in game programming, you can take
CSIS 10A C++ or CSIS 55 Visual Basic and learn programming very thoroughly, so you
can return to Blitz Basic and have a better sense of what to do.
Good luck and have fun – next week we tackle 3D Graphics!!!
12
Download