Slingshot: using a mouse to set parameters of flight

In document Using Games to Learn HTML5 and JavaScript (Page 144-157)

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

In document Using Games to Learn HTML5 and JavaScript (Page 144-157)