Editor's Note -- If you have a promising young programmer in the family, you might want to take advantage of the extra time together during the holidays to teach a little programming. Michael Norton wrote this tutorial for his fourth grade son, and offers it to Mac DevCenter readers and their children. In just seven easy lessons your child can program a fun drawing program ... and I'm sure that will be just the beginning.
Greetings future game developers, and welcome to Elementary Computer Graphics. The elementary I am referring to is elementary school. My son Matt, who is in fourth grade, asked me one evening to teach him how to program video games. I was excited to take on the task but at the same time I realized I had to discuss what I knew on an elementary school level. After several months of thinking and dragging Word documents to the trash, I arrived at some simple explanations. So here goes.
To truly understand computer graphics requires years of studying mathematics. Does this mean that you can't begin to tackle the concepts of computer graphics? I believe the answer to that is No. We will, however, need to cover some simple math principles that will be useful in learning about computer graphics. But just enough to get the job done.
My first choice for teaching computer graphics was Real Basic. However, the price of Real Basic exceeded Matt's allowance and my monthly lunch budget. So fasting for a month wouldn't get him a development system. I decided to fall back on the old, tried-and-true (and FREE) Tcl interpreter. Tcl is available for every operating system under the sun (including, but no pun intended). You or your parents can download Tcl from this web site Macintosh OS X Aqua Tcl. If you are using an Intel platform or other please download from http://www.tcl.tk.
The discussions of Elementary Computer Graphics are broken down into seven lesson modules. The lesson modules include the introductory discussion, a figure <picture> showing the runtime execution and a section at the end, titled, The Script:. This portion of the lesson is most beneficial if you have the Tcl Wish Shell open. Cut and paste the scripts into the console. You should master each script module and then move on. So this may take a few evenings. Let's get started.
Since I will be doing my best to avoid all the ugly math involved, we'll need to meet on some common ground. Everybody has played the game Tic-Tac-Toe, right? Where you're the X player and your opponent is O. The object is to get your Xs three in a row, up or down or diagonally (see Figure 1).
|
|
What has Tic-Tac-Toe got to do with computer graphics? Ah, I am so glad you asked. The game Tic-Tac-Toe is played on a simple grid. Graphics on a computer are drawn on a similar grid.
The game of Tic-Tac-Toe is played on a grid that is 3 squares wide and 3 squares high. If we were to explain the Tic-Tac-Toe grid in computer graphics terms, we would say the Tic-Tac-Toe grid has a width of 3 and a height of 3. The number of grids available are calculated using your third grade multiplication skills. Multiply the width of 3 times the height of 3. The multiplication of 3 x 3 gives us the value of 9. This value in computer graphics has a special meaning. It is called the resolution. Our resolution of the game grid is 3 x 3. Speaking like a computer programmer you would say the resolution is 3 by 3 instead of 3 times 3.
Now let's take this one step further and pretend we are teaching the computer to play Tic-Tac-Toe. The computer can't eyeball the grid and draw its O move as we can. We must break up the grid into terms the computer can understand. A computer only understands numbers. For starters, remember the number line from second grade math? Let's look at it in slightly different way for this purpose (see Figure 2).
|
|
Taking the top 3 blocks of the Tic-Tac-Toe grid, I have created a number line. The smallest number is on the left and the numbers get larger as we move to the right. The values in the blocks are called coordinates. Moving from left to right in the grid, use the coordinates of 0, 1, and 2. Since we use these coordinates to move left to right, we call these x coordinates, which has a special meaning for the computer. The x coordinates tell the computer how to move across the screen. This is good enough for the computer if the Tic-Tac-Toe grid only has 3 blocks.
Tic-Tac-Toe has a 3 x 3 (say 3 by 3) grid, so we also need to tell the computer how to move up and down. Figure 3 shows how this is done.
|
|
We take the left column of blocks and create a grid, as shown. The top left block is the first block with a value of 0. As you move down the block the numbers get bigger. When we go up and down in this grid we use y coordinates. The y coordinates tell us how we go up and down. The farther you move down from the top the bigger the number. In this case, the Tic-Tac-Toe grid is only 3 blocks high, where the y coordinate of 0 is the top and the y coordinate of 2 is the bottom of the grid.
This x-y (pronounced xy) coordinate system allows us to map out the Tic-Tac-Toe grid so we can make a map for the computer to use. The map is shown in Figure 4.
|
|
Now let's tell the computer how to use our Tic-Tac-Toe grid. The very top left block has an x-coordinate of 0 (red) and a y-coordinate of 0 (blue). This is a very special block because we will always start our grid walks from this block. This block is called the origin. A computer graphics display also has an origin in the top left corner of its display.
We are explaining the Tic-Tac-Toe game in terms the computer can understand. You are player one and you want to place your X in the center grid. To place your X in the center you need to speak to the computer in its language. You tell the computer to walk left from the origin block by one step. The value of our x-coordinate is 1. Place a finger from your right hand on the red number 1 on the top of the block. This is your x-coordinate. Place a finger from your left hand on the blue number 1 on the side grid. This is your y-coordinate. Now draw both fingers in to the center of the grid. There is a red 1 for the x-coordinate in this box and a blue 1 for the y-coordinate.
The computer says, "AH! You want to draw an X at coordinates, x=1, y=1. I'll draw the X in for you."
Now the computer takes its turn and places an O in the top right corner of the grid. Do you know what coordinates the computer used? Put a finger from your right hand on the red 2 above the grid. This is right above the upper right block. Now place a finger from your left hand on the blue 0 on the left hand side of the grid. Trace with your left finger to the top right block. The computer put its O at location x=2, y=0, as shown in Figure 5.
|
|
|
I mentioned earlier that the only thing a computer understands is numbers. Have you ever met someone from another country who spoke a different language? If this person didn't speak English then you need the help of an interpreter. An interpreter is a person who speaks both English and one or many other languages. You would speak to the person who didn't understand English and the interpreter would translate what you said into the person's native language.
A computer has several interpreters for several different computer languages. We are using a scripting language called Tcl, pronounced tickle. It is an acronym for Tool Command Language or Tcl (say tickle), as it is commonly called. Tcl is a language that has rules about how we talk to the computer. The Wish Shell application is available on many different computer platforms, such as Microsoft Windows and Unix. If you are using the batteries-included Tcl package for Mac OS X, the Wish Shell app is in your Applications->Utilities folder. Scroll down to find the Wish Shell app, as shown in Figure 6. You can activate the interpreter by double-clicking the Wish Shell app.
|
|
Let's take a look at what the interpreter is and how it is used. Start the Wish Shell application and you'll see two windows. One is a graphical window, with the name Wish Shell on the title bar and the other is the interpreter window. The interpreter window has the name Console on its title bar (see Figure 7).
|
|
The console window is where we will access the Tcl interpreter. The console window has a % sign. This percent sign is called a command line prompt. We type in our Tcl commands at this prompt. Let's see if we can say hello to our computer. You can type in the following command at the console prompt. Remember the language has special rules and must be typed in as shown. Type the word "puts," then a space, and then in quotes, "hello!". Try this example in the console window.
puts "hello!"
Figure 8 shows what your console window should display if you typed the command in correctly.
|
|
The Script:
puts "hello!"
We told the computer to 'put' to its console, with the Tcl command, puts,
the message 'hello!'. The message to be displayed on the console is
enclosed in quotes. When the computer displays your message you'll notice
there are no quotes.
You have just run a simple command on the Tcl interpreter. Congratulations to you. You just executed your very first computer program.
Now what happens if you typed in the command wrong? Wanna see the computer get mad at you? The example shown in Figure 9 shows what happens when we don't type in the command and use a space. Spaces are important in Tcl scripting for the computer to understand what is a command and what is the command's data, called an argument. Repeat after me, "The space separates the command from the arguments."
|
|
The Script:
puts"hello!"
When the computer is upset by what you typed into the console interpreter it will display an error message. An error message is a helpful way of telling you, the programmer, that you have offended the computer. Don't worry, most computers rarely hold a grudge for long.
Let's look at a few basic concepts of the Tcl language. Suppose we want to ask the computer to remember a magic number for us. Using Tcl we would type in the following command:
set magic_number 2
The command set has a special meaning in Tcl -- it instructs the computer
to store the data. This is called setting a variable. In order for the
computer to store the data it needs a special name for the variable, so that the computer can remember where to find the stored data. In our case,
we named the data variable, magic_number. Let's take a closer look at
this command. The Tcl command is set, followed by a space, then the variable
name, followed by a space and the data assigned to the variable. Remember
our mantra, Tcl uses space-separated commands and arguments.
In order for the computer to retrieve and display the data we need to type the following:
puts $magic_number
When you are telling the computer (using the Tcl language) to retrieve data you must type the $ sign in front of the variable name you used for your data. Experimenting at the console, you would see the results shown in Figure 10.
|
|
The Script:
set magic_number 2
puts $magic_number
|
Suppose you would like to do some simple math in your Tcl console. Let's
take a look at doing something simple, like adding 2 + 2. Basic first
grade arithmetic, right? How do we tell the computer to add 2 + 2 for
us? We will need to use the Tcl command, expr, which is the command
for math expressions (expr). The Tcl command expr has rules we must
follow or else the computer will get mad at us. Let's take a look at
our simple first grade arithmetic on the Tcl Wish console. Here is what
you will need to type:
expr 2 + 2
The Script:
expr 2 + 2
The Tcl command is expr, the arguments are our math expression, 2 + 2,
space separated. Using our magic_number example, let's add 2 to our
magic number? That is, we want to do this:
And we would type the following into the Tcl console to get it done:
set new_magic_number [expr 2 + $magic_number]
Whoa! Where did those brackets [ ] come from? If you look hard we have
two Tcl commands on one line. The Tcl interpreter can only handle one
Tcl command at a time. The Tcl interpreter is going to perform the command
inside the brackets first. In our case it is the Tcl command expr. The
math expression will be calculated. Then guess what? The answer to the
simple arithmetic is going to be handed off to the Tcl command set as
a data argument. That's a mouth full isn't it? Let's break this down.
We type this command into the Tcl console interpreter:
set new_magic_number [expr 2 + $magic_number]
Tcl will grab what is inside the brackets first and do the following:
expr 2 + $magic_number
Obviously, the answer to the great mystery is 4. The answer is handed
back to the set command by the interpreter.
set new_magic_number 4
The Tcl interpreter does this all invisibly so we don't see it like I showed you. But that's what the computer is doing. Let's see if the computer has the right answer (see Figure 11).
|
|
The Script:
set magic_number 2
set new_magic_number [expr 2 + $magic_number]
Before we continue, let's quickly review. Look at how we set the magic_number
and how we set the new_magic_number. Why did we need to use brackets
to set the value of the new_magic_number? The values inside the brackets
[] needed to be evaluated by the computer. In this case, the computer
had to first compute the value of the Tcl expr command. Once it did
this, the value of 4 was set to the variable new_magic_number. We will
use brackets in a Tcl program when we want the computer to compute a
value first and then set a variable.
Let's revisit our Tic-Tac-Toe grid. The upper left corner block is located at x=0 and y=0, as shown in Figure 4. Let's set these variables using the Tcl command set.
set x 0
set y 0
Now let's tell the computer to calculate a new block coordinate for the
bottom right block of the Tic-Tac-Toe grid. We know from our little
map that this block is located at x=2 and y=2. We can have the computer
calculate this new block location. To get from the upper lefthand corner
of the grid to the lower right corner of the grid we must walk across the
x direction 2 steps and down the y direction 2 steps. Using Tcl commands
set and expr, we would type in the following at the Tcl interpreter
console:
set new_x [expr 2 + $x]
set new_y [expr 2 + $y]
|
|
The Script:
set x 0
set y 0
set new_x [expr 2 + $x]
set new_y [expr 2 + $y]
The variables new_x and new_y hold the grid position of the lower righthand corner block. If you look at Figure 4 you will see the lower righthand block in the Tic-Tac-Toe grid has the values, x=2 and y=2.
The value of new_x is 2 and the value of new_y is 2, the location of the lower righthand block in the Tic-Tac-Toe grid. If you are making
your move in Tic-Tac-Toe to place your X at the lower righthand corner
you would need to tell the computer to place an X at location x=2 and
y=2. I see the light bulb going on above your head! Time to move on.
Most computers today use a windowing system to display graphics on the computer. Our Tic-Tac-Toe game grid is a simple window that is 3 blocks wide by 3 blocks high. We learned earlier that the grid has a resolution of 3 x 3 (say 3 by 3).
A typical computer window system has a display resolution of at least 640 x 480, to resolutions up and around 1280 x 1024. Obviously, a 3 x 3 window would be too small to see if created on your computer window display. So let's pick a common window size. Using a game like Doom or Quake by id Software, we could select a window size of 640 x 480. The video game window is 640 wide by 480 high.
Since we are talking about computer windows and not a Tic-Tac-Toe grid, we would use the term pixels instead of blocks. A pixel is a picture element. Pixels are the magic little workers that make pictures appear on your computer display. We will create a display window 640 pixels wide by 480 pixels tall.
Tcl has a special software toolkit, called Tk, for graphics programming. When you run the Wish Shell app you are basically running Tk. We can set the little Wish window to the display size of a video game window. This is what you would type into the console window:
set video_game_width 640
set video_game_height 480
We instructed the computer of the values we want to store for creating our new game-size window. We want a window that is 640 pixels wide and is 480 pixels tall. Next we would need to create a graphics window, called a canvas, using the Tk command.
canvas .video_game_window -width $video_game_width -height $ video_game_height
The output from your console should look similar to the console output in Figure 13.
|
|
Nothing spectacular at the moment, right? Right! We set the new window
dimensions, but we just haven't instructed Tk to display the new window.
Tk has a special command called pack that performs a lot of magic in
the background to place and display our new window. Type in this command
at the console:
pack .video_game_window
Now let's see what happens to our Wish window, as shown in Figure 14.
|
|
The Script:
set video_game_width 640
set video_game_height 480
canvas .video_game_window \
-width $video_game_width -height $video_game_height
pack .video_game_window
Our little Wish window magically grew didn't it? This is the action of the Tk pack command. When we enter the pack command it sends our instructions to the Wish Shell window.
Please note, if you ever see the following error message that you will need to destroy your previously created video_game_window.
window name "video_game_window" already exists in parent
It may be lingering around from the previous script example. Use the following and then try the script again:
destroy .video_game_window
If that doesn't work you should try quitting your Wish Shell and restarting it. Now back to our discussion already in session.
|
Just like the Tic-Tac-Toe grid, the Wish window is described by x and y coordinates. The upper lefthand corner of the Wish Shell window is the origin just as the upper lefthand corner of the Tic-Tac-Toe grid had its origin. The origin is where the x and y coordinates are both 0. Figure 15 looks a lot like Figure 4, only the Wish window is 640 x 480 instead of 3 x 3 like the Tic-Tac-Toe grid.
|
|
You move around using the coordinates in the game window we created in much the same way we moved around the Tic-Tac-Toe grid. At the top of the window y=0, and y gets bigger as you move down. To the left of the window, x=0, and x gets bigger as you move right through the window. Now for a pop quiz. What are the x and y values of the middle of the window?
Let's see, the biggest value of x is 639, on the righthand side of the window and half of 639 is roughly 320. The biggest value of y, at the bottom of the window is 479. Half of 479 is roughly 240. The middle x value is 320 and the middle y value is 240. The pixel coordinates of the middle of the window are x=320 and y=240.
Want to have a little fun and prove this is the middle of the window? We can run a simple experiment to tell us the x and y coordinates of the Wish app window. Tk uses x and y values for tracking the computer's mouse. The x mouse value is %x and the y mouse value is %y in Tk. These values are used to tell us where the mouse pointer is inside our Wish Shell window. Type in the following command and see this for yourself:
bind .video_game_window <Motion> { puts "mouse x: %x mouse y: %y" }
The Tk command bind instructs Tk we want our Tcl command puts
bound to the motion of the mouse. Every time you move the mouse, Tk will
hand off the mouse coordinates to our Tcl command puts. You will need
to move your mouse inside the Wish Shell game window to see the mouse
coordinates. The mouse is only bound there. Move outside the window
and Tk will not display any coordinates. Move back in and the coordinates
will scroll down the console window again.
Let's give it a try and see if you can prove the middle of the screen is x=320 and y=240. My test values are shown in Figure 16.
|
|
The Script:
set video_game_width 640
set video_game_height 480
canvas .video_game_window \
-width $video_game_width -height $video_game_height
pack .video_game_window
bind .video_game_window <Motion> { puts "mouse x: %x mouse y: %y" }
The moment you have been waiting for, all young game-playing careers. Here is the dark secret to drawing on the computer. Are you worthy of having such knowledge and power? Behold, plotting the pixel.
The Tk graphics environment doesn't actually provide a utility to plot a pixel, so we are going to have to make do with drawing extremely small rectangles. The rectangle will be one pixel wide by one pixel tall. Basically, we're going to draw a square and pass it off as a pixel for this example. Type in this small piece of code into the console,
.video_game_window create rectangle 320 240 320 240This should draw a teeny-tiny black pixel in the center of your game window. Now you're cooking, and just a few short minutes ago you typed in your first Tcl program.
The Script:
set video_game_width 640
set video_game_height 480
canvas .video_game_window -width $video_game_width -height $video_game_height
pack .video_game_window
.video_game_window create rectangle 320 240 320 240
If you're not as enthusiastic with those results, how about we draw a larger rectangle we can see. And let's give it some color!
.video_game_window create rectangle 320 240 350 270 -fill red
The -fill option for the Tk create rectangle command allows you to change
the colors. Try playing around with black, blue, red, green, and yellow.
The Script:
set video_game_width 640
set video_game_height 480
canvas .video_game_window -width $video_game_width -height $video_game_height
pack .video_game_window
.video_game_window create rectangle 320 240 350 270 -fill red
In just a few short lessons of experimenting with scripts you can't become a game-coding master. That takes time and experience. But what can we do with what we already know? Well, Tcl/Tk is powerful enough to allow us to code a simple paint program. Most kids have played with Broderbund's Kid Pix in school. This drawing program can be crudely replicated with a few lines of scripting code in Tcl/Tk. We are going to create a very basic paint program using our video game window. We first create our window and display it in the usual manner.
set video_game_width 640
set video_game_height 480
canvas .video_game_window -width $video_game_width -height $video_game_height
pack .video_game_window
To draw with the mouse, you hold the left button down and draw. The left
mouse button is B1 in Tcl/Tk language. We will be dragging the mouse
to draw pixels. Moving the mouse in Tcl/Tk we use the Motion option,
as we did while experimenting with the window mouse coordinates. Just
as we did before, our script must bind to the B1-Motion action
on the computer. When a computer is looking for an action to take place
in a window it is said to be looking for an event. The event our computer
is looking for in order to draw is the B1-Motion, where you
are pressing the left mouse button down and moving the mouse. This is
also called dragging the mouse.
We will need to write our own special Tcl command, which will be called when
this event is seen by the computer. When we write a special command
of our own in Tcl it is called a procedure. Consider it a mini-program
script. To let Tcl know we're implementing our own script we must use
the Tcl command proc. The following procedure will tell the Tcl interpreter
how to handle the mouse drawing on our videogame window. Our mini-script
procedure name is mouse_draw. Here is what it looks like:
proc mouse_draw { x y } {
set xul [expr $x - 3]
set yul [expr $y - 3]
set xlr [expr $x + 3]
set ylr [expr $y + 3]
.video_game_window create rectangle $xul $yul $xlr $ylr -fill red
}
What are the variable names xul, yul, xlr, and ylr? Remember, we are drawing a rectangle, well, actually a square, 6 pixels by 6 pixels. The xul means x, upper left, and yul means y, upper left. The xlr stands for
x lower right, and so forth. Doesn't this look a lot like how we described
the Tic-Tac-Toe grid?
What is the { x y } in the Tcl command proc mouse_draw { x y }? We need
to collect the mouse coordinates. Remember how we did this in the simple
mouse experiment from before? The Tk graphics tool allows us to examine
the mouse coordinates using the special notation, %x and %y. We will
call our mouse_draw procedure in this manner:
mouse_draw %x %y
This command as it is won't work for us. Remember, the computer is listening
for an event. In this case we want to draw only when the left mouse
button (Bl) is held down and the mouse is moving (Motion).
We need to bind the event (B1-Motion).
bind .video_game_window <B1-Motion> { mouse_draw %x %y }
That's it. You have a simple paint program. My work of art is displayed in Figure 17.
|
|
There is a paint online version of Kid Pix, try it out and see how your paint program compares.
The Script:
set video_game_width 640
set video_game_height 480
canvas .video_game_window -width $video_game_width -height $video_game_height
pack .video_game_window
proc mouse_draw { x y } {
set xul [expr $x - 3]
set yul [expr $y - 3]
set xlr [expr $x + 3]
set ylr [expr $y + 3]
.video_game_window create rectangle $xul $yul $xlr $ylr -fill red
}
bind .video_game_window <B1-Motion> { mouse_draw %x %y }
You mastered basic graphics scripting. We didn't write a first person shooter game but you did master writing a simple draw program. You will need to play around with scripts presented here and go back and play with them. You have the web address for the Kid Pix online page -- why don't you see if you can copy some of the operations of Kid Pix.
A lot of cool computer graphics projects can be tackled using Tcl. Try to add keyboard bindings to your programs. Keep at it. I find computer graphics programming to be as fun as building with Legos. Don't take my word for it. Find out for yourself. Remember to use your new-found knowledge for the good of mankind.
Michael J. Norton is a software engineer at Cisco Systems.
Return to the Mac DevCenter
Copyright © 2009 O'Reilly Media, Inc.