Surface Game Canvas: JavaScript Source Code

Free HTML5 Game Tutorial for Beginners: Page 29

Desktop Resize Event Handler Mobile Resize Event Handler Draw to the Canvas

HTML5 Mobile Web Programming

Free Online Game Development Course: Design with HTML5

This Web page includes the entire source code which draws to the canvas for the Surface Game. JavaScript file surface-game-canvas.js responds to window resize events. surface-game-canvas.js saves coordinates from window resize events. surface-game-canvas.js reacts to touch and mouse movement on the canvas. surface-game-canvas.js draws digits as the user moves them across the canvas. surface-game-canvas.js snaps the digits into place within the answer box.

//HTML canvas element.
var cvs = null; 

//canvas context.
var context = null; 


//Bounding box of canvas.
var bb = null;

//Width and height of one image.
var iDimDigit = new Number(10);

//Half the dimensions of one image.
var iDimHalf = new Number(5);

//Vertical space between rows.
var iSpacer  = new Number(5); 

//Y coordinate to highlight 
//a digit when selected.
var iHighlightY = new Number(0);

//Array of images of 
//digits or symbols.
var aImgDigits = null; 

//Answer box rectangle:x,y,h,w.
var shapeAnswerBox = null; 

//Top box of draggable 
//digits, bottom Y coordinate.
var iDragBoxT = null; 

//Bottom box of draggable 
//digits, top Y coordinate.
var iDragBoxB = null;

// Offsets of the 
// bounding box of the canvas:
var iOffsetX = new Number(0);
var iOffsetY = new Number(0);

//Array of coordinates 
// in top row of images:
var aCoords  = null; 

//Array of coordinates 
// in bottom row of images:
var aCoordsB  = null;

//One coordinate;
var coord = null;

//Array of coordinates 
//representing answers. 
//Each coord contains an 
// index into the digit array.
var aAnswers = null;

// Index into aAnswers:
var iAnswer  = new Number(0);

//Constant: The maximum amount 
// of images to display [0..9].
IMG_COUNT = new Number(10); 

//Constant: The maximum 
// amount of images per row to display [0..4].
ROW_COUNT = new Number(5);

//Constant: The original square 
// dimension of one digit image. 
I_DIM_DIGIT  = new Number(32); 

/**
 * function loadDisplay() is called
 * to initialize fields for the 
 * code in this file.
 * This file modifies the canvas.
 *
 * @param {Number} nMobile:
 * 0 if Desktop.
 * 1 if Mobile.
 */
function loadDisplay(nMobile){
 
 cvs = document.getElementById('cv');

 context  = cvs.getContext('2d'); 

 aAnswers = new Array(ROW_COUNT);

 loadDigits(); 


 if (nMobile == 1){

  resizeCanvasMobile();

 }
 else {  
 
   eContent = document.getElementById('eContent');

   resizeCanvasDesktop();

 }
 
 cvs.addEventListener('touchmove', function (e) {
 
 e.preventDefault(); 
  
 if (e.targetTouches.length >=  1) {
   
  var t1 = e.targetTouches[0];
   
  drawTapGraphic(t1.pageX,t1.pageY);
   
 }
  
 },false);

}

/**
 * function loadDigits()
 * 1. create a local array of String.
 * Each String is the path to the source
 * for one image.
 * 2. Iterate over the array of String.
 * For each String create an instance of a 
 * new Image and assign the path to the source.
 * 3. Finally wait until the last image has loaded,
 * then call the function drawDigits().
 */
function loadDigits(){
 
 iDimDigit = Number(window.innerWidth * 0.09);
 
 aImgDigits = new Array(IMG_COUNT);
 
var aSDigits=[
 "assets/digit0.gif",
 "assets/digit1.gif",
 "assets/digit2.gif",
 "assets/digit3.gif",
 "assets/digit4.gif",
 "assets/digit5.gif",
 "assets/digit6.gif",
 "assets/digit7.gif",
 "assets/digit8.gif",
 "assets/digit9.gif"
];
 
 for (var i= 0; i < IMG_COUNT; i++){
 
  aImgDigits[i] = new Image();

  aImgDigits[i].src = aSDigits[i];

 }

 aImgDigits[IMG_COUNT-1].onload = function() { 
 
  drawDigits();

 };
}

Desktop Resize Event Handler

/**
* Resize the canvas
* for horizontal views.
* Canvas covers 1/2 the
* window width.
 */
function resizeCanvasDesktop(){ 
 
 var iW = window.innerWidth * 0.4; 
 
 iW = new Number(iW); 
 
 resizeCoords(iW); 
 
 iSpacer = iDimDigit/4;
 
 iDragBoxT = iDimDigit+iSpacer;
 
 iDragBoxB = iDimDigit * 2.75;

 iH = new Number(iDimDigit * 3.75); 
 
 resizeData(iW,iH);
 
 iOffsetX = bb.left;
 
 iOffsetY = bb.top; 
 
}

Mobile Resize Event Handler

/**
* resizeCanvasMobile()
* assumes vertical
* orientation.
* canvas width equals
* 90% of the window width.
 */
