The previous lesson described how to make a solitaire concentration game using the canvas.
When the player selected a card, we used the canvas
command to change the image of a card back to the image of a card face.
It would look cooler to show the card flipping over, instead of just changing it from front to back.
When we create an image with the
image create command,
we've created an object, just like we did with the
command. The image objects have commands associated with them, just
like the sound objects do.
One of the image object's commands is
copy. We can
use this command to copy one image to another. The nifty thing
is that when we copy one image into another, we can also modify it
with the option/value pairs.
Here's a couple of the things we can do. We can control where the new image gets copied into our original image, and we can control the size of the image we copy. We can even control the X and Y size separately.
We control the size by sub-sampling the image. Sub-sampling means that instead of taking every pixel from the new image and moving it into our original image, we skip a pixel, or two pixels, or 3 pixels, etc.
If we skip every other pixel and every other row, the new image will be 1/2 the size of the original. If we skip 2 pixels and 2 rows (and only take every 3'd pixel from the new image), we'll make an image that's 1/3 the size of the original.
When we subsample an image, we can tell Tcl/Tk to subsample the
columns and rows at a different rate. We do this by giving the
-subsample two arguments. The first argument will
be the sub-sampling rate for the X dimension (the columns) and the
second will be the sub-sampling rate for the Y dimension (the rows).
A value of 1 means take every pixel. A value of 2 means to skip every other pixel. A value of 3 means to skip 2 pixels, etc.
Here's an example that loads one of the card images and makes two sub-sampled copies of the image. We create a rectangle for each image, and then create the images over the rectangle to show what part of the image was copied.
This code makes images like this:
The left-most image is the original, the middle one is sub-sampled every other pixel in the X dimension. the rightmost image is sub-sampled every third pixel in the X dimension.
Try typing that code into Komodo Edit and running it. Then try changing the the sub-sampling options to see how it changes the image.
The image copy command will start copying at the upper left hand
corner of the destination image. We can change this using the
option. We can use both the
options in the same command.
Here's a summary of the options we've just discussed.
|left top right bottom||Copy the image into these coordinates|
|xCount yCount||Skip xCount pixels across and yCount pixels down when copying. This reduces the size of an image.|
Lets try using just one image (
card2) and copy the
image to it with different sub-sampling. The code looks like this:
You'll end up with a result like this:
Yuck. What happened is that Tcl/Tk copied an image sub-sampled to every other pixel, then copied one sub-sampled every third pixel over that, and then copied one sub-sampled every fourth pixel over that.
But it only changed the pixels it was copying. It didn't change the other pixels.
Sometimes, this is what we want to do, but it makes a funky looking card when we're trying to write code that looks like a card being flipped over.
We probably need to learn a new command.
The image object also has a
put command. We can tell Tcl/Tk
what color (or colors) to put into an area of an image.
For instance, to fill an image with a new color (like gray), we can use this command:
Try adding this before the last copy in the example above to see if it solves the problem (it does).
Here's a summary of the new commands:
|Copy a new image into the original image|
|Put a new color at a location (or locations) in the image. You can use the |
put image commands and the
-to options, we can make images
that look like they're being flipped around their center.
But we don't want to show a bunch of images side by side. That's great to see what's going on, but it doesn't look like a card flipping over.
We could do a loop like this:
This would actually work, but it's kind of kludgey, and it takes a lot of computer resources to create and destroy things. It's much faster to just change them a little.
We can use the
itemconfigure command that we looked at in
the previous lesson to change the image the canvas is displaying to a
temporary image. Then we can copy the card image into the temporary image
with different sub-samplings and different locations.
Now, we're ready to flip the cards. Here's the procedure that will do
the trick. Notice that we use
in the loops.
We use the
after command to slow the computer down a
little bit. Without the
after commands making it pause
between images, the cards would flip so fast we wouldn't seem them
update idle command makes the computer update the
In this procedure we make a new image object that we can copy the original images into. We change the sub-sampling each time we go through a loop, and calculate a new location around the center of the card to copy the image into.
This makes it look as if we were turning the card over until it's edge on to us.
Once we've made the first image very narrow, we start another loop where we use the second image and subsample less each time. This makes it look like we're continuing to flip the card over and showing more and more of the second image each time.
This procedure is another generic type procedure. We can change the
end images to flip a card from
face down to face up, or from face up to face down.
We could even use images of Harry Potter and Goyle to make it look like Harry was flipping and transforming into Goyle!
We call the
flipImageX procedure from the
procedure instead of using the
itemconfigure command that we used
in the previous lesson.
playerTurn procedure looks like this. Notice that
after a player finds a match, we configure the image to be blank and
bind command to put a binding on the images with
an empty command. Assigning an empty command means to do nothing. That's
the same as destroying the binding.
Try changing the number of milliseconds that the
command pauses for to see how it changes the speed of the cards flipping.
flipImageY procedure and use that to flip the
cards end-over-end instead of side to side. Change the
playerTurn to use the
flipImageY to a
blank image instead.
copycommand and the
aftercommand to slow the computer down enough for people to see the different images in an animation.
update idleto force the computer to update the screen after you change images in an animation.
You might have noticed that index we're using to keep track of the
player,score. I wonder if that means that we
could also have a
computer,score index and change this
one-person game into a two-person game to play against the computer...
Find out the answer to this and other thrilling questions in the next lesson...