HTML5 Game Development – Lesson 7

Image Tutorials

Today we will create our first complete game – Arkanoid. In this lesson I will show you how to detect basic collisions and work with HTML5 local storage. You can operate with pad using mouse and keyboard (left/right buttons). We will store in local storage elapsed time of previous game and amount of broken bricks (points).

Here you can read our previous lesson: Developing Your First HTML5 Game – Lesson 6.

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 is source code of our seventh lesson

index.html

01 <!DOCTYPE html>
02 <html lang="en" >
03     <head>
04         <meta charset="utf-8" />
05         <title>HTML5 Game Development - Lesson 7 | Script Tutorials</title>
06         <link href="css/main.css" rel="stylesheet" type="text/css" />
07         <script src="js/jquery-1.5.2.min.js"></script>
08         <script src="js/script.js"></script>
09     </head>
10     <body>
11         <header>
12             <h2>HTML5 Game Development - Lesson 7</h2>
13             <a href="https://www.script-tutorials.com/html5-game-development-lesson-7/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a>
14         </header>
15         <div class="container">
16             <canvas id="scene" width="800" height="600"></canvas>
17         </div>
18     </body>
19 </html>

Step 2. CSS

Here are used CSS styles.

css/main.css

01 /* page layout styles */
02 *{
03     margin:0;
04     padding:0;
05 }
06 body {
07     background-color:#eee;
08     color:#fff;
09     font:14px/1.3 Arial,sans-serif;
10 }
11 header {
12     background-color:#212121;
13     box-shadow: 0 -1px 2px #111111;
14     display:block;
15     height:70px;
16     position:relative;
17     width:100%;
18     z-index:100;
19 }
20 header h2{
21     font-size:22px;
22     font-weight:normal;
23     left:50%;
24     margin-left:-400px;
25     padding:22px 0;
26     position:absolute;
27     width:540px;
28 }
29 header a.stuts,a.stuts:visited{
30     border:none;
31     text-decoration:none;
32     color:#fcfcfc;
33     font-size:14px;
34     left:50%;
35     line-height:31px;
36     margin:23px 0 0 110px;
37     position:absolute;
38     top:0;
39 }
40 header .stuts span {
41     font-size:22px;
42     font-weight:bold;
43     margin-left:5px;
44 }
45 .container {
46     margin20px auto;
47     overflowhidden;
48     positionrelative;
49     width800px;
50 }

Step 3. JS

js/jquery-1.5.2.min.js

We use jQuery for our lesson. Available in package. Next file most important (here are all our html5 functional):

js/script.js

