How To Design A Mobile Game With Html5, The beauty of these titles is that they work equally properly on each cellular and desktop using identical code. How To Design A Mobile Game With Html5, Could HTML5 finally fulfill the holy grail of “write as soon as, run anywhere”?
Getting Started # How To Design A Mobile Game With Html5
Before you start sketching the next Temple Run or Angry Birds, you ought to be aware of a few things that might dampen your excitement:
- Performance. Mobile browsers are not traditionally recognized for his or her blazing JavaScript engines. With iOS 6 and Chrome beta for Android, although, issues are improving fast.
- Resolution. A veritable cornucopia of Android devices sports a variety of resolutions. Not to mention the increased resolution and pixel density of the iPhone four and iPad 3.
- Audio. Hope you benefit from the sound of silence. Audio assist in cellular browsers is poor, to say the least. Lag is a significant drawback, as is the truth that most devices supply only a single channel. iOS won’t even load a sound until the consumer initiates the motion. My recommendation is to carry tight and await browser distributors to sort this out.
Now, as a Web developer you’re used to coping with the quirks of sure browsers and degrading gracefully, and coping with fragmented platforms. So, a couple of technical challenges won’t put you off, right? What’s extra, all of those efficiency and audio issues are short-term. The cell browser panorama is altering so quickly that these issues will quickly be a distant reminiscence.
In this tutorial, we’ll make a relatively simple sport that takes you thru the basics and steers you away from pitfalls. The end result will seem like this:
It’s a fairly easy recreation, by which the person bursts floating bubbles earlier than they attain the top of the screen. Imaginatively, I’ve titled our little endeavor Pop.
We’ll develop this in a variety of distinct levels:
- Cater to the multitude of viewports and optimize for cell;
- Look briefly at using the canvas API to attract to the display;
- Capture contact events;
- Make a fundamental game loop;
- Introduce sprites, or sport “entities”;
- Add collision detection and a few easy maths to spice issues up;
- Add a bit of polish and some basic particle results.
1. Setting The Stage # How To Design A Mobile Game With Html5
Enough of the background story. Fire up your favorite text editor, pour a strong brew of coffee, and let’s get our palms dirty.
As mentioned, there is a plethora of decision sizes and pixel densities across units. This means we’ll scale our canvas to suit the viewport. This may come at the price of a loss in quality, but one intelligent trick is to make the canvas small after which scale up, which offers an efficiency enhance.
Let’s kick off with a fundamental HTML shim:
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,
user-scalable=no, initial-scale=1, maximum-scale=1, user-scalable=0" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<style type="text/css">
body { margin: 0; padding: 0; background: #000;}
canvas { display: block; margin: 0 auto; background: #fff; }
</style>
</head>
<body>
<canvas> </canvas>
<script>
// all the code goes here
</script>
</body>
</html>
The meta
viewport tag tells cellular browsers to disable consumer scaling and to render at full size quite than shrink the web page down. The subsequent apple-
prefixed meta tags allow the game to be bookmarked. On the iPhone, bookmarked apps don’t show the toolbar at the backside of the page, thus liberating up the priceless real property.
Take a have a look at the next:
// namespace our game
var POP = {
// set up some initial values
WIDTH: 320,
HEIGHT: 480,
// we'll set the rest of these
// in the init function
RATIO: null,
currentWidth: null,
currentHeight: null,
canvas: null,
ctx: null,
init: function() {
// the proportion of width to height
POP.RATIO = POP.WIDTH / POP.HEIGHT;
// these will change when the screen is resized
POP.currentWidth = POP.WIDTH;
POP.currentHeight = POP.HEIGHT;
// this is our canvas element
POP.canvas = document.getElementsByTagName('canvas')[0];
// setting this is important
// otherwise the browser will
// default to 320 x 200
POP.canvas.width = POP.WIDTH;
POP.canvas.height = POP.HEIGHT;
// the canvas context enables us to
// interact with the canvas api
POP.ctx = POP.canvas.getContext('2d');
// we're ready to resize
POP.resize();
},
resize: function() {
POP.currentHeight = window.innerHeight;
// resize the width in proportion
// to the new height
POP.currentWidth = POP.currentHeight * POP.RATIO;
// this will create some extra space on the
// page, allowing us to scroll past
// the address bar, thus hiding it.
if (POP.android || POP.ios) {
document.body.style.height = (window.innerHeight + 50) + 'px';
}
// set the new canvas style width and height
// note: our canvas is still 320 x 480, but
// we're essentially scaling it with CSS
POP.canvas.style.width = POP.currentWidth + 'px';
POP.canvas.style.height = POP.currentHeight + 'px';
// we use a timeout here because some mobile
// browsers don't fire if there is not
// a short delay
window.setTimeout(function() {
window.scrollTo(0,1);
}, 1);
}
};
window.addEventListener('load', POP.init, false);
window.addEventListener('resize', POP.resize, false);
First, we create the POP
namespace for our game. Being good builders, we don’t need to pollute the worldwide namespace. In maintaining a good practice, we are going to declare all variables firstly of this system. Most of them are obvious: canvas
refers to the canvas
factor in the HTML, and ctx
enables us to access it via the JavaScript canvas API.
In POP.init, we seize a reference to our canvas element, get its context and modify the canvas element’s dimensions to 480 × 320. The resize perform, which is fired on resize and cargo occasions, adjusts the canvas’ type attribute for width and height accordingly while maintaining the ratio. Effectively, the canvas is still the same dimensions however has been scaled up using CSS. Try resizing your browser and you’ll see the canvas scale to suit.
If you tried that on your telephone, you’ll discover that the tackle bar continues to be visible. Ugh! We can fix this by including a number of additional pixels to the document after which scrolling down to cover the address bar, like so:
// we need to sniff out Android and iOS
// so that we can hide the address bar in
// our resize function
POP.ua = navigator.userAgent.toLowerCase();
POP.android = POP.ua.indexOf('android') > -1 ? true : false;
POP.ios = ( POP.ua.indexOf('iphone') > -1 || POP.ua.indexOf('ipad') > -1 ) ?
true : false;
The code above sniffs out the consumer agent, flagging for Android and iOS if present. Add it at the finish of POP.init
, earlier than the call to POP.resize()
.
Then, within the resize
perform, if android
or ios
is true
, we add another 50 pixels to the document’s peak — i.e. enough further area to have the power to scroll down past the tackle bar.
// this will create some extra space on the
// page, enabling us to scroll past
// the address bar, thus hiding it.
if (POP.android || POP.ios) {
document.body.style.height = (window.innerHeight + 50) + 'px';
}
Notice that we do that only for Android and iOS units; otherwise, nasty scroll bars will seem. Also, we have to delay the firing of scrollTo
to verify it doesn’t get ignored on cellular Safari.
2. A Blank Canvas # How To Design A Mobile Game With Html5
Now that we’ve scaled our canvas snuggly to the viewport, let’s add the power to attract some shapes.
Note: In this tutorial, we’re going to stay with basic geometric shapes. iOS 5 and Chrome beta for Android can handle a lot of picture sprites at an excessive frame fee. Try that on Android 3.2 or decrease and the body rate will drop exponentially. Luckily, there’s not a lot overhead when drawing circles, so we will have a lot of bubbles in our recreation without hampering performance on older devices.
Below, we’ve added a basic Draw
object that enables us to clear the display screen, draw a rectangle and circle, and add some textual content. Nothing mind-blowing yet. Mozilla Developers Network has excellent assets all the time, replete with examples for drawing to the canvas.
// abstracts various canvas operations into
// standalone functions
POP.Draw = {
clear: function() {
POP.ctx.clearRect(0, 0, POP.WIDTH, POP.HEIGHT);
},
rect: function(x, y, w, h, col) {
POP.ctx.fillStyle = col;
POP.ctx.fillRect(x, y, w, h);
},
circle: function(x, y, r, col) {
POP.ctx.fillStyle = col;
POP.ctx.beginPath();
POP.ctx.arc(x + 5, y + 5, r, 0, Math.PI * 2, true);
POP.ctx.closePath();
POP.ctx.fill();
},
text: function(string, x, y, size, col) {
POP.ctx.font = 'bold '+size+'px Monospace';
POP.ctx.fillStyle = col;
POP.ctx.fillText(string, x, y);
}
};
Our Draw
object has strategies for clearing the display screen and drawing rectangles, circles, and text. The benefit of abstracting these operations is that we don’t have to recollect the exact canvas API calls, and we can now draw a circle with one line of code, rather than five.
Let’s put it to the test:
// include this at the end of POP.init function
POP.Draw.clear();
POP.Draw.rect(120,120,150,150, 'green');
POP.Draw.circle(100, 100, 50, 'rgba(255,0,0,0.5)');
POP.Draw.text('Hello World', 100, 100, 10, '#000');
Include the code above at the finish of the POP.init
operate, and you should see a few shapes drawn to the canvas.
3 The Magic Touch # How To Design A Mobile Game With Html5
Just as we now have the click
event, cell browsers present methods for catching contact occasions.
The fascinating elements of the code below are the touchstart
, touchmove
, and touchend
occasions. With the standard click
event, we can get the coordinates from e.pageX
and e.pageY
. Touch events are slightly different. They contain a touches array
, every component of which accommodates touch coordinates and other data. We only need the first contact, and we access it like so: e.touches[0]
.
Note: Android supplies JavaScript access to multi-touch actions only since model four.
We also name e.preventDefault()
; when every occasion is fired to disable scrolling, zooming and some other motion that would interrupt the move of the sport.
Add the following code to the POP.init
perform.
// listen for clicks
window.addEventListener('click', function(e) {
e.preventDefault();
POP.Input.set(e);
}, false);
// listen for touches
window.addEventListener('touchstart', function(e) {
e.preventDefault();
// the event object has an array
// named touches; we just want
// the first touch
POP.Input.set(e.touches[0]);
}, false);
window.addEventListener('touchmove', function(e) {
// we're not interested in this,
// but prevent default behaviour
// so the screen doesn't scroll
// or zoom
e.preventDefault();
}, false);
window.addEventListener('touchend', function(e) {
// as above
e.preventDefault();
}, false);
You most likely noticed that the code above passes the occasion data to an Input
object, which we’ve but to outline. Let’s try this now:
// + add this at the bottom of your code,
// before the window.addEventListeners
POP.Input = {
x: 0,
y: 0,
tapped :false,
set: function(data) {
this.x = data.pageX;
this.y = data.pageY;
this.tapped = true;
POP.Draw.circle(this.x, this.y, 10, 'red');
}
};
Now, attempt it out. Hmm, the circles usually are not appearing. A fast scratch of the top and a lightbulb moment! Because we’ve scaled the canvas, we have to account for this when mapping the touch to the screen’s position.
First, we want to subtract the offset from the coordinates.
var offsetTop = POP.canvas.offsetTop,
offsetLeft = POP.canvas.offsetLeft;
this.x = data.pageX - offsetLeft;
this.y = data.pageY - offsetTop;
Then, we need to keep in mind the issue by which the canvas has been scaled so that we will plot to the actual canvas (which continues to be 320 × 480).
var offsetTop = POP.canvas.offsetTop,
offsetLeft = POP.canvas.offsetLeft;
scale = POP.currentWidth / POP.WIDTH;
this.x = ( data.pageX - offsetLeft ) / scale;
this.y = ( data.pageY - offsetTop ) / scale;
If your head is beginning to harm, a practical instance ought to present some relief. Imagine the player faucets the 500 × 750 canvas above at 400,400
. four hundred. We need to translate that to 480 × 320 as an outcome of, so far as the JavaScript is worried, these are the size of the canvas. So, the precise x
coordinate is four hundred divided by the scale; in this case, 400 ÷ 1.56 = 320.5.
Rather than calculating this on every touch occasion, we will calculate them after resizing it. Add the following code to the beginning of this system, along with the opposite variable declarations:
// let's keep track of scale
// along with all initial declarations
// at the start of the program
scale: 1,
// the position of the canvas
// in relation to the screen
offset = {top: 0, left: 0},
In our resize perform, after adjusting the canvas’ width and top, we make note of the present scale and offset:
// add this to the resize function.
POP.scale = POP.currentWidth / POP.WIDTH;
POP.offset.top = POP.canvas.offsetTop;
POP.offset.left = POP.canvas.offsetLeft;
Now, we can use them within the set
method of our POP.Input
class:
this.x = (data.pageX - POP.offset.left) / POP.scale;
this.y = (data.pageY - POP.offset.top) / POP.scale;
4 In The Loop # How To Design A Mobile Game With Html5
A typical sport loop goes one thing like this:
- Poll user enter,
- Update characters and process collisions,
- Render characters on the screen,
- Repeat.
We might, after all, use setInterval
, however, there’s a shiny new toy in town named requestAnimationFrame
. It guarantees smoother animation and is extra battery-efficient. The dangerous news is that it’s not supported constantly throughout browsers. But Paul Irish has come to the rescue with a helpful shim.
Let’s go ahead and add the shim to the start of our current code base.
// https://paulirish.com/2011/requestanimationframe-for-smart-animating
// shim layer with setTimeout fallback
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
And let’s create a rudimentary sport loop:
// Add this at the end of POP.init;
// it will then repeat continuously
POP.loop();
// Add the following functions after POP.init:
// this is where all entities will be moved
// and checked for collisions, etc.
update: function() {
},
// this is where we draw all the entities
render: function() {
POP.Draw.clear();
},
// the actual loop
// requests animation frame,
// then proceeds to update
// and render
loop: function() {
requestAnimFrame( POP.loop );
POP.update();
POP.render();
}
We name the loop on the finish of POP.init
. The POP.loop
function in turn calls our POP.replace
and POP.render
methods. requestAnimFrame
ensures that the loop is known as again, preferably at 60 frames per second. Note that we don’t have to fret about checking for input in our loop because we’re already listening for touch and click occasions, which is accessible by way of our POP. Input
class.
The drawback now is that our touches from the final step are instantly wiped off the display. We want a better method to recollect what was drawn to the screen and where.
5. Spritely Will Do It # How To Design A Mobile Game With Html5
First, we add an entity array to keep monitor of all entities. This array will hold a reference to all touches, bubbles, particles, and some other dynamic thing we need to add to the sport.
// put this at start of program
entities: [],
Let’s create a Touch class that pulls a circle at the level of contact, fades it out and then removes it.
POP.Touch = function(x, y) {
this.type = 'touch'; // we'll need this later
this.x = x; // the x coordinate
this.y = y; // the y coordinate
this.r = 5; // the radius
this.opacity = 1; // initial opacity; the dot will fade out
this.fade = 0.05; // amount by which to fade on each game tick
this.remove = false; // flag for removing this entity. POP.update
// will take care of this
this.update = function() {
// reduce the opacity accordingly
this.opacity -= this.fade;
// if opacity if 0 or less, flag for removal
this.remove = (this.opacity < 0) ? true : false;
};
this.render = function() {
POP.Draw.circle(this.x, this.y, this.r, 'rgba(255,0,0,'+this.opacity+')');
};
};
The Touch
class units a quantity of properties when initiated. The x and y coordinates are passed as arguments, and we set the radius this.r
to 5 pixels. We additionally set an initial opacity to 1 and the speed by which the contact fades to zero.05. There is also a remove
flag that tells the main sport loop whether or not to take away this from the entity’s array.
Crucially, the class has two primary strategies: update
and render
. We will name these from the corresponding part of our game loop.
We can then spawn a new occasion of Touch
in the sport loop, and then move them via the replace method:
// POP.update function
update: function() {
var i;
// spawn a new instance of Touch
// if the user has tapped the screen
if (POP.Input.tapped) {
POP.entities.push(new POP.Touch(POP.Input.x, POP.Input.y));
// set tapped back to false
// to avoid spawning a new touch
// in the next cycle
POP.Input.tapped = false;
}
// cycle through all entities and update as necessary
for (i = 0; i < POP.entities.length; i += 1) {
POP.entities[i].update();
// delete from array if remove property
// flag is set to true
if (POP.entities[i].remove) {
POP.entities.splice(i, 1);
}
}
},
Basically, if POP.Input.tapped
is true
, then we add a new occasion of POP.Touch
to our entities array. We then cycle through the entity’s array, calling the update
technique for every entity. Finally, if the entity is flagged for removal, we delete it from the array.
Next, we render them in the POP.render
operate.
// POP.render function
render: function() {
var i;
POP.Draw.rect(0, 0, POP.WIDTH, POP.HEIGHT, '#036');
// cycle through all entities and render to canvas
for (i = 0; i < POP.entities.length; i += 1) {
POP.entities[i].render();
}
},
Similar to our replace function, we cycle through the entities and call their render
methodology to draw them to the screen.
So far, so good. Now we’ll add a Bubble
class that may create a bubble that floats up for the consumer to pop.
POP.Bubble = function() {
this.type = 'bubble';
this.x = 100;
this.r = 5; // the radius of the bubble
this.y = POP.HEIGHT + 100; // make sure it starts off screen
this.remove = false;
this.update = function() {
// move up the screen by 1 pixel
this.y -= 1;
// if off screen, flag for removal
if (this.y < -10) {
this.remove = true;
}
};
this.render = function() {
POP.Draw.circle(this.x, this.y, this.r, 'rgba(255,255,255,1)');
};
};
The POP.Bubble
class is very similar to the Touch
class, the main differences being that it doesn’t fade but moves upwards. The movement is achieved by updating the y
position, this.y
, in the replace function. Here, we also check whether the bubble is off display; if so, we flag it for elimination.
Note: We may have created a base Entity
class that both Touch
and Bubble
inherit from. But, I’d quite not open another can of worms about JavaScript prototypical inheritance versus classic at this point.
// Add at the start of the program
// the amount of game ticks until
// we spawn a bubble
nextBubble: 100,
// at the start of POP.update
// decrease our nextBubble counter
POP.nextBubble -= 1;
// if the counter is less than zero
if (POP.nextBubble < 0) {
// put a new instance of bubble into our entities array
POP.entities.push(new POP.Bubble());
// reset the counter with a random value
POP.nextBubble = ( Math.random() * 100 ) + 100;
}
Above, we now have added a random timer to our recreation loop that can spawn an instance of Bubble
at a random position. At the beginning of the sport, we set nextBubble
with a value of a hundred. This is subtracted on each sport tick and, when it reaches 0, we spawn a bubble and reset the nextBubble
counter.
6. Putting It Together # How To Design A Mobile Game With Html5
First of all, there is not yet any notion of collision detection. We can add that with an easy operation. The math behind this is basic geometry, which you’ll brush up on at Wolfram MathWorld.
// this function checks if two circles overlap
POP.collides = function(a, b) {
var distance_squared = ( ((a.x - b.x) * (a.x - b.x)) +
((a.y - b.y) * (a.y - b.y)));
var radii_squared = (a.r + b.r) * (a.r + b.r);
if (distance_squared < radii_squared) {
return true;
} else {
return false;
}
};
// at the start of POP.update, we set a flag for checking collisions
var i,
checkCollision = false; // we only need to check for a collision
// if the user tapped on this game tick
// and then incorporate into the main logic
if (POP.Input.tapped) {
POP.entities.push(new POP.Touch(POP.Input.x, POP.Input.y));
// set tapped back to false
// to avoid spawning a new touch
// in the next cycle
POP.Input.tapped = false;
checkCollision = true;
}
// cycle through all entities and update as necessary
for (i = 0; i < POP.entities.length; i += 1) {
POP.entities[i].update();
if (POP.entities[i].type === 'bubble' && checkCollision) {
hit = POP.collides(POP.entities[i],
{x: POP.Input.x, y: POP.Input.y, r: 7});
POP.entities[i].remove = hit;
}
// delete from array if remove property
// is set to true
if (POP.entities[i].remove) {
POP.entities.splice(i, 1);
}
}
The bubbles are somewhat boring; they all journey on the similar pace on a very predictable trajectory. Making the bubbles travel at random speeds is a straightforward task:
POP.Bubble = function() this.sort = ‘bubble’;
this.r = (Math.random() * 20) + 10;
this.speed = (Math.random() * 3) + 1; this.x = (Math.random() * (POP.WIDTH) – this.r);
this.y = POP.HEIGHT + (Math.random() * 100) + 100; this.take away = false; this.update = function() this.y -= this.pace; // the rest of the category is unchanged
And let’s make them oscillate back and forth, in order that they’re harder to hit:
POP.Bubble = function() {
this.type = 'bubble';
this.r = (Math.random() * 20) + 10;
this.speed = (Math.random() * 3) + 1;
this.x = (Math.random() * (POP.WIDTH) - this.r);
this.y = POP.HEIGHT + (Math.random() * 100) + 100;
this.remove = false;
this.update = function() {
this.y -= this.speed;
// the rest of the class is unchanged
Again, we’re using some fundamental geometry to achieve this effect; in this case, a sine wave. While you don’t need to be a math whiz to make video games, primary understanding goes a good distance. The article “A Quick Look Into the Math of Animations With JavaScript” should get you began.
Let’s also present some statistics on screen. To do this, we might need to observe numerous actions throughout the sport.
Put the next code, along with all of the different variable declarations, firstly of this system.
// this goes at the start of the program
// to track players's progress
POP.score = {
taps: 0,
hit: 0,
escaped: 0,
accuracy: 0
},
Now, in the Bubble
class, we will maintain a monitor of POP.score.escaped
when a bubble goes off display.
// in the bubble class, when a bubble makes it to
// the top of the screen
if (this.y < -10) {
POP.score.escaped += 1; // update score
this.remove = true;
}
In the main replace loop, we increase POP.rating.hit
accordingly:
// in the update loop
if (POP.entities[i].type === 'bubble' && checkCollision) {
hit = POP.collides(POP.entities[i],
{x: POP.Input.x, y: POP.Input.y, r: 7});
if (hit) {
POP.score.hit += 1;
}
POP.entities[i].remove = hit;
}
In order for the statistics to be accurate, we need to report all the faucets the consumer makes:
// and record all taps
if (POP.Input.tapped) {
// keep track of taps; needed to
// calculate accuracy
POP.score.taps += 1;
Accuracy is obtained by dividing the variety of hits by the variety of taps, multiplied by a hundred, which provides us a pleasant percentage. Note that ~~(POP.score.accuracy)
is a fast method (i.e. a hack) to spherical floats right down to integers.
// Add at the end of the update loop
// to calculate accuracy
POP.score.accuracy = (POP.score.hit / POP.score.taps) * 100;
POP.score.accuracy = isNaN(POP.score.accuracy) ?
0 :
~~(POP.score.accuracy); // a handy way to round floats
Lastly, we use our POP.Draw.textual
content to show the scores in the principle replace function.
// and finally in the draw function
POP.Draw.text('Hit: ' + POP.score.hit, 20, 30, 14, '#fff');
POP.Draw.text('Escaped: ' + POP.score.escaped, 20, 50, 14, '#fff');
POP.Draw.text('Accuracy: ' + POP.score.accuracy + '%', 20, 70, 14, '#fff');
7. Spit And Polish # How To Design A Mobile Game With Html5
There’s a typical understanding that a playable demo may be made in a couple of hours, but a polished sport takes days, weeks, months, and even years!
We can do a couple of issues to improve the visual enchantment of the sport.
Particle Effects
Most video games boast some type of particle effects, that are nice for explosions. What if we made a bubble explode into many tiny bubbles when it’s popped, somewhat than disappear instantly?
Take a take a glance at our Particle
class:
POP.Particle = function(x, y,r, col) {
this.x = x;
this.y = y;
this.r = r;
this.col = col;
// determines whether particle will
// travel to the right of left
// 50% chance of either happening
this.dir = (Math.random() * 2 > 1) ? 1 : -1;
// random values so particles do not
// travel at the same speeds
this.vx = ~~(Math.random() * 4) * this.dir;
this.vy = ~~(Math.random() * 7);
this.remove = false;
this.update = function() {
// update coordinates
this.x += this.vx;
this.y += this.vy;
// increase velocity so particle
// accelerates off screen
this.vx *= 0.99;
this.vy *= 0.99;
// adding this negative amount to the
// y velocity exerts an upward pull on
// the particle, as if drawn to the
// surface
this.vy -= 0.25;
// off screen
if (this.y < 0) {
this.remove = true;
}
};
this.render = function() {
POP.Draw.circle(this.x, this.y, this.r, this.col);
};
};
It’s fairly apparent what’s going on here. Using some fundamental acceleration so that the particles speed up as they attain the surface is a nice touch. Again, this math and physics are beyond the scope of this text, but for those involved, Skookum Digital Works explains it in depth.
To create the particle effect, we push a quantity of particles into our entities
array every time a bubble is hit:
// modify the main update function like so:
if (hit) {
// spawn an explosion
for (var n = 0; n < 5; n +=1 ) {
POP.entities.push(new POP.Particle(
POP.entities[i].x,
POP.entities[i].y,
2,
// random opacity to spice it up a bit
'rgba(255,255,255,'+Math.random()*1+')'
));
}
POP.score.hit += 1;
}
Waves
Given the underwater theme of the game, adding a wave impact to the highest of the screen could be a nice touch. We can do that by drawing a quantity of overlapping circles to offer the phantasm of waves:
// set up our wave effect;
// basically, a series of overlapping circles
// across the top of screen
POP.wave = {
x: -25, // x coordinate of first circle
y: -40, // y coordinate of first circle
r: 50, // circle radius
time: 0, // we'll use this in calculating the sine wave
offset: 0 // this will be the sine wave offset
};
// calculate how many circles we need to
// cover the screen's width
POP.wave.total = Math.ceil(POP.WIDTH / POP.wave.r) + 1;
Add the code above to the POP.init
perform. POP.wave
has numerous values that we’ll want to draw the waves.
Add the next to the primary replace perform. It uses a sine wave to regulate the place of the waves and give the illusion of movement.
// update wave offset
// feel free to play with these values for
// either slower or faster waves
POP.wave.time = new Date().getTime() * 0.002;
POP.wave.offset = Math.sin(POP.wave.time * 0.8) * 5;
All that’s left to be carried out is to draw the waves, which goes into the render operate.
// display snazzy wave effect
for (i = 0; i < POP.wave.total; i++) {
POP.Draw.circle(
POP.wave.x + POP.wave.offset + (i * POP.wave.r),
POP.wave.y,
POP.wave.r,
'#fff');
}
Here, we’ve reused our sine wave solution for the bubbles to make the waves transfer gently back and forth. Feeling seasick yet?
Final Thoughts
Phew! That was fun. Hope you enjoyed this quick forage into methods and methods for making an HTML5 recreation. We’ve managed to create a very simple sport that works on most smartphones as nicely as trendy browsers. Here are some issues you can contemplate doing:
- Store high scores utilizing native storage.
- Add a splash display screen and a “Game over” screen.
- Enable power-ups.
- Add audio. Contrary to what I stated firstly of this text, this isn’t unimaginable, only a bit of a headache. One method is to use audio sprites (kind of like CSS picture sprites); Remy Sharp breaks it down.
- Let your creativeness run wild!
# How To Design A Mobile Game With Html5