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
[sociallocker]
download in package
[/sociallocker]
Ok, download the example files and lets start coding !
Step 1. HTML
Here is html markup of our demo.
index.html
01 | <!DOCTYPE html> |
02 | <html lang="en" > |
03 | <head> |
04 | <meta charset="utf-8" /> |
05 | <title>HTML5 Game Development - Lesson 4 | Script Tutorials</title> |
06 | <link href="css/main.css" rel="stylesheet" type="text/css" /> |
07 | <!--[if lt IE 9]> |
08 | <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> |
09 | <![endif]--> |
10 | <script src="http://code.jquery.com/jquery-latest.min.js"></script> |
11 | <script type="text/javascript" src="js/script.js"></script> |
12 | </head> |
13 | <body> |
14 | <div class="container"> |
15 | <canvas id="scene" width="1000" height="600"></canvas> |
16 | </div> |
17 | <footer> |
18 | <h2>HTML5 Game Development - Lesson 4</h2> |
19 | <a href="https://www.script-tutorials.com/html5-game-development-lesson-4/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a> |
20 | </footer> |
21 | </body> |
22 | </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
001 | // inner variables |
002 | var canvas, ctx; |
003 | var backgroundImage; |
004 | var iBgShiftX = 100; |
005 | var dragon; |
006 | var dragonW = 75; // dragon width |
007 | var dragonH = 70; // dragon height |
008 | var iSprPos = 0; // initial sprite frame |
009 | var iSprDir = 4; // initial dragon direction |
010 | var dragonSound; // dragon sound |
011 | var wingsSound; // wings sound |
012 | var bMouseDown = false; // mouse down state |
013 | var iLastMouseX = 0; |
014 | var iLastMouseY = 0; |
015 | // ------------------------------------------------------------- |
016 | // objects : |
017 | function Dragon(x, y, w, h, image) { |
018 | this.x = x; |
019 | this.y = y; |
020 | this.w = w; |
021 | this.h = h; |
022 | this.image = image; |
023 | this.bDrag = false; |
024 | } |
025 | // ------------------------------------------------------------- |
026 | // draw functions : |
027 | function clear() { // clear canvas function |
028 | ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); |
029 | } |
030 | function drawScene() { // main drawScene function |
031 | clear(); // clear canvas |
032 | // draw background |
033 | iBgShiftX -= 4; |
034 | if (iBgShiftX <= 0) { |
035 | iBgShiftX = 1045; |
036 | } |
037 | ctx.drawImage(backgroundImage, 0 + iBgShiftX, 0, 1000, 940, 0, 0, 1000, 600); |
038 | // update sprite positions |
039 | iSprPos++; |
040 | if (iSprPos >= 9) { |
041 | iSprPos = 0; |
042 | } |
043 | // in case of mouse down - move dragon more close to our mouse |
044 | if (bMouseDown) { |
045 | if (iLastMouseX > dragon.x) { |
046 | dragon.x += 5; |
047 | } |
048 | if (iLastMouseY > dragon.y) { |
049 | dragon.y += 5; |
050 | } |
051 | if (iLastMouseX < dragon.x) { |
052 | dragon.x -= 5; |
053 | } |
054 | if (iLastMouseY < dragon.y) { |
055 | dragon.y -= 5; |
056 | } |
057 | } |
058 | // draw dragon |
059 | 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); |
060 | } |
061 | // ------------------------------------------------------------- |
062 | // initialization |
063 | $(function(){ |
064 | canvas = document.getElementById('scene'); |
065 | ctx = canvas.getContext('2d'); |
066 | var width = canvas.width; |
067 | var height = canvas.height; |
068 | // load background image |
069 | backgroundImage = new Image(); |
070 | backgroundImage.src = 'images/hell.jpg'; |
071 | backgroundImage.onload = function() { |
072 | } |
073 | backgroundImage.onerror = function() { |
074 | console.log('Error loading the background image.'); |
075 | } |
076 | // 'Dragon' music init |
077 | dragonSound = new Audio('media/dragon.wav'); |
078 | dragonSound.volume = 0.9; |
079 | // 'Wings' music init |
080 | wingsSound = new Audio('media/wings.wav'); |
081 | wingsSound.volume = 0.9; |
082 | wingsSound.addEventListener('ended', function() { // looping wings sound |
083 | this.currentTime = 0; |
084 | this.play(); |
085 | }, false); |
086 | wingsSound.play(); |
087 | // initialization of dragon |
088 | var oDragonImage = new Image(); |
089 | oDragonImage.src = 'images/dragon.gif'; |
090 | oDragonImage.onload = function() { |
091 | } |
092 | dragon = new Dragon(400, 300, dragonW, dragonH, oDragonImage); |
093 | $('#scene').mousedown(function(e) { // binding mousedown event (for dragging) |
094 | var mouseX = e.layerX || 0; |
095 | var mouseY = e.layerY || 0; |
096 | if(e.originalEvent.layerX) { // changes for jquery 1.7 |
097 | mouseX = e.originalEvent.layerX; |
098 | mouseY = e.originalEvent.layerY; |
099 | } |
100 | bMouseDown = true; |
101 | if (mouseX > dragon.x- dragon.w/2 && mouseX < dragon.x- dragon.w/2 +dragon.w && |
102 | mouseY > dragon.y- dragon.h/2 && mouseY < dragon.y-dragon.h/2 +dragon.h) { |
103 | dragon.bDrag = true; |
104 | dragon.x = mouseX; |
105 | dragon.y = mouseY; |
106 | } |
107 | }); |
108 | $('#scene').mousemove(function(e) { // binding mousemove event |
109 | var mouseX = e.layerX || 0; |
110 | var mouseY = e.layerY || 0; |
111 | if(e.originalEvent.layerX) { // changes for jquery 1.7 |
112 | mouseX = e.originalEvent.layerX; |
113 | mouseY = e.originalEvent.layerY; |
114 | } |
115 | // saving last coordinates |
116 | iLastMouseX = mouseX; |
117 | iLastMouseY = mouseY; |
118 | // perform dragon dragging |
119 | if (dragon.bDrag) { |
120 | dragon.x = mouseX; |
121 | dragon.y = mouseY; |
122 | } |
123 | // change direction of dragon (depends on mouse position) |
124 | if (mouseX > dragon.x && Math.abs(mouseY-dragon.y) < dragon.w/2) { |
125 | iSprDir = 0; |
126 | } else if (mouseX < dragon.x && Math.abs(mouseY-dragon.y) < dragon.w/2) { |
127 | iSprDir = 4; |
128 | } else if (mouseY > dragon.y && Math.abs(mouseX-dragon.x) < dragon.h/2) { |
129 | iSprDir = 2; |
130 | } else if (mouseY < dragon.y && Math.abs(mouseX-dragon.x) < dragon.h/2) { |
131 | iSprDir = 6; |
132 | } else if (mouseY < dragon.y && mouseX < dragon.x) { |
133 | iSprDir = 5; |
134 | } else if (mouseY < dragon.y && mouseX > dragon.x) { |
135 | iSprDir = 7; |
136 | } else if (mouseY > dragon.y && mouseX < dragon.x) { |
137 | iSprDir = 3; |
138 | } else if (mouseY > dragon.y && mouseX > dragon.x) { |
139 | iSprDir = 1; |
140 | } |
141 | }); |
142 | $('#scene').mouseup(function(e) { // binding mouseup event |
143 | dragon.bDrag = false; |
144 | bMouseDown = false; |
145 | // play dragon sound |
146 | dragonSound.currentTime = 0; |
147 | dragonSound.play(); |
148 | }); |
149 | setInterval(drawScene, 30); // loop drawScene |
150 | }); |
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
1 | // 'Wings' music init |
2 | wingsSound = new Audio('media/wings.wav'); |
3 | wingsSound.volume = 0.9; |
4 | wingsSound.addEventListener('ended', function() { // looping wings sound |
5 | this.currentTime = 0; |
6 | this.play(); |
7 | }, false); |
8 | wingsSound.play(); |
2. Draw sprites
01 | var oDragonImage = new Image(); |
02 | oDragonImage.src = 'images/dragon.gif'; |
03 | oDragonImage.onload = function() { |
04 | } |
05 | .... |
06 | // update sprite positions |
07 | iSprPos++; |
08 | if (iSprPos >= 9) { |
09 | iSprPos = 0; |
10 | } |
11 | // draw dragon |
12 | 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
Conclusion
Are you like our new handy dragon? 🙂 I will be glad to see your thanks and comments. Good luck!







