Next page | Contents page |

Animating suit completion

This is more complicated than animating the deal. We will make all the cards from a completed suit fly towards the grey column on the right and end up with just the Ace displayed there. Let's make the completed Aces form a column. Create it when Spider is created, just before adding the event listeners:


  this.ACE_COLUMN = new Column (this.COL_WIDTH * 10 + 10,
                                Card.prototype.height + 50);
  // ACE_COLUMN.yT allows space for the remainder pile above it

That column needs to be drawn whenever the game is redrawn - in Spider.draw().

Each card in a completed column will fly in a straight line towards the same destination which will be the next available position in the ACE_COLUMN. Instead of setTimeout() we will use requestAnimationFrame (function_name) which has a similar effect except that instead of us specifying a delay time the browser will call our function at the start of the display hardware's next frame. These days the frames typically occur 60 times per second so if our function and the drawing take less than 1/60th second we will see display updates at that frequency. This technique is used a lot in games.

This is the function to be changed, in spiderC.js:


function moveTo (column)
{ column.addColumn (GAME.mouse.newCol);
  var oldLast = GAME.mouse.oldCol.getLastCard ();
  if (null !== oldLast) oldLast.reveal ();
  if (column.endsWithFullSuit ())
  { column.removeFullSuit ();
    GAME.game.nCompleted++;
  }
  GAME.game.draw ();
  GAME.mouse = null;
}

The removeFullSuit() method is generic so we will keep it in our framework for other games but we need a more Spider-specific routine here. Let's think about how to do it. Write some pseudocode.


  if (column.endsWithFullSuit ())
  { uiPaused = true
    get sublist from column, down from King
    get target position xy in ACE_COLUMN
    decide no of steps for animation to last say 2 seconds
    for each card in the sublist
    {
      get its xLeft and yTop position in the column
      dx = (xy.x - card.xLeft) / nSteps
      dy = (xy.y - card.yTop) / nSteps
      remove the card from the original column
    }
    put the data in GAME.animData, with stepNo = 0
    fly()
  }
  
  function fly()
  { ad = GAME.animData // shorter reference
    if (ad.stepNo < ad.nSteps)
    {
      game.draw()
	  for each card in ad.cards
	  {
	     add dx and dy to xL and YT, rounding
		 draw the card in its new position
	  }
      ad.stepNo++
      requestAnimationFrame (fly)
    }
    else
    {
      add the Ace to ACE_COLUMN
	  nCompleted++
	  record in history that suit is completed
      game.draw()
      uiPaused = false;
    }
  } 

That is basically what I am doing. You should be able to write it now as an exercise. Remember how we set up test card positions to enable suit completion to be seen and tested.

Note that another special entry is needed in the history so that a suit completion can be undone.

Next page | Contents page |