HTML5 Game Development – Lesson 7

HTML5 Game Development – Lesson 7

13 51035
HTML5 Game Development - Lesson 7

HTML5 Game Development – Lesson 7

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

<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="utf-8" />
<title>HTML5 Game Development - Lesson 7 | Script Tutorials</title>
<link href="css/main.css" rel="stylesheet" type="text/css" />
<script src="js/jquery-1.5.2.min.js"></script>
<script src="js/script.js"></script>
</head>
<body>
<header>
<h2>HTML5 Game Development - Lesson 7</h2>
<a href="https://www.script-tutorials.com/html5-game-development-lesson-7/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a>
</header>
<div class="container">
<canvas id="scene" width="800" height="600"></canvas>
</div>
</body>
</html>

Step 2. CSS

Here are used CSS styles.

css/main.css

/* page layout styles */
*{
margin:0;
padding:0;
}
body {
background-color:#eee;
color:#fff;
font:14px/1.3 Arial,sans-serif;
}
header {
background-color:#212121;
box-shadow: 0 -1px 2px #111111;
display:block;
height:70px;
position:relative;
width:100%;
z-index:100;
}
header h2{
font-size:22px;
font-weight:normal;
left:50%;
margin-left:-400px;
padding:22px 0;
position:absolute;
width:540px;
}
header a.stuts,a.stuts:visited{
border:none;
text-decoration:none;
color:#fcfcfc;
font-size:14px;
left:50%;
line-height:31px;
margin:23px 0 0 110px;
position:absolute;
top:0;
}
header .stuts span {
font-size:22px;
font-weight:bold;
margin-left:5px;
}
.container {
margin: 20px auto;
overflow: hidden;
position: relative;
width: 800px;
}

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

