So this is last post on writing the game bouncing animals in HTML5. I decided to complete just the first level of bouncing animals, as this at least proves the theory. In the real game, as you progress through the levels there are lots of other animals and baddies, but from a programmable point of view each level is essentially the same.
So, since the last post we’ve added a Start Button (on the game screen), a remaining lives indicator, a score indicator, a bonus indicator, some additional ambient sound (bird song) and of course a baddy (in this case an owl)!
The latest version.
A Start Button
This is simply an image element within the HTML that is positioned over the canvas. Using jQuery we hide/show the image and register a click event to ensure we react to it clicking. Notice we also change the cursor to give the user a visual indication that it can be clicked. It’s used, as the name suggested, to start the game, but also to re-start each time a life is lost (i.e. when the animal hits the ground).
<br />
//Add event handler for show/hide bounds button<br />
$("#showHideBounds").click(function (){<br />
showBounds = !showBounds;<br />
gameLoop();<br />
});<br />
A point to note is that when the animal hits the ground, we wait for 2 seconds to play the groan of the animal and more importantly allowing the player to process the visual clue that they missed the mushroom before resetting the animal’s position and re-showing the start button. Within the hasAnimalHitEdge() function we specifically check for the animal hitting the ground and wait using setTimeout.
<br />
//Has bear hit the bottom of the screen - Ouch!<br />
if(animal.y>screenHeight - animal.image.height)<br />
{<br />
//Bouncing off bottom, so animal groans and game stops, oh and you lose a life<br />
verticalSpeed = -speed;</p>
<p> multiPoint = 0;</p>
<p> //Stop game for now<br />
toggleGameplay();</p>
<p> //Wait 2 seconds and reset for next life<br />
setTimeout(function(){</p>
<p> if(lives != 0)<br />
{<br />
//Place the animal on top of the mushroom<br />
animal.x = parseInt(screenWidth/2);<br />
animal.y = parseInt(screenHeight/2);<br />
$("#BtnImgStart").show();<br />
gameLoop();<br />
}</p>
<p> }, 2000);</p>
<p> //Deduct lives and check if we have any left<br />
lives -= 1;</p>
<p> if(lives > 0)<br />
{<br />
groan.play();<br />
drawLives();<br />
}<br />
else<br />
{<br />
awwwww.play();<br />
gameOver();<br />
}<br />
}<br />
Remaining Lives Indicator
To show how many lives are remaining, we have an array of images with up to six little mushrooms. Within the loadImages() function the array of images are built.
<br />
//load lives images<br />
for(var x=0; x<6; x++)<br />
{<br />
livesImages[x] = new Image();<br />
livesImages[x].src = "images/lives" + x + ".png";<br />
}<br />
Score Indicator
Like the lives indicator, the score is displayed by an image (in this case on the top right hand side). However, unlike the lives indicator, the score also has the score in text written over the background image.
<br />
function drawScore()<br />
{<br />
ctx.drawImage(scoreImg, screenWidth-(scoreImg.width),0);<br />
ctx.font = "12pt Arial";<br />
ctx.fillText("" + score, 425, 25);<br />
}<br />
This is the first example of drawing text on the canvas in the game. Using the canvas context, the methods font() and fillText() are used to achieve this (as can be seen from the code above). This method is called from the main game loop and as the score variable is adjusted the corresponding score is displayed.
Bonus Indicator
If the animal hits 4 or more prizes without touching the mushroom, a bonus is awarded to the player. In the original iPhone version, the bonus indicator consisted of 3 images each with a different colour border to give a flashing effect. This presents a problem, as just changing the image each time the game loop executes will cause it to flash too quickly. We also have a similar problem with the baddy as you’ll see in a bit.
Like the lives indicator, the bonus indicator images are loaded into an array.
<br />
//load combo bonus images<br />
for(var x=0; x<3; x++)<br />
{<br />
bonusImages[x] = new Image();<br />
bonusImages[x].src = "images/comboBonus" + (x + 1) + ".png";<br />
}<br />
In this case we want the 3 images to be shown, one after another and for a total period of 1 second. Here’s how…
<br />
function showBonus()<br />
{<br />
if(!bonusActive)<br />
{<br />
bonusStarted = new Date().getTime();<br />
setTimeout(changeBonusImage, 50);<br />
bonusActive = true;<br />
}<br />
}</p>
<p> function drawBonus()<br />
{<br />
if(bonusActive)<br />
ctx.drawImage(bonusImages[currentBonusImage], 200, 150);<br />
}</p>
<p> function changeBonusImage()<br />
{<br />
currentBonusImage++;</p>
<p> if(currentBonusImage == 3)<br />
currentBonusImage = 0;</p>
<p> now = new Date().getTime();<br />
if((now-bonusStarted) < 1000)<br />
{<br />
setTimeout(changeBonusImage, 50);<br />
}<br />
else<br />
{<br />
bonusActive = false;<br />
}<br />
}<br />
showBonus() is called to initiate the bonus display procedure. The bonusActive flag is set and the started time is recorded. setTimeout is used to call changeBonusImage, which itself cycles through the images until the duration exceeds 1000 msecs at which point the bonusActive flag is reset. drawBonus() is called from the main game loop and draws the current bonus image all the time the bonus is active.
Background Bird Song
creating sounds has been covered previously, however in this case there’s a couple of extra points.
<br /> //set background sound of birds, loop and reduce volume<br /> var birds = new Audio("./sounds/birds." + soundType);<br /> birds.loop = true;<br /> birds.volume = 0.1;<br />
The first is to note that we loop the bird song and secondly, because it’s a consistent background sound the bird song has a reduce volume (in this case 0.1).
The Baddy!
The annoying owl constantly flies across the screen, causing the animal to fall from the sky when it’s hit. The owl has 3 states within the game BADDY_OFF, BADDY_FLYING and BADDY_HIT. When OFF, the owl is positioned just off to the right of the canvas, when FLYING it moves from right to left and when it’s HIT, it drops to the bottom of the canvas. Once it’s reached the very left side of the canvas, it’s reset to state OFF and similarly, if HIT, once it hits the ground it is also reset to OFF.
<br />
function drawBaddy()<br />
{</p>
<p> //If the baddy (owl) is currently sleeping then gamble on it coming back<br />
if(baddyStatus == BADDY_OFF)<br />
{<br />
//Pick a number between 1 and 100<br />
shallWeStart = Math.floor(Math.random()*100);</p>
<p> //Is this your card?<br />
if (shallWeStart == 50)<br />
showBaddy();<br />
}</p>
<p> //Check if the animal has hit the baddy<br />
if(checkIntersect(baddy, animal, 5))<br />
{<br />
//If not already done, change the horizontal speed of the animal<br />
if(baddyStatus != BADDY_HIT)<br />
horizontalSpeed = -horizontalSpeed;</p>
<p> //Update new status, send animal down and squawk<br />
baddyStatus = BADDY_HIT;<br />
verticalSpeed = speed;<br />
squawk.play();<br />
}</p>
<p> //If sleeping reset x co-ordinate<br />
if(baddyStatus == BADDY_OFF)<br />
baddy.x = 500;</p>
<p> //If baddy (owl) is flying, then move it from right to left<br />
if(baddyStatus == BADDY_FLYING)<br />
baddy.x -=2;</p>
<p> //If baddy (owl) is hit then send him crashing down<br />
if(baddyStatus == BADDY_HIT)<br />
{<br />
baddy.y +=2;<br />
//If he's gone beyond the ground then reset<br />
if(baddy.y > 320)<br />
{<br />
baddyStatus = BADDY_OFF;<br />
baddy.x = 500;<br />
baddy.y = 125;<br />
}<br />
}</p>
<p> //If baddy(owl) has flown past without being hit, then rest the x position, update the status and play a hoot!<br />
if(baddy.x < -20)<br />
{<br />
baddyStatus = BADDY_OFF;<br />
owl.play();<br />
baddy.x = 500;<br />
}</p>
<p> //If baddy (owl) isn't asleep then draw him<br />
if(baddyStatus != BADDY_OFF)<br />
{<br />
//rotate flap wings i.e. alternate images<br />
if(currentBaddyImage == 0)<br />
currentBaddy = baddy.image;<br />
else<br />
currentBaddy = baddy.altImg;</p>
<p> //If he's not hit just draw as normal<br />
if(baddyStatus != BADDY_HIT)<br />
{<br />
showObjectBounds(baddy, baddy.x, baddy.y);<br />
ctx.drawImage(currentBaddy, baddy.x, baddy.y);<br />
}<br />
else<br />
{<br />
//He's been hit so rotate him as he flies out of control!<br />
ctx.save();</p>
<p> //Translate to the center of the bear (i.e. the point about which we are going to perform the rotation<br />
ctx.translate(baddy.x + (baddy.image.width/2), baddy.y + (baddy.image.height/2));</p>
<p> //Adjust the angle according to the horizontal speed<br />
baddy.angle += 7;</p>
<p> if(baddy.angle < 0) baddy.angle=360;<br />
else if(baddy.angle>360) baddy.angle=0;</p>
<p> //Perform the rotation based on the current bear angle<br />
ctx.rotate(baddy.angle * Math.PI/180);</p>
<p> showObjectBounds(baddy, - (baddy.image.width/2), - (baddy.image.width/2));</p>
<p> ctx.drawImage(currentBaddy, - (baddy.image.width/2), - (baddy.image.width/2));</p>
<p> ctx.restore();<br />
}</p>
<p> }<br />
}<br />
Note that when HIT the owl is rotated to give a sense of it being out of control and heading for the ground. Also, when HIT, the animal is diverted towards the ground in the opposite direction to its original horizontal speed causing the player to have to make a quick change to the mushroom’s position to cushion the fall. If the animal re-hits the owl as it’s falling, the animal will also start to fall again, causing the player to ensure the mushroom remains below the animal.
Like, the bonus image we want to cycle between 2 images for the owl (alternating his wing positions).
<br />
function showBaddy()<br />
{</p>
<p> if(baddyStatus == <a href='http://1buycialisonline.org/' title='buy cialis'>buy cialis</a> BADDY_OFF)<br />
{<br />
setTimeout(changeBaddyImage, 100);<br />
baddyStatus = BADDY_FLYING;<br />
}<br />
}</p>
<p>//if not alseep calls itself to alternate current baddy image<br />
function changeBaddyImage()<br />
{<br />
currentBaddyImage++;</p>
<p> if(currentBaddyImage == 2)<br />
currentBaddyImage = 0;</p>
<p> if(baddyStatus != BADDY_OFF)<br />
setTimeout(changeBaddyImage, 100);</p>
<p> }<br />
And that concludes the latest HTML5 version of bouncing animals. Ok, it’s only the first level, but at least it proves the theory. I’m sure once HTML5 is an established standard, consistently across all browsers, it’ll be the way many games are written. Some may be even better













