Draw and Redraw to the Canvas

Free HTML5 Game Tutorial for Beginners: Page 10

Overview Draw Images Performance Tips Draw after Resize Events Function drawAnswerBox() Function drawAnswers() Function drawDigits() Function redraw() Draw after Touch Events Summary
Canvas of Desktop Surface Game

Overview

This article discusses how to draw images to the canvas, including performance hints for multiple redraws. This tutorial explains redrawing after a resize event and drawing after a touch event. This lesson covers drawing and redrawing to the canvas for the example Surface Game.

This article uses variables prepared when the browser resizes. See the Resize Canvas and Coordinates tutorial for details regarding preparing resized variables. Additionally the Reusable Coordinates tutorial explains how to scale the coordinates for digits based on canvas dimensions.

Draw Images to the Canvas

The method drawImage() is part of the canvas 2D context API. Method drawImage() is used often in the Surface Game's drawing functions. The parameters for drawImage() follow.

The following JavaScript demonstrates calling drawImage() with variable names from the previous list.

context.drawImage(
 imGraphic,
 imgX,
 imgY,
 imgW,
 imgH,
 cvsX,
 cvsY,
 cvsW,
 cvsH
);
		

Performance

Touch move and mouse move events may involve a lot of redrawing to the canvas. Redrawing can happen very often during the game, yet resize events happen less often. Therefore it's faster to calculate as much as possible during resize events. Any variable which can be calculated within an onresize event handler should be calculated in the onresize event handler.

For example with touchmove events, a redraw function may be called as fast as the device can fire touch events. The more processing in the touchmove event, the slower the device can fire touch events, the slower the game runs. See the Resize Canvas and Coordinates tutorial for details regarding processing dimensions during resize events.

Draw after Resize

The Resize Canvas and Coordinates and Reusable Coordinates tutorials discuss preparing variables for drawing after a resize event. When the canvas resizes, determine and save the new dimensions of digits, the answer box, the top and bottom boxes of digits, and the canvas. During drawing operations use the new saved dimensions.

Update a list of graphical coordinates during a resize event. Redraw each graphic onto the canvas after the coordinates are updated.

The Surface Game's resize event handlers adjust each coordinate's minimum and maximum properties within an array of coordinates. See the Create Reusable Code for Coordinates tutorial for details.

After each resize event the Surface Game redraws the answer box, the current set of answers and each draggable digit. Resize event handlers call drawAnswerBox(),drawAnswers(), drawDigits() and coordsLoad(). Discussion regarding functions drawAnswerBox(),drawAnswers() and drawDigits() follow. See the Reusable Coordinates tutorial for details regarding function coordsLoad().

Function drawAnswerBox()

Function drawAnswerBox() just draws the rectangle for the answer box with a white background and red outline. The following listing includes the entire drawAnswerBox() function.

First save the size of the answer box to local variable shapeAnswerBox. Second draw a solid white answer box. Third draw a red outline around the answer box. Line context.fillStyle = "#ffffff"; assigns white as the color to fill the answer box. Line context.strokeStyle = "#ff0000"; assigns red as the color to outline the answer box.

function drawAnswerBox(){
 
shapeAnswerBox = new Shape4Sides(
0,
iDimDigit+iSpacer*2,
iDimDigit*ROW_COUNT,
iDimDigit
);
 
context.strokeStyle = "#ff0000";
 
context.fillStyle = "#ffffff";
 
context.beginPath();  
 
context.fillRect(
shapeAnswerBox.sx,
shapeAnswerBox.sy,
shapeAnswerBox.sw,
shapeAnswerBox.sh
);
 
context.strokeRect(
shapeAnswerBox.sx,
shapeAnswerBox.sy,
shapeAnswerBox.sw,
shapeAnswerBox.sh
);

// Medium-dark blue
context.fillStyle = "#000099";

}

Function drawAnswers()

Function drawAnswers() is called by resize event handlers when a mobile device reorients or the Web browser's resized. The canvas resizes when the browser resizes. Therefore each digit's scale and location has to be redrawn

Array aAnswers contains a set of Coord references. The Coord references in aAnswers indicate which digits the player placed in the answer box. Each Coord.min is calculated based on the answer digit's location in the answer box. The following line of code multiplies the answer digit's location in the answer box i by the new digit dimension iDimDigit.

For example if a digit's location is to the far left, then i equals zero, and the digit's X coordinate equals zero. However if a digit has been placed third from the left hand side of the answer box, then i equals two. Assuming each digit's width equals 16 pixels, the following line of code calculates 2 * 16 = 32. The left side of the third digit in the answer box will be placed 32 pixels from the left.

