128
The support for audio and video in HTML5 varies across the browsers. You can look ahead to the presentation of video as a reward for completing the quiz in Chapter 6, and to the audio presented as part of the rock-paper-scissors game in Chapter 8. If you want to tackle this subject, it would be great to have a sound when the cannonball hits the target and a video clip showing the target exploding.
Moving away from the look of the game, you can invent a scoring system, perhaps keeping track of attempts versus hits.
129 Function Invoked By / Called By Calls
change Invoked by action of the setInterval function called in finish
drawall, calls the moveit method of cball, which is moveball.
Ball Invoked directly by code in a var statement Myrectangle Invoked directly by code in a var statement drawball Invoked by call of the draw method for the one
Ball object
drawrects Invoked by call of the draw method for the target object
moveball Invoked by call of the moveit method for the one Ball object
Picture Invoked directly by code in var statements drawAnImage Invoked by call of the draw method for a
picture object
Sling Invoked directly by code in var statements drawsling Invoked by call of the draw method for mysling
Table 4-6 shows the code for the slingshot application, with the new or changed lines commented. Notice that the form is absent from the body element. Before looking at the code, try to identify what parts will be the same as in the cannonball application and what would be different.
Table 4-6. The Slingshot Application
Code Explanation
<html>
<head>
<title>Slingshot pulling back</title>
<script type="text/javascript">
var cwidth = 1200;
130
Code Explanation
var cheight = 600;
var ctx;
var canvas1;
var everything = [];
var tid;
var startrockx = 100; Starting position x var startrocky = 240; Starting position y var ballx = startrockx; Set ballx var bally = startrocky; Set bally var ballrad = 10;
var ballradsq = ballrad*ballrad; Save this value var inmotion = false;
var horvelocity;
var verticalvel1;
var verticalvel2;
var gravity = 2;
var chicken = new Image(); Name of original target chicken.src = "chicken.jpg"; Set image file
var feathers = new Image(); Name of hit target feathers.src = "feathers.gif"; Set image file function Sling(bx,by,s1x,s1y,s2x,s2y,
s3x,s3y,stylestring) {
Function defining a slingshot based on the four points plus a color
131
Code Explanation
this.bx = bx; Set property bx
this.by = by; … by
this.s1x = s1x; … s1x
this.s1y = s1y; … s1y
this.s2x = s2x; … s2x
this.s2y = s2y; … s2y
this.s3x = s3x; … s3x
this.s3y = s3y; … s3y
this.strokeStyle = stylestring; … strokeStyle this.draw = drawsling; Set the draw method
this.moveit = movesling; Set the move method (not used)
} Close function
function drawsling() { Function header for drawsling ctx.strokeStyle = this.strokeStyle; Set this style
ctx.lineWidth = 4; Set line width
ctx.beginPath(); Start the path
ctx.moveTo(this.bx,this.by); Move to bx,by
ctx.lineTo(this.s1x,this.s1y); Set up to draw to s1x,s1y ctx.moveTo(this.bx,this.by); Move to bx,by
ctx.lineTo(this.s2x,this.s2y); Set up to draw to s2x,s2y ctx.moveTo(this.s1x,this.s1y); Move to s1x,s1y
132
Code Explanation
ctx.lineTo(this.s2x,this.s2y); Set up to draw to s2x,s2y ctx.lineTo(this.s3x,this.s3y); Draw to s3x,s3y
ctx.stroke(); Now draw the path
} Close function
function movesling(dx,dy) { Header for movesling
this.bx +=dx; Add dx to bx
this.by +=dy; Add dy to by
this.s1x +=dx; Add dx to slx
this.s1y +=dy; Add dy to s1y
this.s2x +=dx; Add dx to s2x
this.s2y +=dy; Add dy to s2y
this.s3x +=dx; Add dx to s3x
this.s3y +=dy; Add dy to s3y
} Close function
var mysling= new
Sling(startrockx,startrocky,
startrockx+80,startrocky-10,startrockx+80, startrocky+10,startrockx+70,
startrocky+180,"rgb(120,20,10)");
Build new Sling and assign it to the mysling variable
function Ball(sx,sy,rad,stylestring) { this.sx = sx;
this.sy = sy;
this.rad = rad;
this.draw = drawball;
133
Code Explanation
this.moveit = moveball;
this.fillstyle = stylestring;
}
function drawball() {
ctx.fillStyle=this.fillstyle;
ctx.beginPath();
ctx.arc(this.sx,this.sy,this.rad, 0,Math.PI*2,true);
ctx.fill();
}
function moveball(dx,dy) { this.sx +=dx;
this.sy +=dy;
}
var cball = new Ball(startrockx,startrocky, ballrad,"rgb(250,0,0)");
function myrectangle(sx,sy,swidth, sheight,stylestring) {
this.sx = sx;
this.sy = sy;
134
Code Explanation
this.swidth = swidth;
this.sheight = sheight;
this.fillstyle = stylestring;
this.draw = drawrects;
this.moveit = moveball;
}
function drawrects() {
ctx.fillStyle = this.fillstyle;
ctx.fillRect(this.sx,this.sy, this.swidth,this.sheight);
}
function Picture (sx,sy,swidth, sheight,imga) {
this.sx = sx;
this.sy = sy;
this.img = imga;
this.swidth = swidth;
this.sheight = sheight;
this.draw = drawAnImage;
this.moveit = moveball;
}
function drawAnImage() {
135
Code Explanation ctx.drawImage(this.img,this.sx,this.
sy,this.swidth,this.sheight);
}
var target = new Picture(700,210,209, 179,chicken);
Build new Picture object and assign it to target
var ground = new myrectangle(0,370, 1200,30,"rgb(10,250,0)");
everything.push(target);
everything.push(ground); Put the ground on top of the chickens feet everything.push(mysling);
everything.push(cball);
function init(){
ctx = document.getElementById ('canvas').getContext('2d');
canvas1 = document.getElementById ('canvas');
canvas1.addEventListener('mousedown', findball,false);
Set up event handling for the mousedown event
canvas1.addEventListener('mousemove', moveit,false);
Set up event handling for the mousemove event
canvas1.addEventListener('mouseup', finish,false);
Set up event handling for the mouseup event
drawall();
}
function findball(ev) { Function header for mousedown event
var mx; Variable to hold mouse x
136
Code Explanation
var my; Variable to hold mouse y
if ( ev.layerX || ev.layerX == 0) {
ev.layerX is okay
mx= ev.layerX; Use it for mx my = ev.layerY; } Use layerY for my else if (ev.offsetX || ev.offsetX
== 0) {
Else try offset
mx = ev.offsetX; Set mx my = ev.offsetY; } Set my if (distsq(mx,my, cball.sx,
cball.sy)<ballradsq) {
Is mouse over ball?
inmotion = true; Set inmotion
drawall(); Draw everything
} Close if over ball
} Close function
function distsq(x1,y1,x2,y2) { Header for distsq return (x1-x2)*(x1-x2)+(y1-y2)*
(y1-y2);
Return distance squared
} Close function
function moveit(ev) { Function header for mousemove event
var mx; For mouse x
var my; For mouse y
if (inmotion) { in motion?
if ( ev.layerX || ev.layerX == 0) { Does layerX work?
mx= ev.layerX; Use it for mx
137
Code Explanation
my = ev.layerY; ev.layerY for my } else if (ev.offsetX || ev.offsetX == 0) { Does offsetX work?
mx = ev.offsetX; Use it for mx my = ev.offsetY; Use offsetY for my
} Close if true
cball.sx = mx; Position ball x
cball.sy = my; …and y
mysling.bx = mx; Position sling bx
mysling.by = my; … and by
drawall(); Draw everything
} Close if in motion
} Close function
function finish(ev) { Function for mousedown
if (inmotion) { In motion?
inmotion = false; Reset inmotion var outofcannon =
distsq(mysling.bx,mysling.by, mysling.s1x,mysling.s1y)/700;
Base outofcannon proportional to square of bx,by to s1x,s1y
var angleradians = -Math.atan2 (mysling.s1y-mysling.by,
mysling.s1x-mysling.bx);
Compute angle
horvelocity = outofcannon*Math.cos (angleradians);
verticalvel1 = - outofcannon*Math.sin (angleradians);
138
Code Explanation
drawall();
tid = setInterval(change,100);
} }
function drawall() {
ctx.clearRect(0,0,cwidth,cheight);
var i;
for (i=0;i<everything.length;i++) { everything[i].draw();
} }
function change() {
var dx = horvelocity;
verticalvel2 = verticalvel1 + gravity;
var dy = (verticalvel1 + verticalvel2)*.5;
verticalvel1 = verticalvel2;
cball.moveit(dx,dy);
var bx = cball.sx;
var by = cball.sy;
if ((bx>=target.sx+40)&&(bx<=
(target.sx+target.swidth-40))&&
(by>=target.sy+40)&&(by<=
(target.sy+target.sheight-40))) {
Check for inside of target (40 pixels)
139
Code Explanation
target.img = feathers; Change target img }
if (by>=ground.sy) {
clearInterval(tid);
}
drawall();
}
</script>
</head>
<body onLoad="init();">
<canvas id="canvas" width="1200"
height="600">
Your browser doesn't support the HTML5 element canvas.
</canvas>
<br/>
Hold mouse down and drag ball. Releasing the mouse button will shoot the slingshot.
Slingshot remains at the last position.
Reload page to try again.
Instructions for using mouse
</body>
</html>
140
Testing and uploading the application
These applications can be created without external image files, but using images for the target and the hit target is fun, so you remember to include those files when you upload your project. You can choose your own targets. Perhaps you feel kindly towards chickens!
Youll need to test that the program performs correctly in three situations: when the ball plops down to the left of the target, when the ball hits the target, and when the ball sails over the target. Note that I massaged the values so that the chicken needs to be hit in the middle, so it is possible for the ball to touch the head or tail and not cause the feathers to appear.
You can vary the position of the cannon and its target and hit target, and the slingshot and the chicken and the feathers, by changing the variables such as startrockx, and you can modify the gravity variable. If you put the slingshot closer to the target, you can have more ways to hit the chicken: pulling more to the left for a direct shot versus pulling down for more of a lob. Enjoy!
As I mentioned, you could use an animated gif for the hit target in either the cannonball or slingshot applications. This would produce a nice effect.
Summary
In this chapter, you learned how to create two ballistics applications. It is important to understand how they are the same and how they are different. The programming techniques and HTML5 features include
• programmer-defined objects
• setInterval to set up a timing event for the animation, as done for the bouncing ball
• building an array using the push method and using the array as a list of what to display
• modifying arrays using the splice method
• the use of trig functions with calculations to rotate the cannon and to resolve the horizontal and vertical velocities so as to simulate gravity
• using a form for player input
• handling mouse events (mousedown, mousemove, mouseup), with addEventListener to obtain player input
• move drawing arcs, rectangles, lines and images on a canvas
The technique of programmer-defined objects and the use of an array of objects to display will come up again in later chapters. The next chapter focuses on a familiar game known as either memory or concentration. It will use a different timing event as well as the Date function, introduced in Chapter 1.
141