![]() |
Welcome to Beginner Programming
|
| Course content | Enter chat room | Send email
to mailing list |
Check calendar |
There are two essential components to any computer game:
In this lesson we are going to investigate how to play sounds in Tcl/Tk.
Fortunately for us Tcl/Tk is a very extendable computer language. We are also fortunate that Tcl/Tk has been around for a while now and many developers have created extensions to do a whole variety of things. One of the things that have already been done is to write extensions that play sounds.
Computer sound is stored in what is called digital format. The most common form of digital sound is the music CD that we all have used. In the PC world computer sounds can be stored in a variety of digital formats. One of the most common is the WAV format, so named because the sound files come with the ".wav" extension on the end of the file name. Fortunately for us most PC's come with lots of ".wav" files already available. To locate some on your machine simply use the file finder and search for all files that contain "*.wav". This should produce a list of files including the one we will use in this lesson. On my machine here it is found in:
c:/windows/media/Ding.wav
(Macintosh users will have other wav files available).
Step 1: the first part |
The sound playing software tools are not packaged with the Tcl/Tk tool set that we downloaded and installed as part of lesson #1. Our first step is to download and install the sound extensions to Tcl/Tk. After having done this process once in lesson #1 you will find that this exercise is very familiar to you now. In fact the sound extension is much smaller than the full Tcl/Tk package and is easier to install. The sound extension we want is called the Snack Sound Extension. You can read more about it's capabilities at the website hilited in the previous sentence. We will be making use of only a small subset of the snack sound extension's capabilities: namely its ability to play .wav files.
To get to the download page for Snack simply click here. On this web page you should find a link like
Binary Release for Windows 95/98/NT/2K with Tcl/Tk 8.1.1 or later 529Kb (April 19, 2000)
which when clicked will start the download of the Snack Extension Software. (Macintosh or Linux users will use the link appropriate to their OS).
Follow all the instructions to download and install this software.
It will be basically similar to what happened in lesson #1.
Step 2: the second part |
If you remember back to lesson #1 after we downloaded the tools we checked them out by typing a short program in the wish console window. We can do the same thing here.
Bring up the wish program as you have done for many lessons now ...
only this time don't bother with the editor window just yet.
At the wish console prompt simply type the following lines (hitting Enter
after each)
| package require snack
snack::sound s s read c:/windows/media/Ding.wav s play |
At this point your screen should look something like that below and you should have heard a sound immediately after typing the last line and hitting Enter.
You can experiment by retyping the last two lines for each of the ".wav"
files that you have found on your machine. eg on my machine I have another
wav file called "Chimes.wav". If I retype these two lines in
my console window I'll hear another sound ... which come to think of it
sounds a lot like chimes.
| s read c:/windows/media/Chimes.wav
s play |
Step 3: the third part |
Let's now add the sound capability to the program we just wrote for lesson #6.
What we basically need to do is add the 4 lines we have typed above into the program at appropriate locations. While we do this let's attempt to understand a little about what these lines are doing.
The first thing you will want to do is to create a copy of the file called lesson6.tcl and call it lesson7.tcl . Bring this lesson7.tcl file up inside your editor program.
The first change I want you to make is to go through and change every line where you see the words "lesson 6" to read "lesson 7".
The next change I want you to make is to add the "package require" line
you typed above as the very first non comment line in your new program.
ie.
| #========================================
# FILE: lesson7.tcl # # AUTHOR: # # REVISIONS: # #======================================== package require snack |
Computer languages often come with extensions. Sometimes these are called libraries. Sometimes they are called packages.
Tcl/Tk has adopted the package name for these code extensions.
Basically what you are telling the wish program by this first line is that you will be using some commands that can be found in the package called "snack".
We will need to place the second and third lines that we typed in the
console above into the main part of our program.
There is no requirement for them to go in any particular place provided
that it is before the vwait statement. As such let's
put it just ahead of that statement. ie.
| #
# initialize the sound # snack::sound s s read c:/windows/media/Ding.wav #
|
The first line is at first a little curious because it contains a "double colon" as part of the command name.
This is what is termed in Tcl/Tk as a namespace specific command.
Namespaces themselves are a subject for a more advanced course. Suffice to say they are a good technique to use to help modularize and simplify larger Tcl/Tk programs. The authors of the snack package chose to place all their variables and commands under the "snack" namespace. In this case the command is "sound" and thus "snack::sound" refers directly to that particular command.
For our purposes just think of the "snack::" as simply part of the wierd name they gave to their command inside their package. In English this command says:
"create a variable called s which we can use to store a sound"
The next line is simply the command to "read in" the ".wav" file to our newly created structure/variable called "s". The file we have chosen to read in is located on my C drive inside the "windows" folder and inside the "media" folder contained there. The file itself is called "Ding.wav". You are free to add whatever sound file you may have on your machine.
So far all we have done is effectively initialize our sound effect. It is now time to find appropriate locations within our code to play this sound effect. To me it makes sense to play it whenever our fruit object strikes the ground.
What do we mean by striking the ground? In lesson#6 our
fruit didn't move. OK let's fix that now.
Step 3: the fourth part |
In computer animation image moving is sometimes called blitting.
What we are going to be doing is exactly what any computer game programmer does: draw the image; wait some short amount of time; then move the image slightly and redraw it.
The first change we want to do is to give ourselves some more room to
work. In other words let's make our window bigger. This
line we want to change is:
| #
# setup top level window size, position and title # wm geometry . 350x400+10+10 wm title . "lesson7" |
| Don't forget that you can run your code after each one of these changes. It is in fact a very good habit to get into as a programmer. Make small changes and test them as you go along. If you were to do that you would now find that your wish window has gotten bigger. It actually grew from 200x250 pixels to 350x400 pixels according to the change in the geometry line above. |
Next let's give ourselves a bigger canvas to draw on. The
line in question is:
| #
# set up our animation canvas # canvas $f_a.c -height 210 -width 300 -background lightBlue pack $f_a.c -side top |
Notice now that our canvas area has grown from 100x150 pixels to 210x300 pixels.
But hey you say ... the buttons are all messed up. No problem
let's move those down to a new location.
| #
# arrange the animation frame and button frames # in main frame # place $f_a -x 10 -y 10 place $f_b -x 30 -y 250 place $f_b2 -x 70 -y 300 |
We are now almost ready to make our fruit "fall".
First let's position the fruit in an appropriate place to fall from.
| #
# display the new image and text # $f_a.c create image 10 10 -image $myimage -tag imagetag $f_a.c create text 80 50 -text $myimage -tag texttag |
How are we going to start this "falling" process off?
That's right we need another button.
Let's call that button "Drop" and place it beside the "Quit" button
that we already have.
| button $f_b2.quit -text "quit" -command
{ set x_it 1 }
button $f_b2.go -text "drop" -command { dropImage } pack $f_b2.go $f_b2.quit -side left |
For those of you who are following the advice above and trying the code
at each change will notice that the program now is complaining about the
lack of a procedure called "dropImage" which we have connected to our "Drop"
button above.
| This sequence of adjustments to the code is very deliberate. It is always better to change the "infrastructure" parts to get your new feature enabled before you actually write the code for your new feature. That way you are immediately in a position to test anything you add to the new feature itself as you build it. This is what is known as "incremental code design" or "design-code-test". There are other formal ways to develop software but this has the best proven track record in real world projects. |
Here's what we want to do to move our graphics.
| #========================================
# dropImage - entry point #======================================== proc dropImage { } { global f_a global s set nextdrop 1
set nextdrop -18
set nextdrop -8
puts stdout "dropImage:done"
#========================================
|
The actual math and physics behind the dropping of objects is somewhat complex.
When you come to study these things later in high school and you ask "Why would I want to know this #$@!?"
Well here's a less than obvious answer ... "because I want to be a video game designer and I will need to make my falls realistic".
Each leg of the drop above has a construct like this below.
| set nextdrop 1
for { set i 0 } { $i < 2000 } { incr i 200 } { after $i "$f_a.c move imagetag 12 $nextdrop" set nextdrop [ expr $nextdrop + 4 ] } |
By now you should be comfortable with all of the Tcl/Tk language used in this construct so let's try to reproduce it's logic in plain English.
"Starting with the nextdrop variable set to 1, loop 10 times incrementing the time by 200ms each loop. At each loop iteration setup to move the image to the right by 12 pixels and down by an accelerating amount each time ... to simulate the pull of gravity. Each vertical drop amount will increase by 4 pixels each time through the loop starting at the initial value of 1 ...ie. 1, 5, 9, 13 etc."
Notice how we conveniently handle the bounce up by simply starting our loop with a negative vertical drop amount. Remember from the previous lesson where coordinates were discussed. Vertical pixel direction is a positive number in the downward direction. ie. pixel row 10 is higher up on the screen than pixel row 100 is.
I warned you that all that math you are learning actually has some real
uses.
The fun part |
Now let's finally add the sound effect to our code !!!
While we describe the line(s) that we will be adding to the code, why don't you think about where these lines might go in the code before I give you the answer below.
As with our image moving (or blitting as it is sometimes called) we would probably want to schedule our sound effect at specific times in our little cartoon sequence. If you understood the code above you would see that the object strikes the ground after 2000ms on the first fall, after 4000ms on the second bounce and after 5000ms on the third bounce. These would be good times in which to insert our sound effects. When we were playing the sound on the console above the line we were typing was:
s play
This is precisely the command we would want to execute at these 3 times.
How do we do this?
Why we use exactly the same "after" command that we used inside the loop but with the "$i" and the command to execute parts changed: ie. at the 2sec mark (2000ms = 2sec) we would need a command like:
after 2000 "s play"
We would need to play our sound effect after the object had completed
the first fall. ie.
| for { set i 0 } { $i
< 2000 } { incr i 200 } {
after $i "$f_a.c move imagetag 12 $nextdrop" set nextdrop [ expr $nextdrop + 4 ] } after 2000 "s play" |
I will leave it up to you to add the other two lines that we require to complete our sound effects at the appropriate place in the code. Those lines would be:
after 4000 "s play"
and
after 5000 "s play"
Final source listing |
| #========================================
# FILE: lesson7.tcl # # AUTHOR: # # REVISIONS: # #======================================== package require snack #========================================
set nextdrop 1
set nextdrop -18
set nextdrop -8
puts stdout "dropImage:done"
#========================================
#
#
} ;# end showImage #========================================
#
#
puts stdout "lesson6 starting" #
#
#
#
button $f_b.grapes -image grapes \
button $f_b.chilli -image chilli \
pack $f_b.apple $f_b.grapes $f_b.chilli -side left button $f_b2.quit -text "quit" -command
{ set x_it 1 }
#
#
#
#
#
puts stdout "lesson7 done" |
When you run this program and hit the drop button you should see an image similar to that below:
Summary |
End of Lesson 7.