c.min = i * iDimDigit;

Each Coord.idx property indexes into the array of images. The index locates the digit the user placed in the answer box. aImgDigits[c.idx] returns an image to draw in the answer box. The entire drawAnswers() function follows.

function drawAnswers(){

for (var i = 0; i < aAnswers.length; i++){
  
var c = aAnswers[i];
  
if (c != null && c.idx != null){
   
c.min = i * iDimDigit;
   
context.drawImage(
 aImgDigits[c.idx],
 0,
 0,
 I_DIM_DIGIT,
 I_DIM_DIGIT,
 c.min,
 shapeAnswerBox.sy, 
 iDimDigit, 
 iDimDigit
);

}
  
}
 
}

Function drawDigits()

Function drawDigits() draws the digits to the upper and lower drag boxes. Before drawing a digit, code verifies the image has downloaded with the following test.

if(aImgDigits[i].complete == true)

If the image hasn't downloaded, then drawing would generate an error.

JavaScript iterates over the array of images named aImgDigits. JavaScript draws the digits in order. First drawing to the top drag box, then drawing to the bottom drag box.

function drawDigits(){   
 
var i = 0; 
var j = 0;
try { 
  
for (i = 0; i < ROW_COUNT; i++){
 
 if(aImgDigits[i].complete == true) {
 
  context.drawImage(
   aImgDigits[i],
   0,
   0,
   I_DIM_DIGIT,
   I_DIM_DIGIT,
   aCoords[i].min,
   iSpacer, 
   iDimDigit,
   iDimDigit
  );
 }

}

for (i = ROW_COUNT; i < IMG_COUNT; i++){
 
 if(aImgDigits[i].complete == true) {
 
  context.drawImage(
   aImgDigits[i],
   0,
   0,
   I_DIM_DIGIT,
   I_DIM_DIGIT,
   aCoords[j].min,
   iDragBoxB, 
   iDimDigit,
   iDimDigit
  );    
 }

 j++;
}

}

catch (err){
 
 viewDebug(
  "drawDigits():"+err.toString()
 ); 

} 
}
		

Draw after Touch or Mouse Events

The Surface Game calls drawTapGraphic(iX,iY) when a graphic is tapped or touched. Parameters iX and iY represent the X and Y coordinates the player tapped or touched on the canvas. Both mobile and desktop versions of the game call function drawTapGraphic(iX,iY).

drawTapGraphic(iX,iY) determines which graphic was tapped. See the Create Reusable Code for Coordinates tutorial for details regarding finding graphics by coordinates. If the player was in the process of dragging an image to the answer box, then functions described in the Create Reusable Code for Coordinates tutorial, return an index. The index is used to return an image from an array of images. The index references the image which the user touched.

Function drawAnswerDigit(index) draws the most recently selected Image directly to the answer box on the canvas.

The code below demonstrates accessing an image reference with an index into the array of images. The name of the array of images is aImgDigits. Once we have a reference to the image, draw the image on the canvas.

The variable I_DIM_DIGIT is the actual unchanging dimension of each image. The variable iDimDigit is the dimension to scale each image based on the current screen size. See the Shape with Four Sides JavaScript Source Code for details regarding the shapeAnswerBox reference. The shapAnswerBox maintains the current dimensions of the answer box.

The following listing includes the entire drawAnswerDigit() function. Function drawAnswerDigit() displays the digit most recently selected by the player. The try-catch block is useful during development but should be removed during performance critical processes such as drawAnswerDigit(). Function drawAnswerDigit() calls Function redraw() which is covered next.

Variable iAnswer represents the number of answers the player has dragged to the answer box so far. If the player attempts to drag too many digits to the box, then clear the box and draw the digit to the far left. Otherwise draw the digit immediately to the right of the last digit. Notice both the answer box and the digit are outlined with a call to API method strokeRect(). The variable iAnswer is incremented in preparation for the next time the player drags a digit.

function drawAnswerDigit(index){
 
try {

// Clear the answers out
// for another set of 
// answers to display.
if (iAnswer >= ROW_COUNT){

answersSet();

}

redraw();

var im = aImgDigits[index];

var c = new Coord(
 (iAnswer * iDimDigit),
 0,
 index
);

//Index in the array.
aAnswers[iAnswer] = c;

context.drawImage(
 im,
 0,
 0,
 I_DIM_DIGIT,
 I_DIM_DIGIT,
 c.min,
 shapeAnswerBox.sy, 
 iDimDigit, 
 iDimDigit
);

context.strokeRect(
 shapeAnswerBox.sx,
 shapeAnswerBox.sy,
 shapeAnswerBox.sw,
 shapeAnswerBox.sh
);

context.strokeRect(
 c.min,shapeAnswerBox.sy,
 iDimDigit,
 iDimDigit
);

iAnswer++;

}

catch (err) {
 
 viewDebug("drawAnswerDigit(): "+err.toString());
 
}

coord = null;

}

