Beginning Game Programming Session 3

Great Games in Liberty BASIC

For Liberty BASIC versions 2 and 3

© Richard G. Ryles, July 2003,

Email: rryles@jeff-davis.k12.ga.us

[http://jdexchange.jeff-davis.k12.ga.us/~rryles/]


MENU

Shooting Gallery Game


Introduction

I hope you're excited about what we have been doing. If you're like me, these articles are not coming fast enough for your. But, we must learn patience. Take what you have learned so far and experiment with it and explore. If you would like to see my solutions to the problems I left you with, load up and run, in Liberty BASIC, SG2sol.bas and SC2sol.bas. Once again your sprites will probably be in different locations but your sprites should move in similar fashion.

This month we are going to take on the shooting aspect of games. This includes basing sprite locations on the locations of other sprites, event flags, and collisions. We will also set up some type of scoring during this session.

Once again, this article is divided into two different sections. The first is going to deal with the sub game and the second with the shooting gallery game. Also, this way if you are only interested in one of the games it will be easier to tell the two apart (there are some aspects covered in each game that are not covered in the other).

I've attempted to keep the file names to eight characters or less, so that those using LB version 2 will not have a problem loading the included files.

Let's get started.

Sub Command Game

What We Hope to Accomplish

We are going to cover a lot of ground this month. First we are going to base the torpedo's location upon that of our sub. Secondly, we will shoot our torpedo with the spacebar. Thirdly, we will set up a collision between the torpedo and the ship and fourth we will have the ship to drop the mine. Let's get started.

Declaration of Variables

Remember last session, we briefly hit upon declaring variables. Declaring the variables we will be using in our game will help us keep things organized and help us know which variable we are using. Many times we will want to keep up with a value that is associated with an individual entity and declaring our variables from the start helps us do that. We are also giving our variables initial values. Last session, we initially forgot to do this with the sub and when we first used the variables LB assigned our variables the value of zero, which is not what we wanted.

Load up your SubCom2.bas file or my SC2sol.bas file. Let's save it under a different name since we will be making changes to it. Go to File>>Save As… and give this file the name of SubCom3. Now we need to declare our variables. Last month we did this for the sub. We are now going to do it for the rest of the entities so that we can use the variable names when relocating them.

Find the Section III of your outline and add the following code:

Figure 1

    'III.  Initialize Variables
    sx=20:sy=75     'initial location of sub
    enemyX=-70:enemyY=200   'initial location of enemy
    shipX=500:shipY=45   'initial location of ship
    torpedoX=150:torpedoY=300   'initial location of torpedo
    mineX=600:mineY=200  'initial location of mine

Now go to Section C and make the following changes.

Figure 2

        'C.  Set Initial Location of Sprites - spritexy
    print #game.g, "spritexy sub ";sx;" ";sy  'pulled the variable values for our entities in these five lines
    print #game.g, "spritexy enemy ";enemyX;" ";enemyY
    print #game.g, "spritexy ship ";shipX;" ";shipY
    print #game.g, "spritexy torpedo ";torpedoX;" ";torpedoY
    print #game.g, "spritexy mine ";mineX;" ";mineY

Save and run your program. All of your sprites should move the same way they did before. So we have really changed nothing as far as the running of the program is concerned but we have prepared our program so that it will be easier to use in the future.

Figure 3

        'D.  Set other Sprite Attributes
    print #game.g, "spritemovexy ship -5 0"    '-5 causes the ship to move to the left
    print #game.g, "spritemovexy mine 0 6"     '6 causes the mine to move down
    print #game.g, "spritemovexy enemy 10 0"     'causes the enemy sub to move right
    'print #game.g, "spritemovexy torpedo 0 -6"      'causes the torpedo to move up

    print #game.g, "spriteorient torpedo flip"      'flips the torpedo to point up instead of down

Figure 3 above, shows the changes I made to Section D. We are moving the enemy to the right, the torpedo up and then we flipped the direction of the torpedo, it was pointing down.

Figure 4

    [TrapEnemy]
    print #game.g, "spritexy? enemy enemyX enemyY"
    if enemyX>500 then print #game.g, "spritexy enemy -70 200"
    return

    [TrapTorpedo]
        if torpedoY<-30 then print #game.g, "spritexy torpedo 150 300"
    return

Figure 4 shows the variable names being used in the two new sprite traps that you should have set up in your SubCom2.bas. Remember that your X's and Y's may be different.

Save your work.

Launching the Torpedo

In preparing for shooting let's get the torpedo to launch with the spacebar. First though, I want to reduce the size of the torpedo to make it a little more realistic.

Figure 5

        'D.  Set other Sprite Attributes
    print #game.g, "spritemovexy ship -5 0"    '-5 causes the ship to move to the left
    print #game.g, "spritemovexy mine 0 6"     '6 causes the mine to move down
    print #game.g, "spritemovexy enemy 10 0"     'causes the enemy sub to move right
    'print #game.g, "spritemovexy torpedo 0 -6"      'causes the torpedo to move up

    print #game.g, "spriteorient torpedo flip"      'flips the torpedo to point up instead of down
    print #game.g, "spritescale torpedo 50"     'reduced the size of the torpedo by 50%

As seen in Figure 6 we have set up a torpedo flag. This flag tells us if a torpedo is on the screen. If it is then we will set up things where we cannot shoot another torpedo until the first one goes off the screen or hits another entity.

Figure 6

    'III.  Initialize Variables
    sx=20:sy=75     'initial location of sub
    enemyX=-70:enemyY=200   'initial location of enemy
    shipX=500:shipY=45   'initial location of ship
    torpedoX=150:torpedoY=300   'initial location of torpedo
    mineX=250:mineY=45  'initial location of mine
    TorpFlag=0 'Torpedo Flag, if this equals one then we have
                    'a torpedo on the screen

In Figure 7 I changed the name of the branch where a keypress takes us to [KeyCheck]. Since that branch will now have several functions the name is a little more general.

Figure 7

    'VI.  Initialize Keyboard and Mouse Events
    print #game.g, "setfocus"   'causes #game.g to be the active window for keypresses and mouse movements
    print #game.g, "when characterInput [KeyCheck]"  'when a key is pressed goto the KeyCheck branch
    wait 'this first wait in the program will not allow the code below to be executed.  From now on the
            'timer, keyboard and mouse are in control of what happens.

Notice in Figure 8 that the “ “ has a space between them. We are using the spacebar to shoot the torpedo. We are also jumping to another branch in an effort to keep our code as uncluttered as possible. Change the branch label from [MoveSub] to [KeyCheck] under Section IX of your code. Then add the new line as indicated in Figure 8.

Figure 8

    [KeyCheck]
    k$=Inkey$   'assigning the Inkey$ another name - shortens what we have to type in

    if k$=" " then gosub [ShootTorpedo]

Copy the code from Figure 9 at the end of Section VI, after the “wait” command, since this is still part of the code called by keyboard events.

Figure 9

    [ShootTorpedo]
    if TorpFlag=0 then
        TorpFlag=1
        torpedoY=sy
        torpedoX=sx+32
    end if
    return

The code in Figure 9 sets thing up so that we can shoot only one torpedo at a time but also lets the torpedo go off the top of the screen before we shoot another one (TorpFlag is what we use to do these two things). If we didn't do this here then every time we hit the space bar the torpedo would start over again. In later sessions we will deal with multiple torpedoes. When the spacebar is pressed, if TorpFlag is 0 (no torpedo on the screen) then we set TorpFlag to 1 meaning that there is now a torpedo on the screen. We are also setting the torpedo's beginning location at our ship location (that is why we used sx and sy. Adding 32 to sx moves the missile over to the center of the sub).

Add the gosub from Figure 10 to your [TimerBranch]. Once again, this is in an effort to keep our code as organized as possible.

Figure 10

    [TimerBranch]   'the timer causes the program to come here every 10th of a second and run the following
    gosub [TrapShip]
    gosub [TrapMine]
    gosub [TrapEnemy]
    gosub [TrapTorpedo]
    gosub [MoveTorpedo]
    gosub [draw]
    wait    'stops when it gets here, waits until told to do something else

Figure 11 shows some changes I made to the [TrapTorpedo] branch, in Section X, as well as the new [MoveTorpedo] branch. Make the changes to [TrapTorpedo] and add the [MoveTorpedo] branch.

Figure 11

    [TrapTorpedo]
        if torpedoY<-30 then
            torpedoX=150:torpedoY=300
            TorpFlag=0
        end if
    return

    [MoveTorpedo]
    if TorpFlag=1 then torpedoY=torpedoY-6
    print #game.g, "spritexy torpedo ";torpedoX;" ";torpedoY
    return

Under [TrapTorpedo], once the torpedo has gone off screen, we set it to a location off the screen area (where there are no other sprites) and set our TorpFlag back to 0. This now allows us to shoot another torpedo the next time the spacebar is pressed. The [MoveTorpedo] branch says that if we do have a torpedo on the screen then at each drawsprites subtract 6 from it's Y value (this causes the torpedo to move up). Finally we print the torpedo's location according to it's torpedoX and torpedoY values which may or may not change depending upon whether TorpFlag is 0 or 1.

Save your work and run the program. Now the torpedo should only shoot if you press the spacebar. You should also not be able to shoot another torpedo until the first one has gone off the top of the screen. Hopefully everything will work correctly. If not make sure you have made no typos.

Collision with the Ship

The next big step is collisions. As our sub shoots the torpedo we want the program to tell us when the torpedo and ship collide. When this collision occurs we can tell the program to do many things. Let's begin by setting up the code to tell us when a collision occurs. First add a new gosub in the [TimerBranch] as shown in Figure 12.

Figure 12

    'VII.  Timer Branch
    [TimerBranch]   'the timer causes the program to come here every 10th of a second and run the following
    gosub [TrapShip]
    gosub [TrapMine]
    gosub [TrapEnemy]
    gosub [TorpShipCollision]
    gosub [TrapTorpedo]
    gosub [MoveTorpedo]
    gosub [draw]
    wait    'stops when it gets here, waits until told to do something else

Next add the [TorpShipCollision] branch to Section X of your code as in Figure 13. This will cause the program to check for collisions each timer cycle.

Figure 13

    [TorpShipCollision]
    print #game.g, "spritecollides torpedo list$"
    print list$
    return

The spritecollides command is new. Go to the LB Help File and read up on it if you want a little more information. Basically we are telling Liberty BASIC here to place the name of any sprite that touches our torpedo sprite into a string variable called list$. And, no there is nothing special about list$. You could name it kill$ if you wanted. The next line simply prints the contents of the list$ variable to the mainwindow.

And lastly, comment out the nomainwin at the beginning of your program. This will allow us to see what is in the list$ variable.

Figure 14

    'I.  Window Setup
    nomainwin
    WindowWidth = 500:WindowHeight =320
    UpperLeftX=Int((DisplayWidth-WindowWidth)/2)        'these two lines center the window on the screen
    UpperLeftY=Int((DisplayHeight-WindowHeight)/2)

Once you have done the above steps run your program. Use the spacebar to shoot the torpedo. When the torpedo is shot you will see the word sub come up on the main window. When you hit the ship the word ship should show up in the main window. See Figure 15 below.

Figure 15

sub

ship
ship
ship
ship
ship
ship

If you see sx= and sy= some numbers you can delete those statements. They are under the [KeyCheck] branch.

Once things are working correctly here uncomment nomainwin and delete the “print list$” statement. Save your work.

Removing Sprites on Collision

Let's cause the ship and torpedo to disappear when they collide. In later sessions we will replace these sprites with sprites of explosions and burning ships.

Figure 16

    [TorpShipCollision]
    print #game.g, "spritecollides torpedo list$"
    if list$= "ship" then
        print #game.g, "spritexy ship ";-100;" ";sy
        torpedoX=150:torpedoY=300
        TorpFlag=0
        playwave "boom.wav", async
    end if
    return

Modify your [TorpShipCollision] branch so that it looks like Figure 16. Once again, if our torpedo collides with the ship the LB places the word “ship” in a variable called list$. If list$ contains only the word “ship” then we move the ship off screen, -100 in this case. The reason that I moved the ship to the left side is so that our trapping routine will notice that the ship is less than 50 and restart the ship on the right side. Next we move the torpedo back to it's start location and then set the TorpFlag to zero which tells us that there is no longer an active torpedo on our screen. The playwave command then plays the boom.wav for us and the async simply lets everything else keep going while the sound is playing. You can play any wave that you want here. Just simply make sure the wave is in the same folder as your game and replace the wave name I have with the one you want.

Save your work and run the program. The ship and the torpedo should both disappear when they collide and the boom.wav should play. If things don't work right then go back and make sure you have typed in everything correctly.

Ship Drops Mine

We want the mine to look like the ship is dropping it. You already have done similar coding with the sub and torpedo, the exception here is that the program is in control. Here we want the ship to drop a new mine each time the old one goes off the bottom of the screen.

Figure 17

    'III.  Initialize Variables
    sx=20:sy=75     'initial location of sub
    enemyX=-70:enemyY=200   'initial location of enemy
    shipX=500:shipY=45   'initial location of ship
    torpedoX=150:torpedoY=300   'initial location of torpedo
    mineX=600:mineY=200  'initial location of mine
    TorpFlag=0 'Torpedo Flag, if this equals one then we have
                    'a torpedo on the screen

Change the initial location of the mine to off screen as indicated in Figure 17. 600 in X places the mine off to the right while 200 in Y lets the mine fall out of view long enough that it restarts again when the ship is fully on screen.

Figure 18

    [TrapMine]
    print #game.g, "spritexy? mine mineX mineY"     'places the mine' coordinated in the variables mineX and mineY
    if mineY>320 then
        print #game.g, "spritexy? ship shipX shipY"
        mineX=shipX+60
        mineY=shipY
    end if
    print #game.g, "spritexy mine ";mineX;" ";mineY
    return  'returns to the point in the program that directed the program here

Now modify the code under [TrapMine] so that it looks like that code in Figure 18. When the mine goes off the bottom of the screen the highlighted code gets the location of the ship and then places the mine at that location (plus 60 pixels to the right which places the mine at the end of the ship).

Save your work and run the program. When the mine goes off the bottom of the screen the mine should then relocate to the back end of the ship and fall again. If things don't work right then go back and make sure you have typed in everything correctly.

Scoring

Let's now set up scoring so that the program will keep track of the number of ships we have sunk.

Figure 19

    nomainwin
    WindowWidth = 500:WindowHeight =320
    UpperLeftX=Int((DisplayWidth-WindowWidth)/2)        'these two lines center the window on the screen
    UpperLeftY=Int((DisplayHeight-WindowHeight)/2)

graphicbox #game.g, 0, 20, 500, 300 'placed down 20 pixles to give the statictext room
statictext #game.st, "Ships Sunk",0,0,200,18 'adding the statictext along the top

Change the statictext to read “Ships Sunk” as in Figure 19.

Figure 20

score=0

Figure 21

    [TorpShipCollision]
    print #game.g, "spritecollides torpedo list$"
    if list$= "ship" then
        print #game.g, "spritexy ship ";-100;" ";sy
        torpedoX=150:torpedoY=300
        TorpFlag=0
        score=score+1
        playwave "boom.wav", async
    end if
    return

Now under the [TorpShipCollision] branch set up the score variable to increase by one each time the torpedo and ship collide.

Figure 22

    [draw]
    print #game.st, "Ships Sunk = ";score
    print #game.g, "drawsprites";
    return

Lastly, under your draw branch set up the statictext so that it will print out the score variable after the statictext. Printing our “score” text here will help us later on when other events may add to our score. We will not have to repeat this command each time another event adds to our score.

Once again save your work and then test it. Your “Ships Sunk” should increase by one each time your torpedo hits a ship.

Random Y Locations

Let's add some variation to our enemy sub. Just a little bit of code will do it.

Figure 23

    [TrapEnemy]
    print #game.g, "spritexy? enemy enemyX enemyY"
    if enemyX>500 then
        enemyY=int(rnd(0)*180)+55
        print #game.g, "spritexy enemy ";0;" ";enemyY
    end if
    return

Modify your TrapEnemy branch to look like that of Figure 23. The line that says enemyY=int(rnd(0)*180)+55 gives us a random number between the numbers 55 and 234, the Y range that we want the enemy sub to move around in. Let's try to break this down. rnd(0) gives us a number between 0 and 1. Since we want a range of 180 numbers we multiply that value by 180. Our answer will have several numbers to the right of the decimal that we don't want so we place the int function at the beginning. This drops all numbers to the right of the decimal. Next, I don't want the number to be less than 55 so I add 55 to my random generated number. Now the next line simply tells the program to place the sprite in it's new location which is zero in X and the randomly generated number in Y. English please… Each time we relocate the enemy sub to the left of the screen it is given a new Y location. So, it will appear in a different Y location each time it restarts.

If you need more information on rnd and int go to the help menu and look them up. If you're still confused email me.

Again, save your work and test it. You should notice the enemy sub starting in a new Y location each time it restarts on the left side.

SubCommand Challenges for this Month

This month your challenges for the SubCommand Game will be as follows:

  1. Set up a collision between your sub and the mine.
  2. Set up a collision between the mine and the enemy sub.
  3. Set up a collision between your sub and the enemy sub.
  4. Set up another statictext to the right of the current one that tells how many subs you have left in the game (begin with three).
  5. When you have zero subs left quit the game (place a notice box in your quit branch telling the score). – Look under the Notice Box section of the Shooting Gallery Game for an example.

Final Remarks on SubCommand

Wow, we got things happening here. You will not want miss the next session. We will be replacing our collisions with explosions and sinking ships as well as adding a midi sound file to our game.


The Shooting Gallery Game

Our Objectives for This Session

After declaring our variables we will be mainly dealing with what I call a bullet routine. After discussing the bullet routine we will then integrate it into our program, it is a program in itself. Then we will discuss collisions, scoring, game timing, notice boxes and confirm boxes.

Declaring our Variables

Now open up your SGallery2.bas file or my SG2sol.bas. Let's save it under a different name. Go to File>>Save As… and give this file the name of SGallery3.bas.

First, as in the SubCommand game, we will declare our variables. This helps us to see up front what variable names we are using in the game. We can now also use the variable name instead of worrying about the number that is supposed to be there, Liberty BASIC will keep up with that for us. Now we need to declare our variables.

Type the following from Figure 24 under section III of your outline. This is the initial, or beginning locations of the sprites for our Shooting Gallery game.

Figure 24

    'III.  Initialize Variables
    balloonX=10:balloonY=300
    bottleX=-20:bottleY=170
    canX=300:canY=150
    squirrelX=300:squirrelY=205
    duckX=0:duckY=170
    targetX=125:targetY=-20
    bulletX=0:bulletY=700
    boardX=0:boardY=244
    duck2X=300:duck2Y=100

Figure 25

        'C.  Set Initial Location of Sprites - spritexy
    print #game.g, "spritexy balloon ";balloonX;" ";balloonY;
    print #game.g, "spritexy bottle ";bottleX;" ";botleY;
    print #game.g, "spritexy can ";canX;" ";canY;
    print #game.g, "spritexy squirrel ";squirrelX;" ";squirrelY;
    print #game.g, "spritexy duck ";duckX;" ";duckY;
    print #game.g, "spritexy target ";targetX;" ";targetY;
    print #game.g, "spritexy bullet ";bulletX;" ";bulletY;
    print #game.g, "spritexy board ";boardX;" ";boardY;
    print #game.g, "spritexy duck2 ";duck2X;" ";duck2Y;             'duck2's start location on the right of the window

Next go down to section IV part C and change the actual location values to the variable names that you just declared.

Figure 26

        'X.  Subs Called by Timer Branch

    [TrapSquirrel]
     print #game.g, "spritexy? squirrel squirrelX squirrelY"
     if squirrelX<-50 then print #game.g, "spritexy squirrel 300 205"
     return

    [TrapDuck]
    print #game.g, "spritexy? duck duckX duckY"
    if duckX>320 then print #game.g, "spritexy duck 0 170"
    return

    [TrapBalloon]
    print #game.g, "spritexy? balloon balloonX balloonY"
    if balloonY<-10 then print #game.g, "spritexy balloon 0 300"
    return

    [TrapDuck2]     'trapping routinge for duck2
    print #game.g, "spritexy? duck2 duck2X duck2Y"
    if duck2X<-20 then print #game.g, "spritexy duck2 300 120"
    return

    [TrapTarget]    'tapping routine for target
    print #game.g, "spritexy? target targetX targetY"
    if targetY>244 then print #game.g, "spritexy target 140 -20"
    return

Using Figure 26 check your variable names to make sure they are the same as the ones we declared. If not make the necessary changes so that all variable names match.

Save your work and run the program to make sure things work correctly. Everything should work as before with no “bugs” popping up.

Bullet Routine

Let's now take a look at the bullet routine. This is a short program that I use with shooting gallery type games. I simply copy and past it into the program that I'm writing or use it as the beginning of a program that I am beginning to write. I'm sure that someone else has come up with another way to do this but this is the one that I worked out and it seems to work well. So, at this point, load the bullet.bas program and let's look at it.

By this time you should be fairly familiar with the windows set-up part so we will skip that and move on down to Section VI where we initialize our keyboard and mouse events. Up to this point in our game we have controlled nothing with either our keyboard or mouse. Here, we want our left mouse button to shoot our bullet. Take a look at the code in Figure 27.

Figure 27

    'VI.  Initialize Keyboard and Mouse Events
    print #game.g, "setfocus";
    print #game.g, " when mouseMove [MoveSight]"
    print #game.g, "when leftButtonDown [Shoot]"
    wait

All the above code does is simply branches off to the Shoot branch each time the left mouse button is pressed down.

Figure 28

    'IX.  Branches called by Mouse and or Keyboard - user entity movement
    [Shoot]
    if ShootFlag=0 then     'if a shot is not currently happening then do the following
        ShootFlag=1            'Says now there is a bullet on the screen
        bx=MouseX-11        'set's the bullets location in the center of the cursor
        by=MouseY-11        'will need to be changed if bullet size is changed
        print #game.g, "spritexy bullet "; bx; " " ;by     'placed the bullet on-screen relative
                                                                         ' to mouse location
        print #game.g, "drawsprites"
        playwave "shot", async      'plays a wav file
    end if
    wait

The ShootFlag in Figure 28 begins an if/then branch that says if ShootFlag is equal to 0 (zero) then make it 1; make the variables bx and by relative to MouseX and MouseY except offset them down and to the right by 11 pixels; then place the bullet sprite in the bx and by location; update the screen with drawsprites; play a sound called shot.wav and end the conditional statement.

If ShootFlag is equal to 1 and you press the left mouse button down again this section of code will be ignored, these things only happen when ShootFlag is equal to 0.

Figure 29

        'VII.  Timer Branch
    [TimerBranch]
    gosub [count]
    gosub [GameTime]
    wait

Figure 29 shows the two branches that are called by the timer in the bullet.bas program. The [draw] branch you are familiar with but let's take a closer look at the [count] branch.

Figure 30

    [count]
    if ShootFlag=1 then
        count=count+1
            if count>3 then
                ShootFlag=0
                count=0
                print #game.g, "spritexy bullet 0 700"
            end if
    end if
    return

The [count] branch counts. When we shoot the bullet we want it to stay on the screen for a few timer cycles so that the program has time to see if there are any collisions with our bullet sprite. This bit of code is only run if ShootFlag is equal to 1. If ShootFlag is equal to one then we take our count variable, which we initially set to zero, and add 1 to it.

	   if count>3 then
                ShootFlag=0
                count=0
                print #w.g, "spritexy bullet 0 700"
            end if

The next if/then condition says that if count is greater than 3 then set ShootFlag to zero, count to zero and place the bullet off the screen. This resets both our variables again so that we can shoot a bullet again.

The if count>3 is what determines how long the bullet sprite stays on the screen. The 3 here is about 3 tenths of a second because our timer is at 100 milliseconds. If we wanted it to stay on the screen longer we could increase the number here, say 7 or 10, and it would be on the screen for a noticeably longer time. Try replacing the 3 with 10 and notice the difference.

Let's now work the bullet routine into our Shooting Gallery program.

Integration of Bullet Routine

We have already set up much of the code for the bullet graphic to appear we just now need to set things up where it will behave according to what we did in the bullet.bas program.

Under Section III of your outline add the following to your list of variables

    ShootFlag=0
    count=0

Add the following bit of code to Section VI of your outline:

print #game.g, "when leftButtonDown [Shoot]"

Add the following bit of code to Section VII, before the gosub [draw], of your outline:

    gosub [count]

Figure 31

    [Shoot]
    if ShootFlag=0 then     'if a shot is not currently happening then do the following
        ShootFlag=1            'Says now there is a bullet on the screen
        bx=MouseX-11        'set's the bullets location in the center of the cursor
        by=MouseY-11        'will need to be changed if bullet size is changed
        print #game.g, "spritexy bullet "; bx; " " ;by     'placed the bullet on-screen relative
                                                                         ' to mouse location
        print #game.g, "drawsprites"
        playwave "shot", async      'plays a wav file
    end if
    wait

Now insert the code from Figure 31 under Section IX of your outline.

Save your work. I placed the code after the [MoveSight] branch.

Next add the [count] branch under Section X of your outline as seen in Figure 32.

Figure 32

    [count]
    if ShootFlag=1 then
        count=count+1
            if count>3 then
                ShootFlag=0
                count=0
                print #game.g, "spritexy bullet 0 700"
            end if
    end if
    return

Save your work. When you run the program now and click your left mouse button you should see the bullet appearing centered on your cursor and hear a shotgun sound. If this does not happen be sure to check and make sure you have typed everything in correctly.

Collisions

Now let's set-up some collisions between the bullet and some of our sprites. The two sprites we are going to work with are the squirrel and the duck. When a collision occurs we can tell the program to do many things. Let's begin by setting up the code to tell us when a collision occurs. First add a new gosub in the TimerBranch as shown in Figure 12.

Figure 33

        'VII.  Timer Branch
    [TimerBranch]
    gosub [TrapSquirrel]
    gosub [TrapDuck]
    gosub [TrapBalloon]
    gosub [TrapDuck2]
    gosub [TrapTarget]
    gosub [count]
    gosub [CheckCollisions]
    gosub [draw]
    wait

Next add the CheckCollisions branch to Section X of your code as in Figure 34. This will cause the program to check for collisions each timer cycle.

Figure 34

[CheckCollisions]
print #game.g, "spritecollides bullet list$"
print list$
return

The spritecollides command is new. Go to the LB Help File and read up on it if you want a little more information. Basically we are telling Liberty BASIC here to place the name of any sprite that touches our bullet sprite into a string variable called list$. And, no there is nothing special about list$. You could name it hits$ if you wanted. The next line simply prints the contents of the list$ variable to the main window.

And lastly, comment out the nomainwin at the beginning of your program. This will allow us to see what is in the list$ variable.

Figure 35

'nomainwin

Once you have done the above steps run your program. Try to hit some of the sprites with the bullet. When the bullet touches another sprite you will see the name of that sprite come up on the main window. See Figure 36 below.

Figure 36

balloon sight duck2
balloon sight duck2
balloon sight duck2
balloon sight duck2
balloon sight duck2
balloon sight duck2

target sight duck2
target sight duck2
target sight duck2
target sight duck2
target sight 
target sight 

Let's talk about Figure 36 for a minute. Notice that even if you did not hit another sprite that “sight” always came up. Remember, the “sight” sprite follows the mouse cursor around, so if we keep it anytime we shoot a bullet it will hit the “sight” sprite. Several times in Figure 36 I hit two sprites, so it listed both of them along with the “sight” sprite in the list. One last item, is the order in which the sprites are listed. If you will notice, they are listed in the order in which they were added with the addsprite command. “target” is listed before “sight” and “duck2” is at the end of the list.

One other thing you may have noticed is that before you even begin shooting that “can” continually shows up in the “list$”. If you go back and check you will see that they are very close in their initial locating values. If you would like you are welcome to one of them to another location so that they will not be touching (I changed the initial values of the bullet's X and Y to 0 and 700). Also, remember that all of these sprites are rectangular in shape, so even though they look round or irregular in shape the computer sees them as rectangles. Sometimes you may think they should not touch, such as the bullet and the sight, but remember both the bullet and the sight are rectangles and when you shoot the bullet it is on top of the sight rectangle.

Now let's remove the duck and the squirrel when they are hit by the bullet, you will do this for the others later as one of the challenges. Run your program and shoot the squirrel. Notice what comes up in the main window when you do this (when you stop the game you can scroll up in the main window to see this).

Figure 37

sqirrel sight
sqirrel sight
sqirrel sight
sqirrel sight
sqirrel sight
sqirrel sight

Figure 38

squirrel board sight
squirrel board sight
squirrel board sight
squirrel board sight
squirrel board sight
squirrel board sight

In Figures 37 and 38 you can see that I got two different lists when I shot the squirrel depending on where I shot him. Both lists included the sight.

Figure 39

    [CheckCollisions]
    print #game.g, "spritecollides bullet list$"
    if list$= "squirrel sight" or list$= "squirrel board sight" then
        print #game.g, "spritexy squirrel 300 205"
        if list$="squirrel sight" then Score=Score+1
        if list$="squirrel board sight" then Score=Score+1
    end i

    print list$
    return

Copy the highlighted lines from Figure 39 into your program. We have make provision for the two possibilities when we shoot the squirrel.

Now let's do this for the duck, the one going from the left to the right.

Run your program and shoot the duck. Try to cover all possible combinations.

Figure 40

baloon duck sight
baloon duck sight
baloon duck sight
baloon duck sight
duck sight
duck sight

In Figure 40 you can see that I am only covering two possibilities, there are more (part of your challenge for Session 3 will be to take care of all the possibilities when the bullet makes a hit on any of the sprites.) I am going to use a new if/then statement for the two conditions of the duck. Make the changes to your program as you see them in Figure 41.

Figure 41

    [CheckCollisions]
    print #game.g, "spritecollides bullet list$"

    if list$= "squirrel sight" or list$= "squirrel board sight" then
        print #game.g, "spritexy squirrel 300 205"
        if list$="squirrel sight" then Score=Score+1
        if list$="squirrel board sight" then Score=Score+1
    end if

    if list$="balloon duck sight" or list$="duck sight" then
        print #game.g, "spritexy duck -40 170"
    end if

Now when you hit the duck or the duck and the balloon, the duck should disappear and reappear from the left side of the screen. If you didn't include the possibility of the balloon being hit the same time as the duck then when you did happen to hit both at the same time nothing would happen because we did not make provision for that specific “balloon duck sight” string to be in list$.

Once things are working correctly save your work. At this point leave the “print list$” code in as well as your nomainwin code commented out. You will need the information from the mainwindow when complete the collisions for the other sprites in the challenge for this month.

Scoring

Let's give some scoring values to some of our sprites. For the squirrel let's say 1 point, for the duck 2 points and for the balloon duck combination let's say 5 points.

First, let's modify the text of our statictext.

Figure 42

    statictext #game.st, "Score: ",0,0,200,18

Under Section I of our outline we simply changed the text inside the quotes to “Score: ” as in Figure 42.

Now add a score variable at the end of Section III as seen in Figure 43.

Figure 43

    'III.  Initialize Variables
    balloonX=10:balloonY=300
    bottleX=-20:bottleY=170
    canX=300:canY=150
    squirrelX=300:squirrelY=205
    duckX=0:duckY=170
    targetX=125:targetY=-20
    bulletX=0:bulletY=700
    boardX=0:boardY=244
    duck2X=300:duck2Y=100
    ShootFlag=0
    count=0
    Score=0

Now we go back down to the CheckCollisions branch to set up our point values.

Figure 44

    if list$= "squirrel sight" or list$= "squirrel board sight" then
        print #game.g, "spritexy squirrel 300 205"
        if list$="squirrel sight" then Score=Score+1
        if list$="squirrel board sight" then Score=Score+1
    end if

As you can see in Figure 44 we said that if list$ is equal to a specific string value then we add 1 to whatever the Score value happens to be. We could have made the two lines into one with an or (as we did in the first line of Figure 44) but then the line would get long and we would possible have to scroll to the right to see it. So for readability we made it into two lines. If you haven't already, add the two lines from Figure 44 to your code. You are welcome to change the point values for the sprites if you so desire.

Now we do the same thing for the duck sprite.

Figure 45

    if list$="balloon duck sight" or list$="duck sight" then
        print #game.g, "spritexy duck -40 170"
        if list$="duck sight" then Score=Score+2
        if list$="balloon duck sight" then Score=Score+5
    end if

We could add the code at the end of the [CheckCollisions] branch that will update the score, but I like putting it with the [draw] branch (I find it a little easier to keep up with since I usually don't have a lot in the [draw] branch). So, copy the following code from Figure 46 into your [draw] branch.

Figure 46

    [draw]
    print #game.st, "Score: ";Score
    print #game.g, "drawsprites";
    return

All we are doing here is telling the computer to again write the text “Score: “ but then after it to place the value of our variable called “Score”.

Run your program now and see how things go. If you have typed the code in correctly you should get scores for shooting the squirrel, the duck and the duck and balloon. Once things are working correctly save your work.

Game Timing

Now, to me this game is not very challenging yet, I can shoot all day long and my score simply depends on how long I want to play. So, let's add a game timer, let's say about 30 seconds of game time.

Our timer fires every 100 milliseconds, that's 10 times per second, so 300 cycles should be close to 30 seconds. If you want to check this out for yourself, copy and run the program below. Time it with a stopwatch or something similar to see how close it is to 30 seconds. I get around 33 seconds – close enough for me, you can tweek it and get it closer if you would like.

timer 100, [count]
[count]
i=i+1
if i >299 then [quit]
print i
wait

[quit]
notice "30 Seconds is Up!"
end

EXAMPLE CODE 1

Now let's add this timing element to our code.

Figure 47

        'VII.  Timer Branch
    [TimerBranch]
    gosub [TrapSquirrel]
    gosub [TrapDuck]
    gosub [TrapBalloon]
    gosub [TrapDuck2]
    gosub [TrapTarget]
    gosub [count]
    gosub [CheckCollisions]
    gosub [draw]
    gosub [GameTime]
    wait

I've added a gosub to my [TimerBranch] and called it [GameTime] to help me remember what this branch does. Add this gosub to your program. Let's go down to the end of our code and add the [GameTime] branch. Usually I don't put anything below the [draw] branch but with this I would like for everything the be check and drawn before I end the game, if I had it higher up it is possible that my final score would not be added to the score displayed on the screen. Figure 48 is the code you need to add.

Figure 48

    [GameTime]
    Time=Time+1
    if Time>300 then [quit]
    print Time
    return

Also go up to your Initialize Variables section and put in a new variable – Time=0.

Now when you run your program it should run for about 30 seconds and then quit.

Notice Boxes

You say, OK, it quits after 30 seconds but what is my score???? Glad you asked. This is where a notice box will come in. For more information on Notice Dialog Boxes go to Help and look under Command Reference. Since we want to tell the player the score after time has run out the logical place for this notice box would be in the [quit] branch.

Figure 49

    'VIII.  Quit Branch - unloads bitmaps and closes windows
    [quit]
    notice "Game Over"+chr$(13)+"Your Score is: ";Score
    '*** Unload all of your bitmaps
    unloadbmp "balloon"    'We can't forget to unload all of our bitmaps

Type the highlighted line from Figure 49 into your code under the [quit] branch. The first set of text in quotes, “Game Over”, becomes the title of our Notice Box. The chr$13 is the ASCII code for a carriage return. The second set of text in quotes is what is printed inside our Notice Box and we have told it to print the value of the variable “Score” after the text “Your Score is: “. We can add as many lines to our Notice Box with the chr$13 as we want. But if we do use the chr$13 then the first set of text in quotes will be the title of our Notice Box. If we didn't use chr$13 at all then the title of our Notice Box would be “Notice”

Run your program, shoot a few targets and wait approximately 30 seconds. At the end of the 30 seconds your Notice Box should appear as in Figure 50.

Figure 50

At this point the program has stopped, the Notice Box does this and will go no farther until you click on the OK button at which point our game simply closes.

Save your work.

Confirm Boxes

That's better you say, but it is a short game and I have to rerun the program to play it again. Well, I have another solution for you. It is called a Confirm Dialog Box. See the help file for more information. Now we want this Confirm Box to come up after the Notice Box so we will place it right under the code for the Notice Box. Copy the highlighted code from Figure 51 into your program.

Figure 51

    'VIII.  Quit Branch - unloads bitmaps and closes windows
    [quit]
    timer 0
    notice "Game Over"+chr$(13)+"Your Score is: ";Score
    confirm "Would You Like To Play Again?";answer$
    if answer$="yes" then goto [StartAgain]
    '*** Unload all of your bitmaps
    unloadbmp "balloon"    'We can't forget to unload all of our bitmaps

Now that we want to start the game again we must first stop the timer. If we let the timer keep going then after we click Yes on the Confirm Box the program will try to catch up with the timer clicks the computer has been keeping up with while you clicked on your Notice Box and Confirm Box – in other words things will go very fast until all timer ticks have been accounted for.

For the Confirm Box the text is the message you want displayed. After the text you must tell the computer the variable name that you want the response stored in. With the Confirm Box you have two possible answers, “yes” and “no”. The third highlighted line says that if answer$ is equal to “yes” then go to the [StartAgain] branch.

Figure 52

    [StartAgain]
    ShootFlag=0
    count=0
    Score=0
    Time=0
    goto [Begin]

Put the code from Figure 52 at the very end of your program. This resets critical variables for us. Place a [Begin] branch label in Section V of the outline above the section of code where you initialize the timer. This restarts the timer for our game if we want to play again.

Check to see that both buttons on the Confirm Box do what they should and that everything else is working correctly. Save your work. If things don't work right then go back and check to see that your code is correct.

Shooting Gallery Challenges for this Month

This month your challenges for the Shooting Gallery Game will be as follows:

1. Set up collisions with the target, balloon and duck2. Also set up all of the possibilities for collisions.

2. Set up different point values for the above-mentioned sprites.

3. Set up another statictext telling the number of shots taken.

4. Set-up a Notice Box at the beginning of the game that gives directions for playing the game.

Closing Remarks

We have covered a lot of ground this month. Next session we will cause our targets to break, the squirrel to flip and the balloons pop. We will also deal with adding MIDI music files to our games. The last thing we will deal with next month is random start locations for our sprites.

Until then: Happy Programming!


Home

Game Tutorial

Pseudo Menubar

Binary Numbers

Designing Games

API Corner

JPEG.DLL

Graphics Text

Tip Corner

Installers

Demos

Submission Guide

Newsletter help

Index