Previous More Card Animation Next

We've done simple animation on the canvas for flipping the cards. We can also make the cards move slowly from one location to another.

When you (or the computer) finds a pair, the cards are moved from where they were on the board to your stack of matched cards.

Right now, the `matchCards` procedure just resets the coordinates of the card images, and presto, the cards teleport to the new location.

The Tk `canvas` command has a subcommand named `move` that will move an item on the canvas to a new location.

The syntax for the canvas `move` command is similar to the other canvas commands:

 `canvasName` The name of the canvas to search `move` Move items on the canvas `id` An identifier for the item (or items) to move. This can be a canvas id number or a tag. `xDistance` How far to move in the X dimension `yDistance` How far to move in the Y dimension

That's the only new command we need to move things on the canvas.

The tricky part (and it's not that tricky) is the geometry.

The easiest way to move the cards is to figure out the distance we need to move them, divide that by how many steps we want to use to move the cards, and then use a `for` loop to move the cards by the step distance for N steps.

We can use the `coords` to find out where the card is, and we know where we want it to go because we have that information in the global `concentration` array.

The canvas `coords` command will give us a two value list for the location of a card. This list is the X and then the Y coordinate.

We can use the `foreach` command to split that list into two values like this:

``````
foreach {c1x c1y} [.game coords \$id1] {break}
foreach {c2x c2y} [.game coords \$id2] {break}
``````

The next step is to calculate the distance to the end point. Because the coordinates have both X and Y values, and the `move` command uses X and Y, we need to calculate an X and Y distance separately like this:

``````
set d1x [expr \$concentration(\$prefix,x) - \$c1x ]
set d1y [expr \$concentration(\$prefix,y) - \$c1y ]
``````

In this game, we'll move the cards in 10 steps, and pause for 1/10 of a second between steps. That means it will take a second to move a card to the score pile, whether the card is moving across the board, or just a single card width.

The step size will be 1/10th the distance in the X and Y dimensions, which we can calculate using the `expr` command:

``````
set step1x [expr \$d1x / 10]
``````

And finally, the loop to move the cards. Notice the `update idle` that tells Tk to update the screen now instead of waiting until everything is done, and the `after 100` that pauses for 100 milliseconds (1/10 second) between passes through the loop.

``````
for {set i 0} {\$i < 10} {incr i} {
.game move \$id1 \$step1x \$step1y
.game move \$id2 \$step2x \$step2y
update idle
after 100
}
``````

The complete new procedure looks like this:

``````
proc moveCards {id1 id2 prefix} {
global concentration

.game raise \$id1
.game raise \$id2

# Get the X and Y coordinates  for the two cards

foreach {c1x c1y} [.game coords \$id1] {break}
foreach {c2x c2y} [.game coords \$id2] {break}

# Calculate the distance that this card is from where
# it needs to go.  Do this for both the X and Y dimensions.
# Do it for both cards.

set d1x [expr \$concentration(\$prefix,x) - \$c1x ]
set d1y [expr \$concentration(\$prefix,y) - \$c1y ]

set d2x [expr \$concentration(\$prefix,x) - \$c2x ]
set d2y [expr \$concentration(\$prefix,y) - \$c2y ]

# We'll take 10 steps to move the cards to the new location.
# Figure out 1/10 the distance to the score pile for each card.

set step1x [expr \$d1x / 10]
set step1y [expr \$d1y / 10]

set step2x [expr \$d2x / 10]
set step2y [expr \$d2y / 10]

# Loop 10 times, moving the card 1/10'th the distance to the
# new location.  Pause 1/10 of a second (100 ms) between movements.
# It will take 1 second to move a card from the current location to
# the desired location.

for {set i 0} {\$i < 10} {incr i} {
.game move \$id1 \$step1x \$step1y
.game move \$id2 \$step2x \$step2y
update idle
after 100
}

# Set the matched card location to stack the next card
# a bit lower than the previous cards.
incr concentration(\$prefix,y) 30
}
``````

Open the program from the previous lesson in Komodo and change the `moveCards` procedure. Presto, now it shows the cards moving.

Right now, the cards move at different speeds, so that they always take one second to reach the destination. Rework the `moveCards` procedure so that the cards move at the same speed, but take a different length of time to reach the match stack.

You can change the step1x and step1y values inside the loop. To be really tricky, make the cards speed up as they move, and then slow down again as they approach their destination.

This lesson is fairly short.
• One or more items on a canvas can be moved with the `move` command.

This looks cooler, but the computer isn't playing any better than a little kid. The next lesson will look at one way to make the computer play better.