function resizeCanvasMobile(){
 
 var iW = window.innerWidth * 0.90;

 resizeCoords(iW);

 iSpacer = iDimDigit/2;

 iDragBoxT = iDimDigit+iSpacer;

 iDragBoxB = iDimDigit * 3.5;

 iH = new Number(iDimDigit * 4.5);

 resizeData(iW,iH);  

}

/**
 * function resizeData() is called
 * by both the desktop and the mobile
 * onresize event handlers.
 * 1. Set the canvas dimensions.
 * 3. draw the various graphics 
 * onto the canvas.
 * @param {Number} iW: Canvas width.
 * @param {Number} iH Canvas height.
 */
function resizeData(iW,iH){
 
 if (context != null){
 
  context.canvas.width = iW;

  context.canvas.height = iH; 

  bb  = cvs.getBoundingClientRect();

  drawAnswerBox();

  drawAnswers();

  drawDigits(); 

 } 
}

/**
 * function resizeCoords()
 * creates two arrays, 
 * representing two rows
 * of coord. 
 * Each coordinate represents 
 * the X coordinates of one digit
 * on the canvas display.
 *
 * @param {Number} iW:
 * width of top or bottom
 * draggable boxes of digits.
 */
function resizeCoords(iW){
 
 // function coordsLoad()
 // is defined in coords.js.
 aCoords = coordsLoad(
  iW,
  aCoords,
  0
 );

 aCoordsB = coordsLoad(
  iW,
  aCoordsB,
  ROW_COUNT
 );

 iDimDigit = aCoords[0].max;

 iDimHalf = iDimDigit/2; 
}


Draw to the Canvas


/**
 * function redraw() clears then redraws the area
 * where we dragged. Computations are minimized
 * in redraw() because it's called often.  
 */
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
 );

}

/**
 * function drawDigits() draws only the digits, 
 * after verifying each source image has loaded.
 */
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()); 

 } 
}

/**
 * function drawAnswers() is called in response
 * to window resizing. Therefore each answer's
 * X position has to be recalculated.
 */
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 drawAnswerBox()
 * Creates a rectangle for the answer box.
 * draws the box where answers are placed. 
 */
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 drawTapGraphic()
 * is called eventually by both mobile
 * and desktop versions of the game.
 *
 * @param {Number} iX: The tapped X coordinate.
 * @param {Number} iY: The tapped Y coordinate.
 */
function drawTapGraphic(iX,iY){
 
 try{ 
  
  if (iX < 0) iX = iOffsetX;
  
  if (iY < 0) iY = iOffsetY; 
  
  if (iY <= iDragBoxT){
   
   coord = coordFind(iX,aCoords);
   
   iHighlightY = iSpacer;
   
  }
  
  else if (iY >= iDragBoxB){
   
   coord = coordFind(iX,aCoordsB); 
   
   iHighlightY = iDragBoxB; 
   
  }
  
  if (coord != null){
   
  // Draw graphic inside the answer box:
  if (isInsideShape(iX,iY,shapeAnswerBox)== true){
    
    drawAnswerDigit(coord.idx);
    
   }
   
   // Draw graphic tapped:
   else if (isInsideShape(iX,iY,shapeAnswerBox) == false){

    redraw();

    drawHighlight();

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

function drawHighlight(){
 
// Highlight the digit the user tapped.
context.strokeRect(
 coord.min,
 iHighlightY,
 iDimDigit,
 iDimDigit
);

 context.globalAlpha = 0.5;

 context.fillStyle = "#0000ff";

  context.fillRect(
  coord.min,
  iHighlightY,
  iDimDigit,
  iDimDigit
 );

 context.globalAlpha = 1.0;

 context.fillStyle = "#000099";

}

/***
* @param {Number} index:
* index into array of images.
**/
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;

}
/**
 * function answersGet() is called
 * by the controller.
 * 
 * @returns {Array} aAnswers: Coord
 * representing every digit the player
 * dragged to the answer box.
 */
function answersGet(){
 
 return aAnswers;
 
}

/**
 * function answerSet() is called
 * by the controller to
 * create default answer data.
 * aAnswers ia an Array of Coord.
 * iAnswer is an index into aAnswers.
 */
function answersSet(){
 
 iAnswer = new Number(0);

 aAnswers = new Array(ROW_COUNT);

}

/**
 * function mouseMoveCanvas()
 * @param {MouseEvent} ev:
 * 
 * The mouse move event input clientX 
 * and clientY are the coordinates
 * of the entire browser screen, 
 * not the coordinates of the canvas.
 * Therefore translate the coordinates, 
 * and then call our drawTapGraphic() function.
 */
function mouseMoveCanvas(ev){
 
 ev.preventDefault();

 var a = translateToCanvasCoords(
  ev.clientX, 
  ev.clientY
 );

 drawTapGraphic(a[0],a[1]);

}

/**
 * function takes mouse movement from a 
 * desktop browser window,
 * then offsets the X and Y values, to represent
 * coordinates within the canvas itself.
 
 * @param {Number} x: Player's current
 * X coordinate.
 * @param {Number} y: Player's current
 * Y coordinate.
 * @return {Array} X and Y canvas
 * coordinates.
 */
function translateToCanvasCoords(x,y){
 
 var actualX = x - iOffsetX;

 var actualY = y - iOffsetY;

 return [actualX,actualY];

}

For the next section, 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.