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.
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.

Previous

Next


Copyright 2007 Clif Flynt