HTML5 Canvas [168]
If we would like to display tile 19 (the ship pointing to the left, or in the 190-degree angle), we first need to find the x and y coordinates for the top-left corner of the tile, by calculating sourceX and sourceY.
Here is pseudocode for the sourceX calculation:
sourceX = integer(current_frame_index modulo
the_number_columns_in_the_tilesheet) * tile_width
The modulo (%) operator will return the remainder of the division calculation. Below is the actual code (with variables replaced with literals) we will use for this calculation:
var sourceX = Math.floor(19 % 10) *32;
The result is x = 9*32 = 288;.
The calculation for the sourceY value is similar except we divide rather than use the modulo operator:
sourceY = integer(current_frame_index divided by
the_number_columns_in_the_tilesheet) *tile_height
Here’s the actual code we will use for this calculation:
var sourceY = Math.floor(19 / 10) *32;
This works out to y = 1*32 = 32;. So, the top-left location on the ship_tiles.png from which to start copying pixels is 288,32.
To actually copy this to the canvas, we will use this statement:
context.drawImage(shipTiles, sourceX, sourceY,32,32,player.x,player.y,32,32);
In Chapter 8, we needed quite a lot of code to draw and translate the player ship at the current rotation. When we use a tile sheet, this code is reduced considerably.
Here is the code we will use to render the player ship. It will replace the renderPlayer() function in Example 8-12 in Chapter 8:
function renderPlayerShip(x,y,rotation, scale) {
//transformation
context.save(); //save current state in stack
context.globalAlpha = parseFloat(player.alpha);
var angleInRadians = rotation * Math.PI / 180;
var sourceX = Math.floor((player.rotation/10) % 10) * 32;
var sourceY = Math.floor((player.rotation/10) /10) *32;
if (player.thrust){
context.drawImage(shipTiles2, sourceX, sourceY, 32, 32,
player.x,player.y,32,32);
}else{
context.drawImage(shipTiles, sourceX, sourceY, 32, 32,
player.x,player.y,32,32);
}
//restore context
context.restore(); //pop old state on to screen
context.globalAlpha = 1;
}
NOTE
You will find the entire source code for Geo Blaster Extended (Example 9-1) later, in Geo Blaster Extended Full Source.
The renderPlayer() function divides the player.rotation by 10 to determine which of the 36 tiles in the shipTiles image instance to display on the canvas. If the player is in “thrust” mode, the shipTiles2 image is used instead of shipTiles.
This works because we have set the ship to rotate by 10 degrees with each press of the left or right arrow key. In Chapter 8’s version of the game, we set this to 5 degrees. If we had created a 72-frame tile sheet, with the player ship rotated in 5-degree increments, we could have kept the player.rotationalVelocity at 5. For Geo Blaster Extended, we only drew 36 tiles for the player ship, so we are using the value 10 for the rotational velocity. There certainly is no reason why we could not use 72 or even 360 frames for the player ship rotation tiles. This is only limited by creative imagination (and patience with a drawing tool).
Let’s look at the rotationalVelocity value assigned earlier in the gameStateNewGame() function:
function gameStateNewGame(){
ConsoleLog.log("gameStateNewGame")
//setup new game
level = 0;
score = 0;
playerShips = 3;
player.maxVelocity = 5;
player.width = 32;
player.height = 32;
player.halfWidth = 16;
player.halfHeight = 16;
player.hitWidth = 24;
player.hitHeight = 24;
player.rotationalVelocity = 10; //how many degrees to turn the ship
player.thrustAcceleration = .05;
player.missileFrameDelay = 5;
player.thrust = false;
player.alpha = 1;
player.rotation = 0;
player.x = 0;
player.y = 0;
fillBackground();
renderScoreBoard();
switchGameState(GAME_STATE_NEW_LEVEL)
}
Other new player attributes
Along with the change in the rotational velocity, we have also modified