One of the problems web app developers face is all the differences between browsers and monitors that we are trying to write for. We want our app to look good on everyone's screen. And we want it to look good on everyone's favorite browser.
Click this link to our Dog Race project for this post. This version has been updated to adapt to your browser.
Re-size your browser window and refresh the page. You should see the size of the canvas change. The finish line moves and the dogs still end at the right hand edge.
The good news is that there are several values that the browser will reveal to us. We can use JavaScript to gather information about the current size of the window. Look at the following code:
alert(window.innerWidth + " x " + window.innerHeight);
You can find all the details here at: W3Schools.
I know it is a bit annoying, but I have left the alert in the code so that you can try different window sizes and see the values on your own screen.
I have put the height of the window in there for you to see, but this page doesn't use it anywhere. Instead we will make horizontal adjustments only. We are not checking for changes to the size while the app is running, only when it is refreshed.
To make all this work, we set up a few global variables:
var currentWidth = window.innerWidth;
var canvasLeft = currentWidth * 0.05;
var canvasWidth = currentWidth * 0.88;
We have been using canvasLeft all along, but now we are going to set it to 5% of the window size. We are adding canvasWidth which will be 88% of the window size. That number came about from experimenting with different values.
It only requires a few changes to the original script to place things in the right spot no matter what the size of the window. First we will set the size of our game board:
function clearCanvas(thisColor){
ctx.fillStyle = thisColor;
ctx.rect(canvasLeft,0,canvasWidth,400);
ctx.fill();
}
We also need to make sure the finish line moves:
//draw the finish line
ctx.strokeStyle = 'black'
ctx.beginPath();
ctx.lineWidth = 1;
ctx.moveTo(canvasLeft + canvasWidth - 30,15);
ctx.lineTo(canvasLeft + canvasWidth - 30,380);
ctx.closePath();
ctx.stroke();
We will use the same variable to adjust the spot on the canvas that where we want the dogs to stop:
var leaderNose = canvasLeft + canvasWidth - 90;
When it came time to print the finishing order next to each dog at the end of the race, I decided to switch the alignment from left to right so that I didn't have to worry about the width of the character:
ctx.textAlign="right";
ctx.fillText(place,canvasLeft+canvasWidth,dog*60 + 60);
Sometimes the fanciest effects are the easiest to code. If you want to copy and paste the entire script into your own editor, here it is below. Don't forget to give Drop Your Anchor a try. C U Next Time!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="generator" content="CoffeeCup HTML Editor (www.coffeecup.com)">
<meta name="description" content="">
<meta name="keywords" content="">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="viewport" content="width=device-width; initial-scale=1.0; user-scalable=1;">
<title>Dog Race</title>
<style>body{color:#FFFFFF}</style>
<script type="text/javascript">
/* Demo Script for 'Writing Games with Canvas in HTML5'
© Copyright 2013, Budd Churchward
*/
var myRed = "#FE0000"; //red - first value is 254
var myBlue = "#0200DD"; //blue - first value is 2
var myYellow = "#FCFF00"; //yellow - first value is 252
var myMagenta = "#660066"; //magenta - first value is 253
var myOrange = "#FF6600"; //orange is - first value is 255
var myGreen = "#06FF00"; //green is - first value is 6
var myBrown = "#993300"; //brown is - first value is 153
var myBackground = "#007777"; //background -- first value is 0
var currentWidth = window.innerWidth;
var canvasLeft = currentWidth * 0.05;
var canvasWidth = currentWidth * 0.88;
function canvasDogRaces(){
// Get the canvas element.
canvas = document.getElementById("myCanvas");
// Make sure you got it.
if (canvas.getContext){
ctx = canvas.getContext("2d");
alert(window.innerWidth + " x " + window.innerHeight);
clearCanvas(myBackground);
drawDog(myGreen, canvasLeft + 20, 10);
drawDog(myYellow, canvasLeft + 20, 70);
drawDog(myBrown, canvasLeft + 20, 130);
drawDog(myRed, canvasLeft + 20, 190);
drawDog(myBlue, canvasLeft + 20, 250);
drawDog(myMagenta, canvasLeft + 20, 310);
//draw the finish line
ctx.strokeStyle = 'black'
ctx.beginPath();
ctx.lineWidth = 1;
ctx.moveTo(canvasLeft + canvasWidth - 30,15);
ctx.lineTo(canvasLeft + canvasWidth - 30,380);
ctx.closePath();
ctx.stroke();
// set start point for each dog and image array
for (var x = 0; x < 6; x++){
hisSpot[x] = canvasLeft + 2;
dogImage[x] = 0;
}
dogCatcher();
delayLoop=self.setInterval(function(){scooter(15)},20);
}else{
alert("Your browser does not\n support 'Canvas'");
}
}
var delayLoop = 0;
var runningDogX = canvasLeft;
var testSpot = 0;
var hisSpot = new Array();
var dogImage = new Array();
var thisDog = new Array();
thisDog[0] = "Arlo";
thisDog[1] = "O'Yeller";
thisDog[2] = "Brownie";
thisDog[3] = "Red Rover";
thisDog[4] = "Bo";
thisDog[5] = "Max";
var placeText = new Array();
placeText[0] = "1st Place: ";
placeText[1] = "2nd Place: ";
placeText[2] = "3rd Place: ";
function showWinner(dog){
ctx.fillStyle='White';
ctx.font="24px Arial";
ctx.textAlign="left";
ctx.fillText(placeText[place] + thisDog[dog],canvasLeft + 20,40*place+30);
}
function goAgain(){
location.reload();
}
function dogCatcher(){
for(var dog = 0; dog < 6; dog++){
dogImage[dog] = ctx.getImageData(hisSpot[dog], dog * 60 + 15,70 ,55);
//ctx.putImageData(dogImage[dog],0,dog * 60);
}
}
var leaderNose = canvasLeft + canvasWidth - 90;
var place = 0;
function scooter(){
var step = 1;
var keepGoing = 0;
for(var dog = 0; dog < 6; dog++){
if(hisSpot[dog]>0){
step = Math.floor(Math.random() * 8)+1;
hisSpot[dog] = hisSpot[dog] + step;
ctx.putImageData(dogImage[dog],hisSpot[dog],dog * 60 + 15);
keepGoing++;
if(hisSpot[dog]>leaderNose){
hisSpot[dog]=0;
if(place<3){showWinner(dog); }
place++;
ctx.textAlign="right";
ctx.fillText(place,canvasLeft+canvasWidth,dog*60 + 60);
}
}
}
if(keepGoing==0){clearInterval(delayLoop); }
}
function myDogSpot(x,y){
ctx.putImageData(dogImage,x, y);
}
function drawDog(thisColor,dogX,dogY){
// draw tail
ctx.beginPath();
ctx.lineWidth = 3;
ctx.strokeStyle = 'black';
ctx.moveTo(dogX + 5,dogY+32);
ctx.lineTo(dogX-10,dogY + 25);
ctx.closePath();
ctx.stroke();
// draw body
ctx.fillStyle = thisColor;
ctx.beginPath();
ctx.rect(dogX+8,dogY + 30,24,16);
ctx.rect (dogX,dogY + 35, 10, 25);
ctx.rect (dogX + 30,dogY + 35, 10, 25);
ctx.fill();
ctx.arc(dogX + 8, dogY + 38, 8, 0, 2*Math.PI, true);
ctx.arc(dogX + 32, dogY + 38, 8, 0, 2*Math.PI, true);
ctx.closePath();
ctx.fill();
// draw head
ctx.beginPath();
ctx.arc(dogX + 36, dogY + 22, 8, 0, 2*Math.PI, true);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.arc(dogX + 40, dogY + 22, 8, 0, Math.PI, false);
ctx.closePath();
ctx.fill();
// draw nose
ctx.fillStyle = 'black';
ctx.beginPath();
ctx.rect(dogX +46,dogY +22,3,3);
ctx.closePath();
ctx.fill();
// draw eye
ctx.beginPath();
ctx.rect(dogX +40,dogY +20,3,3);
ctx.closePath();
ctx.fill();
// draw ear
ctx.beginPath();
ctx.arc(dogX + 30, dogY + 18, 4, Math.PI, 0.2 *Math.PI, false);
ctx.closePath();
ctx.fill();
}
function clearCanvas(thisColor){
ctx.fillStyle = thisColor;
ctx.rect(canvasLeft,0,canvasWidth,400);
ctx.fill();
}
</script>
</head>
<body onload="canvasDogRaces()" bgcolor="#339999">
<h3>
<div id="rowOne_text">Welcome to the Races</div>
<div id="rowTwo_text">Pick Your Dog</div>
</h3>
<canvas id="myCanvas" width="1440" height="400" ;">
</canvas>
</body>
</html>
If you have been following this blog you will know that we are looking at a simple page that shows six dogs racing across the screen. You can find our sample page by clicking this link.
In this post we will focus on the end of the game and review how we move the images across the canvas. In a earlier version we were picking dogs at random and nudging them along one at a time. This version still has to move them one at a time, but we move each dog one after the other. We make it a race by picking a random distance for each move.
Testing the end of the race is simple enough. Our array, hisSpot[], keeps track of the location of each dog. We pick a random number and store it in step. Then use that to bump up the value in the array. Once that has been done we put a new copy of the image down at the new location. The left side of our image blots out any part of the dog that might have been visible in the old location. Here is the code that does that.
step=Math.floor(Math.random()*8)+1;
hisSpot[dog]=hisSpot[dog]+step;
ctx.putImageData(dogImage[dog],hisSpot[dog],dog * 60 + 15);
The code above picks a number between 1 and 8. Math.random()*8 actually picks a number between 0 and 7 so we just add 1 to that value. You can experiment with different values, I didn't want zero to ever come up which would mean that the dog didn't move.
So how do we get a dog to stop moving when it reaches the finish line. Here is a slick trick! Rather than set up yet one more array to keep track of which of the six dogs has finished, we will use hisSpot[] for two purposes. When we initiallized the array we set each value at canvasLeft, which currently is 120. So after we have moved the dog the last time, we change that value to zero. Later on we are going to cover the topic of user screen size and adjust the size of our canvas to look well on different devices. To be ready for this in the future I have set up a variable called leaderNose and given it a value that we can experiment with. By subtracting canvasLeft from this value we leave the door open for shifting things left and right on the page. We can move the board around and not have to hunt for a new value to put in here.
var leaderNose = 1230-canvasLeft;
With that in place, all we need to do is move our dog and then test the location:
if(hisSpot[dog]>leaderNose){
hisSpot[dog]=0;
Do you see where this takes us? Knowing that, we only move dogs that have a value greater than zero in hisSpot[]. So we wrap an if structure around the whole thing.
if(hisSpot[dog]>0){
.
.
.
}
That leaves us with one more problem to solve. We have started a loop running that keeps calling this function over and over. We need to stop that loop when the dogs are all done running. Here is another slick trick. Each time the function is called we set up a simiple variable: var keepGoing = 0;
Every time we move one of the dogs we increment that variable: keepGoing++;
So if we try to move all six dogs and every one of them has already finished, keepGoing will still be zero which tells us it is time to quit:
if(keepGoing==0){clearInterval(delayLoop); }
How cool is that?
Finally, let's display the first three finishers and put a place number next to each dog when he finishes the race. We need another global variable: var place = 0; and the following code:
if(place<3){showWinner(dog); }
place++;
ctx.fillText(place,1180,dog*60 + 60);
Let's look at the last two lines first. place++; will increment our counter. That means that it will be 1 when the first dog crosses the line. The third line simply puts the value of place on the screen. We are using an absolute value, 1180, here. Which means we will have to change it later when we want to support different screen sizes. Oh, well.
Now let's go back to the first line. Notice that we only call the function showWinner() when place is 0, 1 or 2. This is a rewite of the routine:
var placeText = new Array();
placeText[0] = "1st Place: ";
placeText[1] = "2nd Place: ";
placeText[2] = "3rd Place: ";
function showWinner(dog){
ctx.fillStyle='White';
ctx.font="24px Arial";
ctx.textAlign="left";
ctx.fillText(placeText[place] + thisDog[dog],canvasLeft + 20,40*place+30);
}
It is important that we call this function before we print the places next to the dogs for two reasons. First, We are using a small array to hold text for the placing and the first item in an array is zero. Second, the code here sets up the font color and size for the numbers we will print next to the dogs at the finish line.
You can find the complete code ready for you to copy and paste at the bottom of the previous post. If you would like see a project that uses all of these techniques and more, check out my web app: Drop Your Anchor.
..
In this post we will look at a second way to move our graphics across the canvas. Click this link here to see the page we will be coding. I had to make some changes to the project we have been working on because this version moves so much faster than the first. We will talk about why later.
I also changed the size of the canvas to make the game board much wider. This gives us a chance to actually see which dogs are pulling ahead and which ones are falling behind.
We will let every dog finish the race rather than stopping when the first one crosses the line. And we will print the names of the first, second and third place winners.
On the left side of the web page you will see images of the six dogs. I put them there while I was writing the code to see exactly what the image was that I was capturing at the beginning of the game. You will recall from the earlier posts that we have made our canvas wider than the dark area that you see on the screen. The actual game board is smaller and is shifted to the right from the edge of the window. We use the variable canvasLeft to determine this gap. This makes the page look more visually pleasing but it also gives us a little bit of works space to test things on. It is important that it is a different background color so that we can easily see where the edges are on the images that we manipulate in the game. I have left them here so that you can see how I use this space during game development. This is even more clear if you step through the script using Firebug.
In the previous post our puppies appear to move because we a capturing a strip of the image with the dog somewhere in the middle and then placing it back on the screen in a new location shifted only two pixels right of the original. We do not know where the dog is in the final image, so we have to stop and check for a color other than the background in a key location at the finish line. We repeatedly recapture and reposition images as the dogs race across the screen.
In this version we must capture six images, one for each dog, and then keep track of where we are putting them on the screen. The images are smaller and once they are captured they do not change so we only need to do that once, when we are first setting up the game. We also need to keep track of the location of each dog. We will know where each trotter is, so we don't have to test the screen for the winner. Instead we can check a value.
To do these two things we will declare two arrays:
var hisSpot = new Array();
var dogImage = new Array();
Remember that an array is a list of values. So hisSpot[] will be a list of six numbers representing the X coordinate of the dog's image. dogImage[] will be a set of six images stored in computer memory. These values need to be global so that they can be used and manipulated by several functions in our script. You simply place the declarations anywhere in your script as long as it is not inside of one of your functions. Sometimes you might want to put all your declarations in the same place at the beginning of the script. As your code gets longer, it is sometimes more convenient to locate them near the functions that will use them so that debugging and editing is easier.
You will find this code in the first function that gets called when the page is loaded. We only need to do this once.
// set start point for each dog and image array
for (var x = 0; x < 6; x++){
hisSpot[x] = canvasLeft;
dogImage[x] = 0;
}
dogCatcher();
We use a simple for loop to load hisSpot[] for each dog and give or dogImage[] an initial value. After these are initialized we call the function dogCatcher() to capture an image of each of the six puppies. Here it is.
function dogCatcher(){
for(var dog = 0; dog < 6; dog++){
dogImage[dog]=ctx.getImageData(hisSpot[dog],dog*60+15,70 ,55);
ctx.putImageData(dogImage[dog],0,dog*60);
}
}
We have to be sure that two things are done first. One: the dogs have to be already drawn on the canvas. Two: our array, hisSpot[], has to be filled with their locations. You will see that we are still multiplying our loop value, dog, times 60. That is the vertical spacing between the dogs. The +15 how far down the first dog is from the top of the canvas. The 70 is the width of the image that we need to capture, and the 55 is the height. The final line: ctx.putImageData(dogImage[dog],0,dog * 60); is for debugging. It puts a copy of the image that we just captured in the scratch space on the left side of the screen. If you experiment by changing the last two values in the line above it, you will see how handy this is to get just the image you need.
It is important that the dog itself is offset in the image so that there is more space behind his tail than there is infront of his nose. We need this background space to erase the tail on the canvas as the dog moves forward. That is why we set the original value at simply canvasLeft. You can experiment by adding and subtracting numbers in the getImageData line. For example:
hisSpot[dog] + 15
hisSpot[dog] - 15
Play around with this a little and it wll be very clear how that trailing background color makes the annimation work.
In the next few posts we will look at other parts of this program and see how they each work. If you need it, here is the full script that you can copy and paste into your own editor.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="generator" content="CoffeeCup HTML Editor (www.coffeecup.com)">
<meta name="description" content="">
<meta name="keywords" content="">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="viewport" content="width=device-width; initial-scale=1.0; user-scalable=1;">
<title>Dog Race</title>
<style>body{color:#FFFFFF}</style>
<script type="text/javascript">
/* Demo Script for 'Writing Games with Canvas in HTML5'
© Copyright 2013, Budd Churchward
*/
var canvasLeft = 120;
var myRed = "#FE0000"; //red - first value is 254
var myBlue = "#0200DD"; //blue - first value is 2
var myYellow = "#FCFF00"; //yellow - first value is 252
var myMagenta = "#660066"; //magenta - first value is 253
var myOrange = "#FF6600"; //orange is - first value is 255
var myGreen = "#06FF00"; //green is - first value is 6
var myBrown = "#993300"; //brown is - first value is 153
var myBackground = "#007777"; //background -- first value is 0
function canvasDogRaces(){
// Get the canvas element.
canvas = document.getElementById("myCanvas");
// Make sure you got it.
if (canvas.getContext){
ctx = canvas.getContext("2d");
clearCanvas(myBackground);
drawDog(myGreen, canvasLeft + 20, 10);
drawDog(myYellow, canvasLeft + 20, 70);
drawDog(myBrown, canvasLeft + 20, 130);
drawDog(myRed, canvasLeft + 20, 190);
drawDog(myBlue, canvasLeft + 20, 250);
drawDog(myMagenta, canvasLeft + 20, 310);
//draw the finish line
ctx.strokeStyle = 'black'
ctx.beginPath();
ctx.lineWidth = 1;
ctx.moveTo(canvasLeft + 1180-canvasLeft,15);
ctx.lineTo(canvasLeft + 1180-canvasLeft,380);
ctx.closePath();
ctx.stroke();
// set start point for each dog and image array
for (var x = 0; x < 6; x++){
hisSpot[x] = canvasLeft;
dogImage[x] = 0;
}
dogCatcher();
delayLoop=self.setInterval(function(){scooter(15)},20);
}else{
alert("Your browser does not\n support 'Canvas'");
}
}
var delayLoop = 0;
var runningDogX = canvasLeft;
var testSpot = 0;
var hisSpot = new Array();
var dogImage = new Array();
var thisDog = new Array();
thisDog[0] = "Arlo";
thisDog[1] = "O'Yeller";
thisDog[2] = "Brownie";
thisDog[3] = "Red Rover";
thisDog[4] = "Bo";
thisDog[5] = "Max";
function showWinner(dog){
ctx.fillStyle='White';
ctx.font="24px Arial";
ctx.textAlign="left";
ctx.fillText(placeText[place] + thisDog[dog],canvasLeft + 20,40*place+30);
}
function goAgain(){
location.reload();
}
function dogCatcher(){
for(var dog = 0; dog < 6; dog++){
dogImage[dog] = ctx.getImageData(hisSpot[dog], dog * 60 + 15,70 ,55);
ctx.putImageData(dogImage[dog],0,dog * 60);
}
}
var leaderNose = 1230-canvasLeft;
var place = 0;
var placeText = new Array();
placeText[0] = "1st Place: ";
placeText[1] = "2nd Place: ";
placeText[2] = "3rd Place: ";
function scooter(){
var step = 1;
var keepGoing = 0;
for(var dog = 0; dog < 6; dog++){
if(hisSpot[dog]>0){
step = Math.floor(Math.random() * 8)+1;
hisSpot[dog] = hisSpot[dog] + step;
ctx.putImageData(dogImage[dog],hisSpot[dog],dog * 60 + 15);
keepGoing++;
if(hisSpot[dog]>leaderNose){
//clearInterval(delayLoop);
hisSpot[dog]=0;
//leaderNose = leaderNose - 5;
if(place<3){showWinner(dog); }
place++;
ctx.fillText(place,1180,dog*60 + 60);
}
}
}
if(keepGoing==0){clearInterval(delayLoop); }
}
function myDogSpot(x,y){
ctx.putImageData(dogImage,x, y);
}
function drawDog(thisColor,dogX,dogY){
// draw tail
ctx.beginPath();
ctx.lineWidth = 3;
ctx.strokeStyle = 'black';
ctx.moveTo(dogX + 5,dogY+32);
ctx.lineTo(dogX-10,dogY + 25);
ctx.closePath();
ctx.stroke();
// draw body
ctx.fillStyle = thisColor;
ctx.beginPath();
ctx.rect(dogX+8,dogY + 30,24,16);
ctx.rect (dogX,dogY + 35, 10, 25);
ctx.rect (dogX + 30,dogY + 35, 10, 25);
ctx.fill();
ctx.arc(dogX + 8, dogY + 38, 8, 0, 2*Math.PI, true);
ctx.arc(dogX + 32, dogY + 38, 8, 0, 2*Math.PI, true);
ctx.closePath();
ctx.fill();
// draw head
ctx.beginPath();
ctx.arc(dogX + 36, dogY + 22, 8, 0, 2*Math.PI, true);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.arc(dogX + 40, dogY + 22, 8, 0, Math.PI, false);
ctx.closePath();
ctx.fill();
// draw nose
ctx.fillStyle = 'black';
ctx.beginPath();
ctx.rect(dogX +46,dogY +22,3,3);
ctx.closePath();
ctx.fill();
// draw eye
ctx.beginPath();
ctx.rect(dogX +40,dogY +20,3,3);
ctx.closePath();
ctx.fill();
// draw ear
ctx.beginPath();
ctx.arc(dogX + 30, dogY + 18, 4, Math.PI, 0.2 *Math.PI, false);
ctx.closePath();
ctx.fill();
}
function clearCanvas(thisColor){
ctx.fillStyle = thisColor;
ctx.rect(canvasLeft,0,1100,400);
ctx.fill();
}
</script>
</head>
<body onload="canvasDogRaces()" bgcolor="#339999">
<h3>
<div id="rowOne_text">Welcome to the Races</div>
<div id="rowTwo_text">Pick Your Dog</div>
</h3>
<canvas id="myCanvas" width="1200" height="400" ;">
</canvas>
</body>
</html>
In the last posting, we discovered that, using random numbers, we could shift part of our image to the right and make it appear that our dogs were trotting across the screen towards a finish line.
Today, let's ask our JavaScript to actually tell us who the winner is.
We need a way to store the names of our six dogs and then print the correct name on the screen when the first one reaches the finish line.
If you already know about arrays, skip down to the horizontal bar. The rest of us will take a minute to go over this topic quickly.
Coding languages give us a way to store values that we can call up later and manipulate when needed. These are called variables. Sometimes they contain numbers, and sometimes they store text. When they contain text we call them strings because we can think of them as a string of characters. Take a look at this line:
var thisDog = "Spot";
This creates a variable or a container that stores the characters S, p, o, and t in memory. That is simple enough if we had only one dog.
An Array is a way of storing a collection of strings that share a common variable. We can create a list of names like this:
var thisDog = new Array();
thisDog[0] = "Arlo";
thisDog[1] = "O'Yeller";
thisDog[2] = "Brownie";
thisDog[3] = "Red Rover";
thisDog[4] = "Bo";
thisDog[5] = "Max";
Each of these values is the name of a different dog, but they all share the same variable: thisDog followed by a value in the square brackets which is an index to each item in our list. The cool thing about this is that our index can be a variable itself! That means we can write code like this: thisDog[dog]. It is no coincidence that I put the variable dog in the brackets. That's the variable that we used in our random number. It will be the one that just reached the finish line.
Let's write a new function to display the winner's name.
function showWinner(dog){
ctx.fillStyle='White';
ctx.font="24px Arial";
ctx.textAlign="left";
ctx.fillText(thisDog[dog] + " is the Winner!",canvasLeft + 20,150);
}
We will also need to add a line to scooter() that will call this function at the end of the race. It is highlighted below:
if (testSpot.data[0] > 0){
clearInterval(delayLoop);
showWinner(dog);
}
Many of the lines in the new function will look familiar. They are like ones that we used to draw our dogs earlier. ctx.fillStyle= 'White'; sets the color of our text. This time we are using one of the HTML5 colors that all browsers will recognize.
ctx.font="24px Arial"; sets both the size and font of the text. Notice that sometimes I have used 'single quotes' around my code and other times I have used "double quotes." It doesn't matter which ones you use, they both do the same thing. But if you want to include either of those characters in your string, make sure you package it between two of the other. We did this when we named or yellow dog: thisDog[1] = "O'Yeller";
ctx.fillText( ... ); is the line that puts the text on the canvas. It needs three values. The first is the text that you want to print. And the next two are the X,Y coordinates of a location on the canvas where you want the text to appear. These last two values can be expressions like: canvasLeft + 20 or absolute numbers like: 150. But look at how we have set up the text: thisDog[dog] + " is the Winner!"
We are going to pull the name of the winner our of our array using the variable dog that we passed into this function. And then we use the + to add the string " is the Winner!" after it.
I skipped one line: ctx.textAlign="left"; This tells your computer how to place the text in relation to the X,Y coordinates in ctx.fillText(); Other choices are: right and center.
In the next post we will explore an alternate way of moving the dogs. In our first version the dogs stand still while they wait for their random number to come up and then scoot forward. Let's see if we can smooth this out by having each dog move in turn but make their step forward a random distance.
As always, you can copy the full script from this session below and paste it into your own editor. Experiment with it, and make it your own. C U next time.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="generator" content="CoffeeCup HTML Editor (www.coffeecup.com)">
<meta name="description" content="">
<meta name="keywords" content="">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="viewport" content="width=device-width; initial-scale=1.0; user-scalable=1;">
<title>Dog Race</title>
<style>body{color:#FFFFFF}</style>
<script type="text/javascript">
var canvasLeft = 120;
var myRed = "#FE0000"; //red - first value is 254
var myBlue = "#0200DD"; //blue - first value is 2
var myYellow = "#FCFF00"; //yellow - first value is 252
var myMagenta = "#660066"; //magenta - first value is 253
var myOrange = "#FF6600"; //orange is - first value is 255
var myGreen = "#06FF00"; //green is - first value is 6
var myBrown = "#993300"; //brown is - first value is 153
var myBackground = "#007777"; //background -- first value is 0
function canvasDogRaces(){
// Get the canvas element.
canvas = document.getElementById("myCanvas");
// Make sure you got it.
if (canvas.getContext){
ctx = canvas.getContext("2d");
clearCanvas(myBackground);
drawDog(myGreen, canvasLeft + 20, 10);
drawDog(myYellow, canvasLeft + 20, 70);
drawDog(myBrown, canvasLeft + 20, 130);
drawDog(myRed, canvasLeft + 20, 190);
drawDog(myBlue, canvasLeft + 20, 250);
drawDog(myMagenta, canvasLeft + 20, 310);
ctx.strokeStyle = 'black'
ctx.beginPath();
ctx.lineWidth = 1;
ctx.moveTo(canvasLeft + 580,15);
ctx.lineTo(canvasLeft + 580,380);
ctx.closePath();
ctx.stroke();
delayLoop=self.setInterval(function(){scooter(15)},2);
}else{
alert("Your browser does not\n support 'Canvas'");
}
}
var dogImage = 0;
var delayLoop = 0;
var runningDogX = canvasLeft;
var testSpot = 0;
function scooter(){
var dog = Math.floor(Math.random() * 6);
dogCatcher(dog);
myDogSpot(canvasLeft+2, dog * 60 + 15);
testSpot = ctx.getImageData(canvasLeft+575,dog* 60 + 31,10,10);
ctx.putImageData(testSpot,20,dog * 60 + 30);
if (testSpot.data[0] > 0){
clearInterval(delayLoop);
showWinner(dog);
}
}
var thisDog = new Array();
thisDog[0] = "Arlo";
thisDog[1] = "O'Yeller";
thisDog[2] = "Brownie";
thisDog[3] = "Red Rover";
thisDog[4] = "Bo";
thisDog[5] = "Max";
function showWinner(dog){
ctx.fillStyle='White';
ctx.font="24px Arial";
ctx.textAlign="left";
ctx.fillText(thisDog[dog] + " is the Winner!",canvasLeft + 20,150);
}
function goAgain(){
location.reload();
}
function dogCatcher(dog){
dogImage = ctx.getImageData(canvasLeft, dog * 60 + 15, 577, 55);
}
function myDogSpot(x,y){
ctx.putImageData(dogImage,x, y);
}
function drawDog(thisColor,dogX,dogY){
// draw tail
ctx.beginPath();
ctx.lineWidth = 3;
ctx.strokeStyle = 'black';
ctx.moveTo(dogX + 5,dogY+32);
ctx.lineTo(dogX-10,dogY + 25);
ctx.closePath();
ctx.stroke();
// draw body
ctx.fillStyle = thisColor;
ctx.beginPath();
ctx.rect(dogX+8,dogY + 30,24,16);
ctx.rect (dogX,dogY + 35, 10, 25);
ctx.rect (dogX + 30,dogY + 35, 10, 25);
ctx.fill();
ctx.arc(dogX + 8, dogY + 38, 8, 0, 2*Math.PI, true);
ctx.arc(dogX + 32, dogY + 38, 8, 0, 2*Math.PI, true);
ctx.closePath();
ctx.fill();
// draw head
ctx.beginPath();
ctx.arc(dogX + 36, dogY + 22, 8, 0, 2*Math.PI, true);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.arc(dogX + 40, dogY + 22, 8, 0, Math.PI, false);
ctx.closePath();
ctx.fill();
// draw nose
ctx.fillStyle = 'black';
ctx.beginPath();
ctx.rect(dogX +46,dogY +22,3,3);
ctx.closePath();
ctx.fill();
// draw eye
ctx.beginPath();
ctx.rect(dogX +40,dogY +20,3,3);
ctx.closePath();
ctx.fill();
// draw ear
ctx.beginPath();
ctx.arc(dogX + 30, dogY + 18, 4, Math.PI, 0.2 *Math.PI, false);
ctx.closePath();
ctx.fill();
}
function clearCanvas(thisColor){
ctx.fillStyle = thisColor;
ctx.rect(canvasLeft,0,600,400);
ctx.fill();
}
</script>
</head>
<body onload="canvasDogRaces()" bgcolor="#339999">
<h3>
<div id="rowOne_text">Welcome to the Races</div>
<div id="rowTwo_text">Pick Your Dog</div>
</h3>
<canvas id="myCanvas" width="840" height="400" ;">
</canvas>
</body>
</html>