001 // inner variables
002 var canvas, ctx;
003 var iStart = 0;
004 var bRightBut = false;
005 var bLeftBut = false;
006 var oBall, oPadd, oBricks;
007 var aSounds = [];
008 var iPoints = 0;
009 var iGameTimer;
010 var iElapsed = iMin = iSec = 0;
011 var sLastTime, sLastPoints;
012 // objects :
013 function Ball(x, y, dx, dy, r) {
014     this.x = x;
015     this.y = y;
016     this.dx = dx;
017     this.dy = dy;
018     this.r = r;
019 }
020 function Padd(x, w, h, img) {
021     this.x = x;
022     this.w = w;
023     this.h = h;
024     this.img = img;
025 }
026 function Bricks(w, h, r, c, p) {
027     this.w = w;
028     this.h = h;
029     this.r = r; // rows
030     this.c = c; // cols
031     this.p = p; // padd
032     this.objs;
033     this.colors = ['#9d9d9d''#f80207''#feff01''#0072ff''#fc01fc''#03fe03']; // colors for rows
034 }
035 // -------------------------------------------------------------
036 // draw functions :
037 function clear() { // clear canvas function
038     ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
039     // fill background
040     ctx.fillStyle = '#111';
041     ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
042 }
043 function drawScene() { // main drawScene function
044     clear(); // clear canvas
045     // draw Ball (circle)
046     ctx.fillStyle = '#f66';
047     ctx.beginPath();
048     ctx.arc(oBall.x, oBall.y, oBall.r, 0, Math.PI * 2, true);
049     ctx.closePath();
050     ctx.fill();
051     if (bRightBut)
052         oPadd.x += 5;
053     else if (bLeftBut)
054         oPadd.x -= 5;
055     // draw Padd (rectangle)
056     ctx.drawImage(oPadd.img, oPadd.x, ctx.canvas.height - oPadd.h);
057     // draw bricks (from array of its objects)
058     for (i=0; i < oBricks.r; i++) {
059         ctx.fillStyle = oBricks.colors[i];
060         for (j=0; j < oBricks.c; j++) {
061             if (oBricks.objs[i][j] == 1) {
062                 ctx.beginPath();
063                 ctx.rect((j * (oBricks.w + oBricks.p)) + oBricks.p, (i * (oBricks.h + oBricks.p)) + oBricks.p, oBricks.w, oBricks.h);
064                 ctx.closePath();
065                 ctx.fill();
066             }
067         }
068     }
069     // collision detection
070     iRowH = oBricks.h + oBricks.p;
071     iRow = Math.floor(oBall.y / iRowH);
072     iCol = Math.floor(oBall.x / (oBricks.w + oBricks.p));
073     // mark brick as broken (empty) and reverse brick
074     if (oBall.y < oBricks.r * iRowH && iRow >= 0 && iCol >= 0 && oBricks.objs[iRow][iCol] == 1) {
075         oBricks.objs[iRow][iCol] = 0;
076         oBall.dy = -oBall.dy;
077         iPoints++;
078         aSounds[0].play(); // play sound
079     }
080     // reverse X position of ball
081     if (oBall.x + oBall.dx + oBall.r > ctx.canvas.width || oBall.x + oBall.dx - oBall.r < 0) {
082         oBall.dx = -oBall.dx;
083     }
084     if (oBall.y + oBall.dy - oBall.r < 0) {
085         oBall.dy = -oBall.dy;
086     else if (oBall.y + oBall.dy + oBall.r > ctx.canvas.height - oPadd.h) {
087         if (oBall.x > oPadd.x && oBall.x < oPadd.x + oPadd.w) {
088             oBall.dx = 10 * ((oBall.x-(oPadd.x+oPadd.w/2))/oPadd.w);
089             oBall.dy = -oBall.dy;
090             aSounds[2].play(); // play sound
091         }
092         else if (oBall.y + oBall.dy + oBall.r > ctx.canvas.height) {
093             clearInterval(iStart);
094             clearInterval(iGameTimer);
095             // HTML5 Local storage - save values
096             localStorage.setItem('last-time', iMin + ':' + iSec);
097             localStorage.setItem('last-points', iPoints);
098             aSounds[1].play(); // play sound
099         }
100     }
101     oBall.x += oBall.dx;
102     oBall.y += oBall.dy;
103     ctx.font = '16px Verdana';
104     ctx.fillStyle = '#fff';
105     iMin = Math.floor(iElapsed / 60);
106     iSec = iElapsed % 60;
107     if (iMin < 10) iMin = "0" + iMin;
108     if (iSec < 10) iSec = "0" + iSec;
109     ctx.fillText('Time: ' + iMin + ':' + iSec, 600, 520);
110     ctx.fillText('Points: ' + iPoints, 600, 550);
111     if (sLastTime != null && sLastPoints != null) {
112         ctx.fillText('Last Time: ' + sLastTime, 600, 460);
113         ctx.fillText('Last Points: ' + sLastPoints, 600, 490);
114     }
115 }
116 // initialization
117 $(function(){
118     canvas = document.getElementById('scene');
119     ctx = canvas.getContext('2d');
120     var width = canvas.width;
121     var height = canvas.height;
122     var padImg = new Image();
123     padImg.src = 'images/padd.png';
124     padImg.onload = function() {};
125     oBall = new Ball(width / 2, 550, 0.5, -5, 10); // new ball object
126     oPadd = new Padd(width / 2, 120, 20, padImg); // new padd object
127     oBricks = new Bricks((width / 8) - 1, 20, 6, 8, 2); // new bricks object
128     oBricks.objs = new Array(oBricks.r); // fill-in bricks
129     for (i=0; i < oBricks.r; i++) {
130         oBricks.objs[i] = new Array(oBricks.c);
131         for (j=0; j < oBricks.c; j++) {
132             oBricks.objs[i][j] = 1;
133         }
134     }
135     aSounds[0] = new Audio('media/snd1.wav');
136     aSounds[0].volume = 0.9;
137     aSounds[1] = new Audio('media/snd2.wav');
138     aSounds[1].volume = 0.9;
139     aSounds[2] = new Audio('media/snd3.wav');
140     aSounds[2].volume = 0.9;
141     iStart = setInterval(drawScene, 10); // loop drawScene
142     iGameTimer = setInterval(countTimer, 1000); // inner game timer
143     // HTML5 Local storage - get values
144     sLastTime = localStorage.getItem('last-time');
145     sLastPoints = localStorage.getItem('last-points');
146     $(window).keydown(function(event){ // keyboard-down alerts
147         switch (event.keyCode) {
148             case 37: // 'Left' key
149                 bLeftBut = true;
150                 break;
151             case 39: // 'Right' key
152                 bRightBut = true;
153                 break;
154         }
155     });
156     $(window).keyup(function(event){ // keyboard-up alerts
157         switch (event.keyCode) {
158             case 37: // 'Left' key
159                 bLeftBut = false;
160                 break;
161             case 39: // 'Right' key
162                 bRightBut = false;
163                 break;
164         }
165     });
166     var iCanvX1 = $(canvas).offset().left;
167     var iCanvX2 = iCanvX1 + width;
168     $('#scene').mousemove(function(e) { // binding mousemove event
169         if (e.pageX > iCanvX1 && e.pageX < iCanvX2) {
170             oPadd.x = Math.max(e.pageX - iCanvX1 - (oPadd.w/2), 0);
171             oPadd.x = Math.min(ctx.canvas.width - oPadd.w, oPadd.x);
172         }
173     });
174 });
175 function countTimer() {
176     iElapsed++;
177 }

I added my comments anywhere, hope that all code is pretty understandable. Please pay attention to ‘localStorage’ object to understand how to work with HTML5 Local storage (I use ‘setItem’ method to store something and ‘getItem’ to read this from local storage). Also, it can be also interesting to understand how to calculate collisions between the ball and bricks.


Live Demo
download in package

Conclusion

Today, we made our first arkanoid game. Most functionality are already here. We have implemented our first knowledge about collisions and HTML5 local storage too. I will be glad to see your thanks and comments. Good luck!

Rate article