Tip:
Highlight text to annotate it
X
Hi everyone
Today we want to finish our simple whack-a-mole game. We want to make it look a bit nicer
(by adding some simple particle effects), and we want to make sure that it works properly
on mobiles as well as desktop browsers. It's been some time since the last tutorial,
and WADE has evolved quite a lot since then. So first of all, in order to update your WADE,
or to download the new version, you just have to go to www.clockworkchilli.com
You'll notice that the site itself has changed a bit, now you can download WADE directly
from this main page here. But you have to be logged in, which is what I'm going to do
right now.
Now I got this new zip file, let's open that. I am going to copy the latest version of the
wade engine (this javascript file here), plus index.html and style.css. Yes, replace everything.
Now I can delete wade 0.8.
But now we have to remember to edit index.html and make sure that we are loading our awesome.js
file. We have just overwritten this file, so we need to re-do this bit here.
Let's open the game in Chrome to be sure that everything went according to our plans...
Yes, it's working. The background color has changed for some reason, but it doesn't really
matter. If you do want to change it, it's here in style.css. But we'll keep it like
this for now, because I don't really care.
Now let's see how we can make this game a bit better. First of all let's fix the gameplay.
I've created this new picture of a mole with red crosses where its eyes used to be, and
I've called it deadMole.png
Let's load it in our load function:
wade.loadImage('deadMole.png');
Now in mole.js, when a mole is hit, we can tell its sprite to use this new image. We
can get the sprite by doing
var sprite = this.owner.getSprite();
and then
sprite.setImageFile('deadMole.png');
In fact, when a mole dies, we should probably store a flag to remember that it's dead:
this.isDead = true;
Then we should only score points only if the mole is not dead:
if not this.isDead....
And finally, when the mole goes back up again, it is no longer dead:
this.isDead = false;
and this.owner.getSprite().setImageFile('mole.png');
Let's refresh Chrome....
Now you see, I've clicked twice on this mole, but I only got one point. So this is working.
But it doesn't look particularly good. I'm going to add a nice particle effect to highlight
the fact that we've hit the mole. In the game's folder I have added this file called burst.png
(couldn't think of a better name). If we open it, we can see that it isn't a single sprite,
but it's a sprite sheet. This means that it's actually a series of sprites arranged in a
regular grid (it's 4 by 7 grid in this case).
These sprites, when shown in sequence, actually make up an animation. WADE knows how to deal
with these sprite sheet animations, we only have to tell it how many rows and columns
are in the grid. So let's load this image as usual in the load function:
wade.loadImage('burst.png');
And back to mole.js, where we kill the mole, let's play this animation
var burst = new Animation
we are using burst.png, we have a 4 by 7 grid, and we want to play at 30 frames per second.
Then we create a sprite, called burstSprite. Note that this is an empty sprite, that is
I'm not passing an image file name into the constructor of this sprite. Instead, what
I'm going to do is
sprite.addAnimation
Now I need a name here if I want to access this animation in the future, let's just call
it 'particles', and let's use the burst animation that we've just created.
Now I can just do
sprite.playAnimation('particles');
Of course I still need an object to add to the scene. So let's get the position of our
owner... and then we can create an object that uses this sprite, at this position.
Let's add it to the scene:
wade.addSceneObject(obj);
OK, but what happens to this object? I mean, we are going to play this animation, but surely
we want to delete this object at some point. To be precise, we want to delete it as soon
as it's finished playing its particles animation, because we don't need it anymore. We can do
this with easily:
obj.onAnimationEnd = function() {
wade.removeSceneObject(obj); };
Now let's try it
Nice! A bit too small perhaps, let's change that:
sprite.setSize(350, 250);
Ok, so that's done, and it's looking better. Now let's deal with the potentially different
aspect ratios that we might have. Unlike traditional games, this is going to be played on lots
of different devices, so that's going to mean lots of different resolutions and aspect ratios.
How can we make sure that it looks good on as many different aspect ratios as we can?
One way to test it, is by resizing your browser window to whatever resolution you like.
And you see that we have a bit of a problem: when the window gets too small, our game is
no longer playable, because bits of it start to get cut off.
This is because we are assuming that we always have space for our 4x4 grid of holes and moles.
If we are saying that one cell is 300 large, then that means that 4 cells is 1200 large.
But we're looking from farher away (see z equals 2), so everything is scaled down by
50%. This means that we need at least a 600x600 area (in pixels) to be able to play our game.
In fact, it needs to be a little bit taller, because we want to have toom for our score
text at the top too. So let's say 600 by 700 is the minimum resolution that we are going
to need.
All we have to do here, is tell this to WADE, preferably at the beginning of the init function:
wade.setMinScreenSize(600, 700);
What have we done here? Let's see it in action:
Let's start with a big window and see what happens when we make it smaller than 600 x
700? The content gets resized automatically. That's pretty cool, because it means that
the game can always be played, regardless of its resolution.
On the other hand, when we make our window bigger, what is going on at the moment isn't
exactly ideal: the play area is always limited to the same size, it scales down but never
scales up to fill the whole window. But we can fix that. Since we know that the area
occupied by our grass background is 1024x768 (which is half the size of the grass picture,
since we're looking at it from z equals 2), we can just do this:
wade.setMaxScreenSize(1024, 768);
This means that when we make the window bigger than 1024x768, the content is stretched. Always
preserving its aspect ratio though.
Now you might notice some green lines here in the middle of our holes. This is because
now that we are stretching the content, there may be some rounding errors, and the position
or size of your sprites can be off by a fraction of a pixel. You might want to avoid that by
making the two halves of our holes slighly bigger, so that when there is a rounding error
it's not so visible. So in hole.js:
holeTop.setSize(258, 130); holeBottom.setSize(258, 130);
Instead of the actual size which was 256x128. Now let's look again in Chrome, and everything
looks perfect. Well, not exactly everything. The score text
is still disappearing sometimes, depending on the size of the window. This is because
our resolution can change, and more specifically, the height of the game area can change between
700 and 768 (which are the limits that we have set).
Ideally we would like this score text to always be near the top of the screen, regardless
of the current resolution. Let's see how we can do this. Instead of setting its position
to (0, -350), we can try to set it near the top like this:
-wade.getScreenHeight()/2
This is the actual top edge of the screen. Let's add a little bit to move it down slightly,
say 32 pixels. Let's see what happens. It's in the right position. But as soon as
I resize the window, it's in a wrong position again! We want to fix its position relative
to the top edge of the screen. But it's really easy to do this with WADE:
scoreObject.setAlignment('center', 'top'); And there we go. Now it's always in the right
position.
Another thing that is missing here is sounds. Now you may or may not know that audio in
HTML5 games is a bit of a big issue, because it isn't very well supported across all the
different browsers, operating systems and devices. WADE does what it can do to make
sure that everything works on all the different platforms. If you go to clockworkchilli.com
there is an elaborate tutorial which give you some different ways of implementing audio
into your game. For this game here, we are going to use WebAudio. WebAudio is a very
cool audio API that is supported by many different browsers, but not by all of them. Not yet
anyway. It is supported by Firefox, Chrome and Safari (including the Android and IOS
versions), but not Internet Explorer. We still want people to be able to play our games in
Internet Explorer, but I think it's fine for now to just do without the audio for simplicity.
However if you do want to support audio in different devices, then there's a tutorial
on the clockworkchilli website that you can use. So what we are going to do is this: we
are going to check and see if the current browser supports web audio, and if it does
we load a couple of sounds. In the load function:
if (wade.isWebAudioSupported()) {
wade.loadAudio('ding.ogg'); wade.loadAudio('wrong.ogg');
OK you may have noticed that in the game's folder I've put in 4 sound files: ding.ogg,
ding.aac, wrong.ogg and wrong.aac. This is because some (most) browsers support ogg,
some other browsers support aac. So you need to have both versions in your game's folder
for maximum compatibility. However you don't need to worry about this in your code: you
just use the ogg version (or the aac version) and WADE will know to use the other one internally
on the browsers that need the other version.
So then in the mole's onMouseDown function, when we kill a mole, let's play a sound:
wade.playAudioIfAvailable('ding.ogg');
I am using playAudioIfAvailable because the audio may not be have been loaded if the web
audio is not supported (in internet explorer for example).
In the same way, we do this in hole.js:
wade.playAudioIfAvailable('wrong.ogg');
Now let's try it in Chrome
That's cool, isn't it? I think there's just one thing missing, that may not be obvious
if we are only testing this game on a PC. But it would be obvious if you were playing
on a tablet or phone: there is no multitouch support! If you tap with two fingers, only
one of them registers at any one time. But it's really easy to fix. In your app's init
function: wade.enableMultitouch();
Now we want to finish this simple game, by adding a game over screen. So let's say that
when you miss a mole and hit a hole instead, it's game over. So in hole.js, onMouseDown,
instead of decreasing the score, we call wade.app.gameOver And in awesome.js we create this gameOver
function: this.gameOver = function()
Now in here we want to remove absolutely everything from the scene:
wade.clearScene(); Then we are going to tell our players that
it's game over: Var text
This is the text that we are going to show on the screen
var text = 'Game Over You scored ' + this.score + ' points Tap to play again';
You see this slash N here? It's a line break, it's telling WADE that we want to start a
new line of text after the slash N. Then we create a text sprite:
var textSprite = new TextSprite(text, '36px Arial', 'blue', 'center', 3);
And we add it to the scene: wade.addSceneObject(new SceneObject(textSprite));
Let's see now... OK, but then when I click, the game isn't
restarting, which is what I would like to do. Let's just add an onMouseDown function
to our App. When the gameOver function is executed, the "this" keyword represents our
App, so we can add an onMouseDown function to our App in this way:
this.onMouseDown = function() And in here we clear the scene again:
wade.clearScene() Then we disable the onMouseDown event for
the app, otherwise every time the user clicks anywhere, this function is going to be executed
again. So: this.onMouseDown = 0;
And finally, we call the init function, which is going to restart the game.
this.init(); Let's try it now:
And there we go. So what we've go is a really nice game, which is even vaguely entertaining
as well. Best part is, it's only taken us about 45 minutes overall, and that's including
explaining all of steps. I'm pretty sure that with a little bit more time you make something
really good yourselves. Don't forget that on clockworkchilli.com there are some cool
sample games with all the source code that you could use as a starting point to make
your own games. They all come with detailed explanations of how they're made as well.
I really hope you've found these tutorials useful (if you have, give me a thumbs up)
and we'll be back with some more tutorials.
Thanks for watching.