Page 1 of 1

Asteroid Blaster Tutorial Using HTML5,CSS3 and Javascript Rate Topic: -----

#1 fromTheSprawl  Icon User is offline

  • Monomania
  • member icon

Reputation: 513
  • View blog
  • Posts: 2,063
  • Joined: 28-December 10

Posted 02 October 2011 - 06:50 PM

This is a tutorial that will help you create your own Asteroid Blaster game! Don't worry, you'll (hopefully) learn a lot when you're done with this tutorial. I hope. Again. I hope. ^^

A little history on why I chose to do this thing:
Spoiler


What's it?
Asteroid Blaster is a game where asteroids fall down on earth and you have to thwart their benevolent attempt to wipe out all life on earth as we know it.

How's it play?
Little red lines appear falling down the screen and when they reach the bottom of the canvas game over. It's your job to stop them by clicking them, therefore destroying them.

What's needed to create it?
1. HTML5
2. Javascript
3. CSS3
4. The Kinetic.js library
PLEASE READ!
Without this library I would have never finished creating this thing. It allowed me to find the coordinates in the canvas. I almost stopped at one point because I can't seem to find a solution to my problem(getting the coordinates of the mouse on the canvas) but thanks to this, I pulled through. ^^
5. A picture of earth
6. A picture of a nuke
7. Presence of mind
8. Google Chrome Latest Version
Spoiler


I assume, dear reader:
I assume that you have at least a very basic understanding on how Javascript, HTML and CSS works together.

What you'll learn from this tutorial:

HTML5
- Draw multiple lines on the canvas
- Put images on the canvas
- localStorage and sessionStorage
- The <details> tag
- The <summary> tag
- The <hgroup> tag(actually this one sucks)(NOT INCLUDED,that's how much it sucks)
For those who still care about hgroup, see:
Spoiler


Javascript
- setTimeout and setDelay
- Basic object creation
- Manipulating the HTML and CSS files

CSS3
- Font - faces
- Blinking text
- Round edged boxes
- Text shadows

External Stuff
- Getting the coordinates from the canvas using the Kinetic.js library

So let's get it on! I'll divide this thing into sections so you could just CTRL + F something you'd like to know about.

TABLE OF CONTENTS

1.0 HTML5

1.1 Setting Up The HTML5 File
1.2 Setting Up The Canvas
1.3 Setting Up The Miscellaneous Bits
1.4 HTML5 Summary

2.0 CSS3

2.1 Setting Up External Fonts
2.2 Setting Up Text Shadow
2.3 Setting Up The Blinking Text
2.4 Setting Up The Round
2.5 CSS3 Summary

3.0 Javascript

3.1 Setting Up The Global Variables
3.2 Setting Up Kinetic.js To Find The Mouse Coordinates
3.3 Setting Up The Asteroids To Fall
3.4 Setting Up The Restart Function
3.5 Setting Up The Asteroid Object And The Last Bits
3.6 Javascript Summary

4.0 Important Notes,Links, and Thank You Message


1.0 HTML5

1.1 Setting Up The HTML5 File

If you've read my previous tutorial, you could skip this part, but if not, all you need to make a basic html file turn into an html5 file is to set the doctype as this:

<!DOCTYPE HTML>


This automatically makes the browser aware that the file is going to be interpreted as HTML5 technology.

This is the full skeleton we need to use:

<!DOCTYPE HTML>
<html>
	<head>
	</head>
	<body>
	</body>
</html>



Now, at the head part, we need to add a link for css, the Kinetic.js file, and empty tags for Javascript again.

<head>
<link rel="stylesheet" type="text/css" href="css4.css"/>
<script src="Kinetic.js"></script>
<script type="text/javascript">
//We left this empty because this is the part we will use to do most of the programming part
</script>
</head>



Now that that's done, let's proceed to the body part.

1.2 Setting Up The Canvas

First, let us setup the canvas. Inside your body tags insert this line of code:

<canvas id="theCanvas" width="1000" height ="500"  style="border:1px solid black" onclick = "hitIt()"></canvas>



Parts Of The Code Above:
id = We specify the id of the canvas for us to be able to access it using Javascript or CSS3.
width/height = Pretty much what they say they are. Please leave them the values as they are for now as those are the values used to do this thing.
style = We could have used CSS3 for this, but since it's just one, I put it in with the canvas tag. Please do note that real experts always separate the logic with the presentation. In the style attribute we told the browser to put borders on the canvas so to give us a feel of it's boundaries,
onclick = This calls a function when the canvas is clicked. This will be tackled more on the Javascript section of this tutorial.

The canvas as of now is empty, don't frown, we'll mess with it later.

1.3 Setting Up The Miscellaneous Bits

First of all, after your first body tag and before the last body tag add this div so it looks like this:

<body>
<div id ="box">
</div>
</body>



We need the box div to center the whole thing. Now let's paste in these codes inside above our canvas tags:

<h1 id = "title">ASTEROID BLASTER</h1></br></br>
		<table border="1" align="center">
		
			<tr>
			
				<td>HIT:<p id="hit" ></p></td>
				
				<hgroup>
				
					<td>TOP SCORE:<h1 id="tophit"></h1></td>
					
					<td>ENEMIES REMAINING:<h2 id="enemiesRemaining" ></h2></td>
					
				</hgroup>
				
				<td><p id="statusUpdates">STATUS UPDATES</p></td>
				
				<td><input type="button" value="MASTER RESET" onclick="resetAll()"/></td>
				
				<td><input type="button" value="START FALLING!" onclick="startFalling()" id="btx"/></td>
				
			</tr>
			
		</table></br>



I used headers(h1.h2,h3) for the information that we will display on the webpage and two buttons for specific tasks.

Headers(based on id)

hit = Shows your current score
tophit = Shows the top score
enemiesRemaining = Shows the remaining enemies needed to be defeated 'to advance to the next wave
statusUpdates = Will update status, more on this later

Buttons(based on value)

MASTER RESET = Resets everything, the fastest way to play again with the top score reset
START FALLING = Starts the avalanche(?) of asteroids
RESTART = Actually is the START FALLING button, it only appears once the game is in progress. Does not reset the top score

All of these bits are enclosed inside a table. Tables are separated by rows and columns. A basic structure of a table is this:

<table>
<tr>
<td></td>
</tr>
</table>



The table tag specifies the new table, tr tag specifies this is a row, and inside it the td tag specifies table data.

Now that all those are set up we need to use a little bit something under the canvas. Here, you will get acquainted with two new features for an HTML5 page, the details tag and the summary tag.

<details>
			<summary>COPYRIGHT 09 - 29 - 11</summary>
			<p>
			This has been another </p><div id="prodName">Nothing Else To Do</div> <p>production. 
			Thanks for checking this out!
			:)/>
			</p>