The call to new Coord((iAnswer * iDimDigit),0,index) creates a new coordinate where the X position equals iAnswer * iDimDigit. Each time a digit is drawn to the answer box variable iAnswer is incremented. Variable iDimDigit represents the square dimension of one digit. Therefore iAnswer * iDimDigit returns the X position in the answer box to draw the new digit. The X coordinate represents the far left edge to display the new digit.

Function redraw()

The Surface Game's redraw() function executes in response to user interaction on the canvas. Function redraw() iterates over an array of images. The array is named aImgDigits. Each image is drawn according to coordinates saved in an array of Coord. See the tutorial Reusable Coordinates, for details regarding Coord objects.

Numbers ROW_COUNT and IMG_COUNT, assigned at the start of the game, indicate the end points of the first and last set of draggable digits. Integer iDimDigit represents the square dimensions to scale each draggable digit.

Numbers iDragBoxT and iDragBoxB represent the Y coordinates of the top and bottom boxes of draggable digits on the Surface Game's canvas. Variable shapeAnswerBox is a Shape4Sides reference which defines the coordinates and dimensions of the answer box.

The entire redraw() function follows. The entire canvas is filled with dark blue. The answer box is filled in white. Digits zero through four are drawn to the top box of draggable digits. Digits five through nine are drawn to the bottom box of draggable digits.

Last all digits the player currently dragged to the answer box are drawn in the answer box. The array named aAnswers contains a set of Coord representing digits the player dragged to the answer box. Coord.idx is an index into the array of images named aImgDigits. JavaScript iterates over aAnswers assigning each Coord reference to variable c. Method drawImage() draws the image retrieved from aImgDigits[c.idx].

function redraw(){  
 
 context.fillRect(
  0,
  0,
  bb.width,
  bb.height
 );

 context.fillStyle="#ffffff";

 context.fillRect(
  shapeAnswerBox.sx,
  shapeAnswerBox.sy,
  shapeAnswerBox.sw,
  shapeAnswerBox.sh
 );
 
 context.fillStyle="#000099";
 
 var j = 0;

 var i = 0;

 for (i = 0; i < ROW_COUNT; i++){ 
 
  context.drawImage(
   aImgDigits[i],
   0,
   0,
   I_DIM_DIGIT,
   I_DIM_DIGIT,
   aCoords[i].min,
   iSpacer, 
   iDimDigit,
   iDimDigit
  );

 }

 for (i = ROW_COUNT; i < IMG_COUNT; i++){
 
 context.drawImage(
  aImgDigits[i],
  0,
  0,
  I_DIM_DIGIT,
  I_DIM_DIGIT,
  aCoords[j].min,
  iDragBoxB, 
  iDimDigit,
  iDimDigit
 );

 j++;

 } 

 for (i = 0; i < aAnswers.length; i++){
 
  var c = aAnswers[i];


  if (c != null && c.idx != null){
 
   context.drawImage(
    aImgDigits[c.idx],
    0,
    0,
    I_DIM_DIGIT,
    I_DIM_DIGIT,
    c.min,
    shapeAnswerBox.sy, 
    iDimDigit, 
    iDimDigit
  );

 }

}

context.strokeRect(
 shapeAnswerBox.sx,
 shapeAnswerBox.sy,
 shapeAnswerBox.sw,
 shapeAnswerBox.sh
);

}

Summary

This article discussed how to draw images to the canvas, including performance hints for multiple redraws. This tutorial explained redrawing after a resize event and drawing after a touch event. This lesson covered drawing and redrawing to the canvas for the example Surface Game.

This article uses variables prepared when the browser resizes. See the Resize Canvas and Coordinates tutorial for details regarding preparing resized variables. Additionally the Reusable Coordinates tutorial explains how to scale the coordinates for digits across the canvas.

Have fun and love learning! For the next tutorial, tap the image icon containing text which says Next Lesson, or the right pointing arrow at the bottom of the page.

Previous Page Next Page
Copyright © 2015 Seven Thunder Software. All Rights Reserved.