HTML5 Game Development – Lesson 4
Today we continue a series of articles on game development in HTML5 using canvas. Today we going to learn next elements: animation with sprites and basic work with sound. In our demonstration you will see a flying dragon. We will hear the sounds of wings all time (we will loop this sound), and another sound – dragon’s roar (on mouseup event). And finally we will teach our dragon be closer to the mouse cursor (when we hold down the mouse).
Our previous article you can read here: Developing Your First HTML5 Game – Lesson 3. Our new script is new enhanced version of previous one.
Here are our demo and downloadable package:
Live Demo
download in package
Ok, download the example files and lets start coding !
Step 1. HTML
Here are all html of my demo. Then again, if you are still used to the simple html you can check out
some basic information on html5 here
index.html
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="utf-8" />
<title>HTML5 Game Development - Lesson 4 | Script Tutorials</title>
<link href="css/main.css" rel="stylesheet" type="text/css" />
<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript" src="js/script.js"></script>
</head>
<body>
<div class="container">
<canvas id="scene" width="1000" height="600"></canvas>
</div>
<footer>
<h2>HTML5 Game Development - Lesson 4</h2>
<a href="http://www.script-tutorials.com/html5-game-development-lesson-4/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a>
</footer>
</body>
</html>
Step 2. CSS
Here are used CSS styles.
css/main.css
I will not publish styles today – this is just page layout styles, nothing special. Available in package.
Step 3. JS
js/script.js
// inner variables
var canvas, ctx;
var backgroundImage;
var iBgShiftX = 100;
var dragon;
var dragonW = 75; // dragon width
var dragonH = 70; // dragon height
var iSprPos = 0; // initial sprite frame
var iSprDir = 4; // initial dragon direction
var dragonSound; // dragon sound
var wingsSound; // wings sound
var bMouseDown = false; // mouse down state
var iLastMouseX = 0;
var iLastMouseY = 0;
// -------------------------------------------------------------
// objects :
function Dragon(x, y, w, h, image) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.image = image;
this.bDrag = false;
}
// -------------------------------------------------------------
// draw functions :
function clear() { // clear canvas function
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
}
function drawScene() { // main drawScene function
clear(); // clear canvas
// draw background
iBgShiftX -= 4;
if (iBgShiftX <= 0) {
iBgShiftX = 1045;
}
ctx.drawImage(backgroundImage, 0 + iBgShiftX, 0, 1000, 940, 0, 0, 1000, 600);
// update sprite positions
iSprPos++;
if (iSprPos >= 9) {
iSprPos = 0;
}
// in case of mouse down - move dragon more close to our mouse
if (bMouseDown) {
if (iLastMouseX > dragon.x) {
dragon.x += 5;
}
if (iLastMouseY > dragon.y) {
dragon.y += 5;
}
if (iLastMouseX < dragon.x) {
dragon.x -= 5;
}
if (iLastMouseY < dragon.y) {
dragon.y -= 5;
}
}
// draw dragon
ctx.drawImage(dragon.image, iSprPos*dragon.w, iSprDir*dragon.h, dragon.w, dragon.h, dragon.x - dragon.w/2, dragon.y - dragon.h/2, dragon.w, dragon.h);
}
// -------------------------------------------------------------
// initialization
$(function(){
canvas = document.getElementById('scene');
ctx = canvas.getContext('2d');
var width = canvas.width;
var height = canvas.height;
// load background image
backgroundImage = new Image();
backgroundImage.src = 'images/hell.jpg';
backgroundImage.onload = function() {
}
backgroundImage.onerror = function() {
console.log('Error loading the background image.');
}
// 'Dragon' music init
dragonSound = new Audio('media/dragon.wav');
dragonSound.volume = 0.9;
// 'Wings' music init
wingsSound = new Audio('media/wings.wav');
wingsSound.volume = 0.9;
wingsSound.addEventListener('ended', function() { // looping wings sound
this.currentTime = 0;
this.play();
}, false);
wingsSound.play();
// initialization of dragon
var oDragonImage = new Image();
oDragonImage.src = 'images/dragon.gif';
oDragonImage.onload = function() {
}
dragon = new Dragon(400, 300, dragonW, dragonH, oDragonImage);
$('#scene').mousedown(function(e) { // binding mousedown event (for dragging)
var mouseX = e.layerX || 0;
var mouseY = e.layerY || 0;
if(e.originalEvent.layerX) { // changes for jquery 1.7
mouseX = e.originalEvent.layerX;
mouseY = e.originalEvent.layerY;
}
bMouseDown = true;
if (mouseX > dragon.x- dragon.w/2 && mouseX < dragon.x- dragon.w/2 +dragon.w &&
mouseY > dragon.y- dragon.h/2 && mouseY < dragon.y-dragon.h/2 +dragon.h) {
dragon.bDrag = true;
dragon.x = mouseX;
dragon.y = mouseY;
}
});
$('#scene').mousemove(function(e) { // binding mousemove event
var mouseX = e.layerX || 0;
var mouseY = e.layerY || 0;
if(e.originalEvent.layerX) { // changes for jquery 1.7
mouseX = e.originalEvent.layerX;
mouseY = e.originalEvent.layerY;
}
// saving last coordinates
iLastMouseX = mouseX;
iLastMouseY = mouseY;
// perform dragon dragging
if (dragon.bDrag) {
dragon.x = mouseX;
dragon.y = mouseY;
}
// change direction of dragon (depends on mouse position)
if (mouseX > dragon.x && Math.abs(mouseY-dragon.y) < dragon.w/2) {
iSprDir = 0;
} else if (mouseX < dragon.x && Math.abs(mouseY-dragon.y) < dragon.w/2) {
iSprDir = 4;
} else if (mouseY > dragon.y && Math.abs(mouseX-dragon.x) < dragon.h/2) {
iSprDir = 2;
} else if (mouseY < dragon.y && Math.abs(mouseX-dragon.x) < dragon.h/2) {
iSprDir = 6;
} else if (mouseY < dragon.y && mouseX < dragon.x) {
iSprDir = 5;
} else if (mouseY < dragon.y && mouseX > dragon.x) {
iSprDir = 7;
} else if (mouseY > dragon.y && mouseX < dragon.x) {
iSprDir = 3;
} else if (mouseY > dragon.y && mouseX > dragon.x) {
iSprDir = 1;
}
});
$('#scene').mouseup(function(e) { // binding mouseup event
dragon.bDrag = false;
bMouseDown = false;
// play dragon sound
dragonSound.currentTime = 0;
dragonSound.play();
});
setInterval(drawScene, 30); // loop drawScene
});
How it work (shortly): Firstly we define canvas, context, then we load background image, two sounds, then we initialize our dragon and binding different mouse events. In our main loop draw function I am shifting background image (loop), then update sprite positions, and finally – draw our dragon. In our code you can find several new interesting methods:
1. Loop background sound
// 'Wings' music init
wingsSound = new Audio('media/wings.wav');
wingsSound.volume = 0.9;
wingsSound.addEventListener('ended', function() { // looping wings sound
this.currentTime = 0;
this.play();
}, false);
wingsSound.play();
2. Draw sprites
var oDragonImage = new Image();
oDragonImage.src = 'images/dragon.gif';
oDragonImage.onload = function() {
}
....
// update sprite positions
iSprPos++;
if (iSprPos >= 9) {
iSprPos = 0;
}
// draw dragon
ctx.drawImage(dragon.image, iSprPos*dragon.w, iSprDir*dragon.h, dragon.w, dragon.h, dragon.x - dragon.w/2, dragon.y - dragon.h/2, dragon.w, dragon.h);
So, we loading initial image (with set of all sub-images), then – draw part of that image, then shifting its positions, and draw again (loop).
Step 4. Custom files
images/dragon.gif, images/hell.jpg, media/dragon.wav and media/wings.wav
All these files available in our package
Live Demo
download in package
Conclusion
Are you like our new handy dragon?
I will be glad to see your thanks and comments. Good luck!
| I am web developer with huge experience (in web languages and even in system languages). Also I am the founder of current website (and several another). I like to write blogs about web development/design. Feel free to Follow us on Twitter: tweetmeme_screen_name='AramisGC'; | If you Enjoyed our article don't forget to Share the love with your friends. |