</details>



The summary tag contains the summary of the text included inside the details tag. What you'll see is just the summary of the page at first. There is an arrow beside the summary text and once clicked, it will show you the details not in the sumary. How cool is that? ^^

You might notice I've put in a div inside the details tag, we'll use it with CSS3 later.

1.4 HTML5 Summary

<body>
	
	<div id ="box">
	
	
		<h1 id = "title">ASTEROID BLASTER</h1></br></br>
		<table border="1" align="center">
		
			<tr>
			
				<td>HIT:<p id="hit" ></p></td>
				
				<hgroup>
				
					<td>TOP SCORE:<h1 id="tophit"></h1></td>
					
					<td>ENEMIES REMAINING:<h2 id="enemiesRemaining" ></h2></td>
					
				</hgroup>
				
				<td><p id="statusUpdates">STATUS UPDATES</p></td>
				
				<td><input type="button" value="MASTER RESET" onclick="resetAll()"/></td>
				
				<td><input type="button" value="START FALLING!" onclick="startFalling()" id="btx"/></td>
				
			</tr>
			
		</table></br>
		
		<canvas id="theCanvas" width="1000" height ="500"  style="border:1px solid black" onclick = "hitIt()"></canvas></br>
		
		<details>
			<summary>COPYRIGHT 09 - 29 - 11</summary>
			<p>
			This has been another </p><div id="prodName">Nothing Else To Do</div> <p>production. 
			Thanks for checking this out!
			:)/>
			</p>
		</details>
		
		</div>
	</body>



Everything in the HTML5 page is now okay! Let's go to the next part!

2.0 CSS3

The codes for this section are minimal but I placed them in a separate file nonetheless to at least please the designers out there, but the Javascript stuff I'm still not good at separating. Maybe after 10 years! Create an empty file, name it to whatever you named the css link is at the html file, then make sure the extension is in .css.

2.1 Setting Up The External Fonts

According from what I've read, you can now store the font on your website then force the users to use those fonts! Really good if you want to shove down Comic Sans or Chiller on people's throats(?) or eyes.

What I did is download two free fonts from DaFont from the game section, one is Tron inspired, and the other is a secret. Try checking it out for yourself. The respective fonts are owned by their creators and I praise them for sharing such wonderful fonts to the world.

To specify the fonts, first we need to put them inside the font-face tag, which looks like this:

@font-face
{
}



Now we need to put in two fonts, just put this in your css file:

@font-face
{
font-family: ffe;
src: url('ffe.ttf');
}
@font-face
{
font-family: tron;
src: url('Tr2n.ttf');
}



I now have two fonts I can use on my site! The font-family is the name that your font will use for the whole webpage, and the src attribute is where you saved those fonts. Easy like pie right? We can now call them using font-family on the tags of the html elements anytime we like.

Put this in please:

#title{
font-family:tron;
font-size:30px;
text-shadow: 10px 10px 10px #000000;
}

#prodName{
font-family:ffe;
font-size:30px;
}



The title element now is in the font of Tron, while the prodName element is now in our secret font. Whoa, what is that text shadow thing?

2.2 Setting Up Text Shadow

Text shadows are new to CSS3, and it allows you to put in shadows for your text. Neat eh? How it works:

text-shadow: 10px 10px 10px #000000;



This is the text shadow from our title element. Its basic outline is this:

text - shadow: [horizontal shadow] [vertical shadow] [blur distance] [shadow color];



Pretty easy to understand right? That's it! Our title now has a nifty shadow behind it. Shady!

2.3 Setting Up The Blinking Text

Put this in first:

#statusUpdates{
-webkit-transition:color 100ms ease-in; 
}



We will actually use a transition for the blinking stuff. Transition is new for CSS3, and it is used to specify changing styles. As you can see, we specified the color attribute to change it's style every 100 millisecs and the animation should ease-in or be smooth. As for the actual changing of colors? We'll do that on the Javascript part.

2.4 Setting Up The Round Edged Box

Before CSS3 and HTML5 people used PNGs to create round edged backgrounds, not anymore! With the introduction of the attribute border-radius, you can now create round edged boxes!

body{
border:2px solid;
border-radius:100px;
text-align:center;
}



This code will make our body sport a box with a radius of 100px. I don't know how that works exactly, but the more you make the radius closer to 360, the closer it becomes to being a circle. Hey, circle boxes or something! Now that's an idea.

2.5 CSS3 Summary

body{
border:2px solid;
border-radius:100px;
text-align:center;
}

