Previous |
| Next |
The previous lesson described how to make a solitaire concentration game using the canvas.
When the player selected a card, we used the canvas itemconfigure
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 snack::sound
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 -to
option. We can use both the -subsample
and -to
options in the same command.
Here's a summary of the options we've just discussed.
Option | Arguments | Description |
---|---|---|
-to
| left top right bottom | Copy the image into these coordinates |
-subsample
| 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 card
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:
Command | Description |
---|---|
copy
| Copy a new image into the original image |
put
| Put a new color at a location (or locations) in the image. You can use the -to
option with this command.
|
With the copy
and put
image commands and the
-subsample
and -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 after
and update idle
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
changing.
The update idle
command makes the computer update the
display immediately.
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
start
and 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 playerTurn
procedure instead of using the itemconfigure
command that we used
in the previous lesson.
The new playerTurn
procedure looks like this. Notice that
after a player finds a match, we configure the image to be blank and
use the 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 after
command pauses for to see how it changes the speed of the cards flipping.
Write a flipImageY
procedure and use that to flip the
cards end-over-end instead of side to side. Change the itemconfigure
command in playerTurn
to use the flipImageY
to a
blank image instead.
copy
command.
copy
with the -subsample
option.
copy
command and the -to
option.
after
command to slow the computer
down enough for people to see the different images in an animation.
update idle
to 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
score is 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...
Previous | Next |