http://www.script-tutorials.com/tag/game/
You forgot to add the ‘game’ tag.
Sorry for the rude request, but I think that you should write an new post to list the series of tutorial entry link, that would be good for promoting or bookmarking.
Thanks for your nice work!
Hello WM,
Do you mean – create list of all previous game-related tutorials in bottom of each game lesson?
Sorry for my poor English, I’m Taiwanese.
I mean like that: http://net.tutsplus.com/sessions/python-from-scratch/
So, do you like to see all related articles (of same session / series) in one place like here?
Yes, sharing one link is much easier than multiple links, isn’t it?
I’ve seen some journal sites do this way, they posted an introductory index post , and then posted the first article of the series, when proceeding articles was posted, they updated the index post to add links.
There is another way, posting the index post with conclusion after the series ends, but I think the former is better, for that it could make the index post to be spread early.
Outstanding! But when coming from another site, your #3 tutorial did not have the right link.
http://www.script-tutorials.com/html5-game-development-navigating-your-spaceship-lesson-3/
It would make it Ez-ier for people if you had a link at the bottom of each of your tutorial pages to your next tutorial.
In fact I had to go to Lesson 4 to get the link for Lesson 3.
Because you start out with this URL for Lesson 1
http://www.script-tutorials.com/html5-game-development-lesson-1/
http://www.script-tutorials.com/html5-game-development-lesson-2/
Different for Lesson 3 (see above)
And then Lesson 4 is:
http://www.script-tutorials.com/html5-game-development-lesson-4/
Hello Judith,
Thanks for your remarks, I am going to think about it. Generally I want to create extra alternative navigation for more comfort access to our articles (maybe put it into dropdown menu, with sorting by categories)
Thanks for your idea, right now I’m thinking about adding alternative navigation menu to website (dropdown) where will be listed all articles by categories.