#title{
font-family:tron;
font-size:30px;
text-shadow: 10px 10px 10px #000000;
}

#statusUpdates{

-webkit-transition:color 100ms ease-in; 
}

#prodName{
font-family:ffe;
font-size:30px;
}


@font-face
{
font-family: ffe;
src: url('ffe.ttf');
}
@font-face
{
font-family: tron;
src: url('Tr2n.ttf');
}



3.0 Javascript

WARNING: This part was the hardest to put up and the part where I almost gave up, if I miss on something here please point it out. This will get messy so ask away if you're not clear on any part of this one.

Begin!

3.1 Setting Up The Global Variables

At the empty script tags we made put this inside at the top
hit = 0;
enemiesRemaining=0;
worldEnded=false;
var thisPos = new Array();
var curPos = new Array();
topScore = false;



hit = Current score, in integer
worldEnded = A boolean that checks if it is game over
thisPos = An array containg 2 values, X and Y, the coordinates of the mouse, the values come from the functionality given to us by the Kinetic.js library
curPos = An array containing 2 values, X and Y, the coordinates of the mouse from the Kinetic.js library
topScore = A boolean that checks if the player got the top score

Now that the global variables are set, let us tinker with the Kinetic.js library!

3.1 Setting Up The Kinetic.js And Putting An Image To The Canvas Upon Load

Now that the canvas set - up our first priority is getting the mouse coordinates so that we'll know if the mouse is pointing on the right thing at the right time. To do this, import the Kinetic.js library by putting this inside the head tags:

<script src="Kinetic.js"></script>



This will import the Kinetic library in our webpage. I think the Kinetic library does other kickass stuff too, I just don't know what. We'll be using it's mouse coordinate finder functions. To do so, let's use this codes and make them work once the page is loaded:

		window.onload = function(){
				checkVars();
				var kin = new Kinetic_2d("theCanvas");
				var context = kin.getContext();
				var worldX = document.getElementById("theCanvas");
				var worldXContext = worldX.getContext("2d");
				var img = new Image();
				intervalId1 =0;
				intervalId2 =0;
				img.src = "earth.jpg"
				worldXContext.drawImage(img,0,0);
						kin.getCanvas().mouseup = function(){
							kin.drawStage();
						};
				 
						kin.setDrawStage(function(){
							var mousePos = kin.getMousePos();
					
							if (mousePos !== null) {
								mousePos.y;
								curPos[0] = mousePos.x;
								curPos[1] = mousePos.y;
							}
							else {
								curPos[0] = 0;
								curPos[1] = 0;
							}
							


						});
				};			



So it begins. First, upon the loading of the site we need to call upon the checkVars function, which checks the top score. We will see how it works later. For now, let us concentrate on how to set up the coordinates finder and how to put in the image. Now I'm not really sure how this thing works(refers to Kinetic.js) but to put up the coordinate finder first we need to get a context of the canvas. That is accomplished with these lines:

var kin = new Kinetic_2d("theCanvas");
var context = kin.getContext();



After that, we put in the image of earth for the canvas! It is actually easy to do. See this:

var worldX = document.getElementById("theCanvas");
var worldXContext = worldX.getContext("2d");
var img = new Image();
img.src = "earth.jpg"
worldXContext.drawImage(img,0,0);



We just get another context of the canvas, then declare a new variable img to hold our image. Then, we point the source to our image location. Then we draw the image using the context method drawImage. The three arguments we gave it is the img variable, the x coordinate, and the y coordinate where it would be drawn.

Note: For some reason, the image sometimes require multiple refreshes to appear instantaneously on the canvas, but our other image that you will see further on will always appear whenever we want it to. If any of you have an idea why this happens, please let me know.

We now arrive at the coordinate finder section!

		kin.getCanvas().mouseup = function(){
							kin.drawStage();
						};



This piece of code calls the drawStage method of the canvas whenever the mouse touches it. So what does drawStage do?

		kin.setDrawStage(function(){
							var mousePos = kin.getMousePos();
					
							if (mousePos !== null) {
								curPos[0] = mousePos.x;
								curPos[1] = mousePos.y;
							}
							else {
								curPos[0] = 0;
								curPos[1] = 0;
							}
						});



Now I don't know why it has set, probably because it is used by the library, but what's important is what's inside it. Inside, the function gets the mo
use position conveniently by using the getMousePos method of the canvas object using the Kinetic library. It returns an object that contains x and y, coordinates of the mouse. In our if statement, you can see that I give the first index of curPos the x value and the second index the value of y. Now if the current position is not in the canvas, set them both to 0. Everytime we move inside the canvas, curPos is updated! Cool huh.

As promised, here is the checkVars function.

3.2 Setting Up The Top Score

It's a little early for the scores, you might say, we don't even have the game yet! Still, this function is called at the start of the page so we will discuss it here. I will now introduce you to two new HTML5 elements, localStorage and sessionStorage.

What They Are In A Brief Explanation
localStorage stores variables in your browser that will be kept forever until you remove them programmatically or clear the cache. Session storage keeps the variables until you close the browser. Both are easy to use! To create both local or session variables, just put in localStorage.variableName or sessionStorage.variableName. Easy! ^^

	function checkVars(){
			
				if(sessionStorage.hit==0||sessionStorage.hit==undefined){
					sessionStorage.hit=0;
				}
				
				hit = sessionStorage.hit;
				document.getElementById("hit").innerHTML = hit;
				
				if(localStorage.tophit>=sessionStorage.hit&&localStorage.tophit!=0){
					document.getElementById("tophit").innerHTML = localStorage.tophit;
				}
				
				else if(localStorage.tophit==undefined||localStorage.tophit==0){
					localStorage.tophit=0;
					document.getElementById("tophit").innerHTML = 0;
				}

				if(sessionStorage.enemies==undefined||sessionStorage.enemies==0){
					sessionStorage.enemies = 5;
				}
				
				enemiesRemaining=sessionStorage.enemies;
				document.getElementById("enemiesRemaining").innerHTML = enemiesRemaining;
			}