// inner variables
var canvas, ctx;
var iStart = 0;
var bRightBut = false;
var bLeftBut = false;
var oBall, oPadd, oBricks;
var aSounds = [];
var iPoints = 0;
var iGameTimer;
var iElapsed = iMin = iSec = 0;
var sLastTime, sLastPoints;
// objects :
function Ball(x, y, dx, dy, r) {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.r = r;
}
function Padd(x, w, h, img) {
this.x = x;
this.w = w;
this.h = h;
this.img = img;
}
function Bricks(w, h, r, c, p) {
this.w = w;
this.h = h;
this.r = r; // rows
this.c = c; // cols
this.p = p; // padd
this.objs;
this.colors = ['#9d9d9d', '#f80207', '#feff01', '#0072ff', '#fc01fc', '#03fe03']; // colors for rows
}
// -------------------------------------------------------------
// draw functions :
function clear() { // clear canvas function
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
// fill background
ctx.fillStyle = '#111';
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
}
function drawScene() { // main drawScene function
clear(); // clear canvas
// draw Ball (circle)
ctx.fillStyle = '#f66';
ctx.beginPath();
ctx.arc(oBall.x, oBall.y, oBall.r, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
if (bRightBut)
oPadd.x += 5;
else if (bLeftBut)
oPadd.x -= 5;
// draw Padd (rectangle)
ctx.drawImage(oPadd.img, oPadd.x, ctx.canvas.height - oPadd.h);
// draw bricks (from array of its objects)
for (i=0; i < oBricks.r; i++) {
ctx.fillStyle = oBricks.colors[i];
for (j=0; j < oBricks.c; j++) {
if (oBricks.objs[i][j] == 1) {
ctx.beginPath();
ctx.rect((j * (oBricks.w + oBricks.p)) + oBricks.p, (i * (oBricks.h + oBricks.p)) + oBricks.p, oBricks.w, oBricks.h);
ctx.closePath();
ctx.fill();
}
}
}
// collision detection
iRowH = oBricks.h + oBricks.p;
iRow = Math.floor(oBall.y / iRowH);
iCol = Math.floor(oBall.x / (oBricks.w + oBricks.p));
// mark brick as broken (empty) and reverse brick
if (oBall.y < oBricks.r * iRowH && iRow >= 0 && iCol >= 0 && oBricks.objs[iRow][iCol] == 1) {
oBricks.objs[iRow][iCol] = 0;
oBall.dy = -oBall.dy;
iPoints++;
aSounds[0].play(); // play sound
}
// reverse X position of ball
if (oBall.x + oBall.dx + oBall.r > ctx.canvas.width || oBall.x + oBall.dx - oBall.r < 0) {
oBall.dx = -oBall.dx;
}
if (oBall.y + oBall.dy - oBall.r < 0) {
oBall.dy = -oBall.dy;
} else if (oBall.y + oBall.dy + oBall.r > ctx.canvas.height - oPadd.h) {
if (oBall.x > oPadd.x && oBall.x < oPadd.x + oPadd.w) {
oBall.dx = 10 * ((oBall.x-(oPadd.x+oPadd.w/2))/oPadd.w);
oBall.dy = -oBall.dy;
aSounds[2].play(); // play sound
}
else if (oBall.y + oBall.dy + oBall.r > ctx.canvas.height) {
clearInterval(iStart);
clearInterval(iGameTimer);
// HTML5 Local storage - save values
localStorage.setItem('last-time', iMin + ':' + iSec);
localStorage.setItem('last-points', iPoints);
aSounds[1].play(); // play sound
}
}
oBall.x += oBall.dx;
oBall.y += oBall.dy;
ctx.font = '16px Verdana';
ctx.fillStyle = '#fff';
iMin = Math.floor(iElapsed / 60);
iSec = iElapsed % 60;
if (iMin < 10) iMin = "0" + iMin;
if (iSec < 10) iSec = "0" + iSec;
ctx.fillText('Time: ' + iMin + ':' + iSec, 600, 520);
ctx.fillText('Points: ' + iPoints, 600, 550);
if (sLastTime != null && sLastPoints != null) {
ctx.fillText('Last Time: ' + sLastTime, 600, 460);
ctx.fillText('Last Points: ' + sLastPoints, 600, 490);
}
}
// initialization
$(function(){
canvas = document.getElementById('scene');
ctx = canvas.getContext('2d');
var width = canvas.width;
var height = canvas.height;
var padImg = new Image();
padImg.src = 'images/padd.png';
padImg.onload = function() {};
oBall = new Ball(width / 2, 550, 0.5, -5, 10); // new ball object
oPadd = new Padd(width / 2, 120, 20, padImg); // new padd object
oBricks = new Bricks((width / 8) - 1, 20, 6, 8, 2); // new bricks object
oBricks.objs = new Array(oBricks.r); // fill-in bricks
for (i=0; i < oBricks.r; i++) {
oBricks.objs[i] = new Array(oBricks.c);
for (j=0; j < oBricks.c; j++) {
oBricks.objs[i][j] = 1;
}
}
aSounds[0] = new Audio('media/snd1.wav');
aSounds[0].volume = 0.9;
aSounds[1] = new Audio('media/snd2.wav');
aSounds[1].volume = 0.9;
aSounds[2] = new Audio('media/snd3.wav');
aSounds[2].volume = 0.9;
iStart = setInterval(drawScene, 10); // loop drawScene
iGameTimer = setInterval(countTimer, 1000); // inner game timer
// HTML5 Local storage - get values
sLastTime = localStorage.getItem('last-time');
sLastPoints = localStorage.getItem('last-points');
$(window).keydown(function(event){ // keyboard-down alerts
switch (event.keyCode) {
case 37: // 'Left' key
bLeftBut = true;
break;
case 39: // 'Right' key
bRightBut = true;
break;
}
});
$(window).keyup(function(event){ // keyboard-up alerts
switch (event.keyCode) {
case 37: // 'Left' key
bLeftBut = false;
break;
case 39: // 'Right' key
bRightBut = false;
break;
}
});
var iCanvX1 = $(canvas).offset().left;
var iCanvX2 = iCanvX1 + width;
$('#scene').mousemove(function(e) { // binding mousemove event
if (e.pageX > iCanvX1 && e.pageX < iCanvX2) {
oPadd.x = Math.max(e.pageX - iCanvX1 - (oPadd.w/2), 0);
oPadd.x = Math.min(ctx.canvas.width - oPadd.w, oPadd.x);
}
});
});
function countTimer() {
iElapsed++;
}

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!

SIMILAR ARTICLES

jQuery Mobile Lesson 6

0 60
jQuery Mobile Lesson 5

0 75

13 COMMENTS

  1. on my foirfex 6.0.1 it works fine! :-DI wanted to make an animated background for my blog, but maybe it’s too early. :-D

  2. Its a great tutorial. But i think you have missed out a major part of the game… Why isn’t there a Game over message popping up when the game is over ?

  3. great tutorial! how could I add the messages? for example: when the ball hits a ground?

    many thanx and all the best for new year!

Leave a Reply