If the variable we set on localStorage or sessionStorage does not exist, it has a value of undefined. At the first run we check first if sessionStorage is either undefined or 0. If it is, still set it to 0. If it's 0, we set it to 0 because it is 0. If it is undefined, we set it to 0 to bring that session variable to life.

The next lines uses our hit global variable and takes the value of sessionStorage.hit. Why? We use sessionStorage.hit to store the current score of the player. Now the line:

document.getElementById("hit").innerHTML = hit;



Gives the hit element on the html body the value of our hit global variable.

document.getElementById("elementId").innerHTML = value;



This is the standard syntax for changing the values of the elements inside an html page. The thing now updates our webpage! Cool.

Now the next lines check if localStorage.tophit is either undefined or 0. If it's undefined, it's a new game, if it's 0, then it means the last player didn't score. Either way this upon evaluating true will make the localStorage.tophit alive and with the value of 0. We also update the top score element in the html page and set it to 0.

The next line again checks if the sessionStorage.enemies variable is alive. This variable is used to determine how many enemies the player will face. Then we give it to the enemiesRemaining global variable and put it up in our html page for the player to see.

We're done with this part, off to the next!

3.3 Setting Up The Asteroids To Fall

Here is the heart of the game, making the asteroids fall!

		function startFalling(){

				intervalId1= setInterval(function(){
				
					var asteroidx = new Asteroid();
					
					do{
						intervalId2 = setInterval(function(){
						asteroidx.fallDown();
				}
				,20)}while(this.alive==true);
				
				}
				,500);
				
				btnStarter = document.getElementById("btx");
				btnStarter.setAttribute("value","RESTART");
				btnStarter.setAttribute("onclick","restart()");
			
			}



Now this is the part where most of the experts would likely be angry with. This little function generates asteroids and make them fall down every 500ms, with the speed of their descent set to 20ms per pixel. Why did I say this part is the one that they might get angry with? This lines of code will bog down your browser and make it crash if not handled properly. I tinkered with this many times to add additional stuff(such as klaxons) but in the end I didn't, since the browser slowed down to a halt. I am aware that threads could really help with this one, but a quick research shows that threads aren't used in Javascript. That's why in an attempt to replicate them, I used the setInterval function.

What is setInterval?
This method is native to Javascript. It runs a specific function again and again in the time you specify next to it.

WARNING: setInterval does your code infinitely and will not stop unless you stop its evil reign. The solution? The method clearInterval.

How it works:
Each setInterval function returns a unique interval Id. Once you pass it to the clearInterval method, the setInterval function ceases to exist. Aha! Take that, infinity!

Now let me explain the codes. As you can see, my first interval runs every 500ms, and it creates an asteroid object. We give intervalId1 the value of the id of the 1st setInterval. After we create a new asteroid, we have a do while loop which calls the method of the object asteroid fallDown to, uh fall down. Another setInterval! This next interval ensures that our asteroid moves every 20ms, and continues to do so until it is not alive.

We will proceed with the Asteroid object shortly so I can discuss in detail how we make the asteroids fall down.

On to the ne... Oh, there are three lines left on this function. We have the btnStarter variable which gets the element of the btx id'ed button in our html page. Now, we can do stuff with that button! We can set its attributes to other things. For example, I now change the text on the button to "RESTART", and we point it to another function, restart.

By the way I forgot to say the function startFalling is paired with the button btx. Once clicked, the asteroids will start falling. Duh.

Now let's give the restart function some love!

3.4 Setting Up The Restart Function

What if you want to start over again? Restart!

function restart(){
				sessionStorage.hit = 0;
				sessionStorage.enemies = 0;
				location.reload(true);
			}



This function is only available once we click the START FALLING button. As you can see, a restarted game sets the sessionStorage.hit(player's score) to 0. sessionStorage.enemies(number of enemies) to 0, then we reload the page. That's it. ^^

3.5 Setting Up The Asteroid Object And The Last Bits

We're here! We will attempt to create an object in Javascript to justify calling it an OO language. I kid. Haha. Anyway we'll make an asteroid object.

Object name:Asteroid
Description: It's a little rock that falls down from the sky. We depict them as lines on the canvas here.
Methods:
fallDown = Makes the asteroid fall down
trajectory = Picks the asteroids trajectory in falling down.(Actually, just right or left)

It also has a constructor!(Please feel free to contradict me on this one)

In Javascript, to create an object, you first declare a function then a name of that object:

function Transformer(){
this.name = "Objectus Javascriptus";
}



We give it attributes by putting in the this keyword to specify that the name next to the dot will be a variable of that object. I say it's a constructor since we can give it values upon object creation.

To add methods to the object, we use the prototype keyword. How do we do that? See:

Transformer.prototype.transform = function(){
//Do stuff here, let's try...
alert("TRANSFORM! CHECHECHECHENG!");
}



That's it. As for our own Asteroid object, here's what it looks like:

function Asteroid(){
			
				this.world = document.getElementById("theCanvas");
				this.worldContext = this.world.getContext("2d");
				this.worldContext.strokeStyle = "#FF0000";
				this.x = Math.floor(Math.random()*999);
				this.y = 0;
				this.alive = true;
				this.update = false;
				this.id = intervalId2;
				
				if(this.x>500){
					this.direction = "right";
				}
				else{
					this.direction = "left";
				}
				
			}



This object gets a private context of the canvas. We also give it strokeStyle! What is that thing? It just gives our lines the color of red. The private x we give a random number from 0 to 999, corresponding to the x in the canvas. It will determine where the asteroid will appear. Y is set to 0 since the asteroid should appear always above the canvas. We have a variable alive which is set to true to denote that this asteroid is alive. The update thing is used to determine if the asteroid got in the news(more on this later). We have an id variable to get in the setInterval id currently inside the global variable intervalId2 so that we know where it started. The last one we have a little if-else statement. If x is greater than 500, the asteroid will fall from the right, and if it's not, then it will fall from the left.

Let's now discuss the object methods: fallDown and trajectory. The method fallDown is used to do lots of things. First of that, is to ensure that the asteroid is really falling down. It also checks if the asteroid is alive, and if it successfully hit the surface, then it's game over. The method trajectory on the other hand checks if the asteroid touches the sides of the canvas. If it does, the asteroid will change its direction and head for the opposite side. This is to ensure that there are no escaping asteroids. What do you think will happen if the asteroid goes past the side of the screen? Impending doom.

To discuss the details, let us start with the fallDown method first:

Asteroid.prototype.fallDown = function(){

			if(worldEnded==false){
				if(this.alive==true){
					this.worldContext.beginPath();
					
					if(((thisPos[0]-this.x)<10&&(thisPos[0]-this.x)>-10&&(thisPos[1]-this.y)<10&&(thisPos[1]-this.y)>-10)&&thisPos[0]!=0&&thisPos[1]!=0)
					{
						this.alive = false;
						this.worldContext.strokeStyle = "#FFFF00";
						this.worldContext.arc(this.x,this.y,10,0,Math.PI*2,true);
						this.worldContext.stroke();
						this.worldContext.strokeStyle = "#FF0000";
						statUp ="</br> Asteroid #"+intervalId2+ " has been succesfully destroyed!";
						setStatusUpdate(statUp);
						//this.y = y;
						//this.x = x;
						hit++;
						enemiesRemaining--;
						document.getElementById("hit").innerHTML = hit;
						document.getElementById("enemiesRemaining").innerHTML = enemiesRemaining;
						checkForTopScore();
					}
					
					else
					{
						this.worldContext.moveTo(this.x,this.y);
						this.trajectory();
						this.worldContext.lineTo(this.x,this.y);
						this.worldContext.stroke();
						if(this.y>250){
							if(this.update==false){

							statUp ="</br> <i>Asteroid #"+intervalId2+ "</i> has entered the atmosphere!";
							setStatusUpdate(statUp);
							this.update=true;
							}
						}
						
						if(this.y>500){
						this.worldContext.fillStyle="#FF0000";
						this.worldContext.arc(this.x,this.y,100,0,Math.PI*2,true);
						this.worldContext.stroke();
						this.worldContext.fill();
						this.intervalId = intervalId2;
						this.alive = false;
						this.alive = false;
						worldEnded = true;
						}
					}
					this.worldContext.closePath();
				}
			}
			
			else if(worldEnded==true){
			
				var worldX = document.getElementById("theCanvas");
				var worldXContext = worldX.getContext("2d");
				var img = new Image();
				img.src = "nuke.jpg";
				worldXContext.drawImage(img,-300,-300);
				
				if(topScore==true){
					alert("NOOOOOOOOOOOOOOOOO!\nOh yeah, congrats you got the top score. NOOOOOOOOOOOOOOOOOOOOO!");
					topScore =false;
				}
				
				window.clearInterval(this.intervalId);
				window.clearInterval(intervalId1);
				statUp ="</br> THE WORLD HAS BEEN DESTROYED!";
				setStatusUpdate(statUp);
				}
			}



It is easily the largest method on this thing, because it does a lot of stuff. Here's a basic outline:

if world end is false
	if this asteroid is alive is true
		if it was hit by your missile(this is the big if)
			die asteroid!
		else
			move asteroid!
				if asteroid touches surface
					die world!
else if world end is true
	if asteroid is dead
		show nuke, game over
		if topscore is true
			show topscore dialog
		set status



That's the basic outline. Let's focus on these major parts:

1. If the asteroid is alive, and it is hit by you
This condition is evaluated if the game is still on and the world has not yet ended. What we do is open up a contextPath of the canvas of this asteroid object for us to render the next moves. Now we will evaluate if the current position(which is updated by clicking on the canvas, see function hitIt) is close to the position of the mouse hit on the canvas. If it is, we will destroy that asteroid. Sadly, we have a problem, but fortunately, we have a workaround.

THE PROBLEM: I haven't found a way how to clear an asteroid and make the other asteroids fall normally. I attempted many times and I was faced with buggy screens. If anyone knows how to clear just a particular context in the canvas, please let us know.

THE WORKAROUND: When an asteroid dies, I just freeze them in their positions and put a circle on the last point they were alive. This way, it doesn't break the game. The method strokeStyle states the we will use the color yellow when an asteroid dies, and it will encircle the point of the asteroid. Be aware though that not changing it back to the default color of the asteroids when closing the context path will cause problems, so change the strokeStyle again to red before closing the context path.

By the way, I assume that if statement on checking if the asteroid is hit must be cryptic or ugly on your eyes, so let us inspect it further:

if(((thisPos[0]-this.x)<10&&(thisPos[0]-this.x)>-10&&(thisPos[1]-this.y)<10&&(thisPos[1]-this.y)>-10)&&thisPos[0]!=0&&thisPos[1]!=0)



Yikes, it is ugly, but essention. What it does is check if the current mouse click x and y coordinate minus the x and y coordinate position of the asteroid is less than 10. What does this mean? It means you hit it baby! We set it to 10 so that it would be a little easy to click on the asteroids. Hey, there is a trailing and condition, if the current x and y of the mouse is not equal to 0 should be true. Why? Well, if that condition isn't true, then all our asteroids will die upon birth. If we don't click on the canvas the coordinates of the mouse would be 0 and 0.

That would be equal to the birth position of the asteroids. They'll all die without getting a shot at destroying the world. Sad eh? This is further complicated that we have a method that sets the mouse point to 0 everytime we click after a half of a second, which will be discussed further below. Now you see why that condition is needed, hope this clears this if conditions!

2. If the asteroid is alive, and it is not hit(you missed? What?)
The else statement is where the movement of the asteroid continues. Our asteroid moves at a pace of 1px per 20 ms. First, we move our imaginary pointer to the current position of the asteroid, then we call the trajectory object method.

The trajectory Method
The trajectory method checks if the asteroid is touching the screen. If it is, we change the value of direction to either right or left. Note that we must specify the boundary of the canvas and use the x coordinate because the x coordinate is what is used to determine horizontal position. If the direction is right, we decrement x so that the asteroid will move left, and if not, increment all so that it will move right.

Back to the fallDown method! Now we will see where we use the statusUpdate element of the html page. It is the blinking text I told you about earlier. We will use this as a kind of "news updates", it shows heartening messages such as "Asteroid !@#$ has entered the atmosphere!" and "The World Ended!" flashing. I don't know why it will flash that last message when the world ends, who sends it anyway? Everyone on earth is dead. Anyway, for an asteroid to qualify on the news it must get past the invisible atmosphere of our earth, that is 250 on the y coordinate. If it is true, we call the method setStatusUpdate and send the message.

The setStatusUpdate Method
This method is used to manipulate the element statusUpdate on the body of the html page. It blinks, and will only be triggered once an asteroid enters our atmosphere. Kind of a warning system, really. We use a little variable here to determine if we will change the color to black(visible) or white(invisible) of the statusUpdates element. Remember the part where we made a transition attribute on the CSS3 file? This is where we manipulate it. Upon changing of the color, this will smoothly transition the element from one color to the next. We used the setInterval again to make it blink all the time.

Now once we send the message, there is only once condition left to check inside, if the asteroid hits the floor of the canvas, it is game over. Now we use fillStyle, because we will use a circle to show the point of impact, and we will use the color red. Once it hits the canvas, a circle of red will show on that point to denote it hit the canvas, then boom! The world ends. We set the appropriate boolean flags to their right values, and thenm give this asteroid the last interval id of intervalId2 for us to close it properly.

After everything, we opened a path up above, we close the path here.

3. What if the world ended? Aka GAME OVER, by the way you suck.
If the world ends, we once again place another image on the canvas. This time, a pciture of a nuke. See that in the drawImage method, I used negative values? It is used so that the big image will center on the screen. If your image is too big and you want it to center, calculate the coordinates farther up so that it will show the center. I imagine you could also resize the image, but whatever. Now we clear the setIntervals OR ELSE the game will still continue to bog down the mighty Google Chrome. We do this by using the method of the window.clearInterval and giving it the intervalId, first, of this asteroid, the next, of the main setInterval method which creates the asteroid. (If you still remember that part.)
We also send a message to the setStatusUpdate to show that the world ended in the statusUpdates element. (I guess the Klingons will receive it.)

We're finally getting finished on this thing! These are the last things we need to cover:

- How we check for top score when the game ends
- How to check if we hit an asteroid
- Resetting the game aka erase the top score your grandma set that you can't beat

The checkForTopScore method
We now check if the top score(if it exists and is greater than 0) is equal to or less than hit. If it is, we have a new top score, so we change the value of the localStorage topscore to the score of the current player, then we change the topscore text on the html page. Then, we check if there are no enemies remaining. The way this game works, you have to clear a set amount of enemies, then proceed to battle to the next wave. We do this by multiplying the sessionStorage amount of enemies by 2, and giving it back to the sessionStorage enemies value so it will be seen on the next iteration of the game that the next wave is bigger. Oh, we keep the current score of the player too so that it will carry over the next batch of enemies. We tell the player by using the alert box the next number of enemies he/she/it needs to destroy for them to advance to the next round. Don't worry, it will show it anyway on the element in the body.

The hitIt method
This is an important method, I almost left it out. The method is used in conjunction with the Kinetic.js method that is loaded at the start of the page. Once you click the canvas, this method is triggered. What it basically does is get the current coordinates from the canvas from the Kinetic.js method, then it updates itself. An asteroid checks if it's hit every ms and if it coincides or is near with the current x and y in this method, that asteroid is toast. Oh, we also have a little setInterval method here, to empty the sights, or emptySights every half of a second. Why?

The emptySights
You see, if we just let the current coordinates update itself and not clear it, what would you think would happen if we click on a section? Yep. Even if you haven't clicked on that section, any asteroid passing there would be destroyed. So to avoid this, we set the coordinates of the clicks to both 0 every half of a second, so that it will be fair game again and only the parts you'll click will be considered the ones that will destroy an asteroid on that vicinity.

The resetAll method
We have a master reset method button by the way, and it clears everything. It is the same as the restart button, only the master reset button, once triggered, will erase the top score. The top score will still exist if you don't clear your cache on your browser. The only way to remove it is by triggering this button. See, it acts as if it's a real game. ^^
We also reset all the scores and enemies, then refresh the page.

It's done! Finally!

3.6 Javascript Summary
Note: Included everything in the head element of the body.
<head>
		<link rel="stylesheet" type="text/css" href="css4.css"/>
		
		<script src="Kinetic.js"></script>
		
		<script type="text/javascript">
		
			
			hit = 0;
			enemiesRemaining=0;
			worldEnded=false;
			var thisPos = new Array();
			var curPos = new Array();
			topScore = false;
			
			
			window.onload = function(){
				checkVars();
				var kin = new Kinetic_2d("theCanvas");
				var context = kin.getContext();
				var message = "";
				var worldX = document.getElementById("theCanvas");
				var worldXContext = worldX.getContext("2d");
				var img = new Image();
				intervalId1 =0;
				intervalId2 =0;
				img.src = "earth.jpg";
				worldXContext.drawImage(img,0,0);
						kin.getCanvas().mouseup = function(){
							kin.drawStage();
						};
				 
						kin.setDrawStage(function(){
							var mousePos = kin.getMousePos();
					
							if (mousePos !== null) {
								curPos[0] = mousePos.x;
								curPos[1] = mousePos.y;
							}
							else {
								curPos[0] = 0;
								curPos[1] = 0;
							}
							


						});
				};
				
				
			function checkVars(){
			
				if(sessionStorage.hit==0||sessionStorage.hit==undefined){
					sessionStorage.hit=0;
				}
				
				hit = sessionStorage.hit;
				document.getElementById("hit").innerHTML = hit;
				
				if(localStorage.tophit>=sessionStorage.hit&&localStorage.tophit!=0){
					document.getElementById("tophit").innerHTML = localStorage.tophit;
				}
				
				else if(localStorage.tophit==undefined||localStorage.tophit==0){
					localStorage.tophit=0;
					document.getElementById("tophit").innerHTML = 0;
				}

				if(sessionStorage.enemies==undefined||sessionStorage.enemies==0){
					sessionStorage.enemies = 5;
				}
				
				enemiesRemaining=sessionStorage.enemies;
				document.getElementById("enemiesRemaining").innerHTML = enemiesRemaining;
				
			}

			function startFalling(){

				intervalId1= setInterval(function(){
				
					var asteroidx = new Asteroid();
					
					do{
						intervalId2 = setInterval(function(){
						asteroidx.fallDown();
				}
				,20)}while(this.alive==true);
				
				}
				,500);
				
				btnStarter = document.getElementById("btx");
				btnStarter.setAttribute("value","RESTART");
				btnStarter.setAttribute("onclick","restart()");
			
			}


			function restart(){
				sessionStorage.hit = 0;
				sessionStorage.enemies = 0;
				location.reload(true);
			}

			//OBJECT IMPLEMENTATION

			function Asteroid(){
			
				this.world = document.getElementById("theCanvas");
				this.worldContext = this.world.getContext("2d");
				this.worldContext.strokeStyle = "#FF0000";
				this.x = Math.floor(Math.random()*999);
				this.y = 0;
				this.alive = true;
				this.update = false;
				this.id = intervalId2;
				
				if(this.x>500){
					this.direction = "right";
				}
				else{
					this.direction = "left";
				}
				
			}

			Asteroid.prototype.trajectory = function(){
			
			if(this.x>998){
				this.direction ="right";
			}
			else if(this.x<2){
				this.direction = "left";
			}

			if(this.direction=="right"){
				this.y++;
				this.x--;
			}
			else{
				this.y++;
				this.x++;
			}
			
			}


			Asteroid.prototype.fallDown = function(){

			if(worldEnded==false){
				if(this.alive==true){
					this.worldContext.beginPath();
					
					if(((thisPos[0]-this.x)<10&&(thisPos[0]-this.x)>-10&&(thisPos[1]-this.y)<10&&(thisPos[1]-this.y)>-10)&&thisPos[0]!=0&&thisPos[1]!=0)
					{
						this.alive = false;
						this.worldContext.strokeStyle = "#FFFF00";
						this.worldContext.arc(this.x,this.y,10,0,Math.PI*2,true);
						this.worldContext.stroke();
						this.worldContext.strokeStyle = "#FF0000";
						statUp ="</br> Asteroid #"+intervalId2+ " has been succesfully destroyed!";
						setStatusUpdate(statUp);
						//this.y = y;
						//this.x = x;
						hit++;
						enemiesRemaining--;
						document.getElementById("hit").innerHTML = hit;
						document.getElementById("enemiesRemaining").innerHTML = enemiesRemaining;
						checkForTopScore();
					}
					
					else
					{
						this.worldContext.moveTo(this.x,this.y);
						this.trajectory();
						this.worldContext.lineTo(this.x,this.y);
						this.worldContext.stroke();
						if(this.y>250){
							if(this.update==false){

							statUp ="</br> <i>Asteroid #"+intervalId2+ "</i> has entered the atmosphere!";
							setStatusUpdate(statUp);
							this.update=true;
							}
						}
						
						if(this.y>500){
						this.worldContext.fillStyle="#FF0000";
						this.worldContext.arc(this.x,this.y,100,0,Math.PI*2,true);
						this.worldContext.stroke();
						this.worldContext.fill();
						this.intervalId = intervalId2;
						this.alive = false;
						worldEnded = true;
						}
					}
					this.worldContext.closePath();
				}
			}
			
			else if(worldEnded==true){
			
				var worldX = document.getElementById("theCanvas");
				var worldXContext = worldX.getContext("2d");
				var img = new Image();
				img.src = "nuke.jpg";
				worldXContext.drawImage(img,-300,-300);
				
				if(topScore==true){
					alert("NOOOOOOOOOOOOOOOOO!\nOh yeah, congrats you got the top score. NOOOOOOOOOOOOOOOOOOOOO!");
					topScore =false;
				}
				
				window.clearInterval(this.intervalId);
				window.clearInterval(intervalId1);
				statUp ="</br> THE WORLD HAS BEEN DESTROYED!";
				setStatusUpdate(statUp);
				}
			}
			

			function checkForTopScore(){
			if(localStorage.tophit<=hit){
				localStorage.tophit = hit;
				document.getElementById("tophit").innerHTML = hit;
				topScore=true;
			}
			if(enemiesRemaining==0){
				sessionStorage.enemies = sessionStorage.enemies  * 2;
				sessionStorage.hit = hit;
				alert("GOOD JOB! NEXT WAVE:"+ sessionStorage.enemies);
				location.reload(true);
			}
			}
				
			function hitIt(){
				thisPos[0] = curPos[0];
				thisPos[1] = curPos[1];
				setTimeout("emptySights()",500);
			}

			function emptySights(){
				thisPos[0] = 0;
				thisPos[1] = 0;
			}
				
			function setStatusUpdate(msg){
				document.getElementById("statusUpdates").innerHTML = msg;
				z=0;
				setInterval(function(){
				z++;
				if((z%2)==0){
					sU = document.getElementById("statusUpdates");
					sU.setAttribute("style","color:black;");
				}
				else{
					sU = document.getElementById("statusUpdates");sU.setAttribute("style","color:white;");
				}
				},100);
			}
				
			function resetAll(){
				sessionStorage.hit = 0;
				sessionStorage.enemies = 0;
				localStorage.tophit = 0;
				location.reload(true);
			}

		</script>
	</head>





4.0 Important Notes,Links, and Thank You Message

A few important notes:

Known issues:
- Sometimes, it takes a few refreshes or restart for the earth to show. I don't know why it does this, since the nuke image shows up perfectly when we want it. To refresh, click CTRL+F5 repeatedly or click START FALLING then RESTART until the images show. You can try the MASTER RESET though it will erase the top score.
- All resources used(fonts,images,Kinetic.js) are owned by their respective owners and should not be used to sell.
- Include all resources in a single folder.

Links:

Kinetic.js = http://www.kineticjs.com/
Tutorial for mouse coordinates using Kinetic.js = http://www.html5canv...se-coordinates/
fonts = www.dafont.com
Google Images = where I got the images
W3Schools = where I got most of the knowledge of what's used in this thing

Comments, suggestions, and violent reactions all accepted. I attached the file below of the working thing.

Attached File  Asteroid Blaster.zip (781.13K)
Number of downloads: 860

That's it! Whew. If you've read through the whole thing( I bet many would be "tl;dr" with this one), I thank you with all my heart.


Thanks, and have a nice day! ^^


:scooter:

Is This A Good Question/Topic? 4
  • +

Replies To: Asteroid Blaster Tutorial Using HTML5,CSS3 and Javascript

#2 JacksonD  Icon User is offline

  • D.I.C Head

Reputation: 9
  • View blog
  • Posts: 215
  • Joined: 18-October 11

Posted 21 October 2011 - 07:14 PM

big post, great effort.

I learnt something off this. Thanks.
Was This Post Helpful? 0
  • +
  • -

#3 fromTheSprawl  Icon User is offline

  • Monomania
  • member icon

Reputation: 513
  • View blog
  • Posts: 2,063
  • Joined: 28-December 10

Posted 24 October 2011 - 01:36 AM

Thanks dude! I'm really glad you liked it. ^^
Was This Post Helpful? 0
  • +
  • -

#4 alexr1090  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 44
  • View blog
  • Posts: 125
  • Joined: 08-May 11

Posted 09 April 2012 - 02:51 PM

Thanks for the tutorial and spending your time. Unfortunately I can't get it to work. I'm using Firefox and the latest Ubuntu. What could be the reason for this?
Was This Post Helpful? 0
  • +
  • -

#5 fromTheSprawl  Icon User is offline

  • Monomania
  • member icon

Reputation: 513
  • View blog
  • Posts: 2,063
  • Joined: 28-December 10

Posted 18 April 2012 - 07:17 PM

I honestly don't have an idea. Try doing it on Chrome, I think I've specified somewhere that I've made it to run on Google Chrome. If it still doesn't work, try using a machine with a Windows OS. Not really sure if that would do the trick, but do let us know if it does. Thanks for the appreciation. :)
Was This Post Helpful? 0
  • +
  • -

#6 cartman182  Icon User is offline

  • New D.I.C Head

Reputation: -2
  • View blog
  • Posts: 22
  • Joined: 19-May 12

Posted 06 August 2012 - 01:37 PM

View PostfromTheSprawl, on 18 April 2012 - 07:17 PM, said:

I honestly don't have an idea. Try doing it on Chrome, I think I've specified somewhere that I've made it to run on Google Chrome. If it still doesn't work, try using a machine with a Windows OS. Not really sure if that would do the trick, but do let us know if it does. Thanks for the appreciation. :)



Hey!
Thanks allot for the Tutorial.
So without the Kinetic.js import there is no way of getting the X and Y Co-Ordinates of the mouse on a Canvas?
Would you also not be able to see the X and Y of the mouse pointer without the canvas?

Thanks
Was This Post Helpful? 0
  • +
  • -

#7 fromTheSprawl  Icon User is offline

  • Monomania
  • member icon

Reputation: 513
  • View blog
  • Posts: 2,063
  • Joined: 28-December 10

Posted 07 August 2012 - 05:56 PM

Uh, yeah, I forgot how I came to using Kinetic.js but I guess it was because I found the non-library way of looking for them quite a bit of work. So, there is a way. I just used this library to make things simpler. :)
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1