There are two places in the slingshot program in which I use the distance between points or, more accurately, the square of the distance. I need to find out if the mouse cursor is on top of the ball and I want to make the initial velocity—the equivalent of the velocity out of the cannon— depending on the stretch, so to speak, of the slingshot, the distance (bx,by) to (s1x, s1y). The formula for the distance between two points x1,y1 and x2,y2 is the square root of the sum of the squares of (x1-x2) and (y1-y2). I decided to avoid the computation of taking a square root by just computing the sum of the squares. This provides the same test for the mouse cursor being on top of the ball. For the other task, I decided it was okay to use the
111 square of the distance for the initial velocity. I experimented with some numbers and, as I mentioned earlier, 700 seemed to work.
Building the application and making it your own
Lets now take a look at the code for the basic firing of a cannonball, without a cannon, based on horizontal and initial vertical speeds; the firing of a cannonball from a cannon, based on angle and initial speed out of the cannon; and the slingshot, based on angle and initial speed determined from the position of the mouse. As in previous chapters, Ill present the functions and what they call or are called by for each application. In this case, the tables are similar, though not identical, for all three applications. The calling is more varied than previous examples in that there are situations in which functions are invoked because they are named as methods of a programmer-defined object or as part of a declaration (var) statement. This is a characteristic of object-oriented, event-driven programming. Ill also present the complete code for each application in its own table, along with an explanation of what each line does.
Table 4-1 shows the functions for the basic cannonball application.
Table 4-1. Functions in the Simplest Cannonball Application
Function Invoked By / Called By Calls
init Action of the onLoad in body tag drawall drawall Invoked directly by init,
fire, change
Calls the draw method of all objects in the everything array. These are the functions drawball, drawrects.
fire Invoked by action of the onSubmit attribute in form
drawall
change Invoked by action of the setInterval function called in fire
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
112
Table 4-2 shows the complete code for the simplest application, with the ball moving in an arc and no actual cannon.
Table 4-2. The First Cannonball Application
Code Explanation
<html> Opening html tag
<head> Opening head tag
<title>Cannonball</title> Complete title element
<style> Opening style tag
form { Style for the form
width:330px; Width
margin:20px; External margin
background-color:brown; Color
padding:20px; Internal padding
} Close this style
</style> Close style element
<script> Opening script tag
var cwidth = 600; Set value for width of canvas, used for clearing var cheight = 400; Set value for height of canvas, used for clearing var ctx; Variable to hold canvas context
var everything = []; Array to hold all objects to be drawn. Initialized as an empty array
var tid; Variable to hold identifier for the timing event var horvelocity; Variable to hold the horizontal velocity (aka
displacement)
113 Code Explanation
var verticalvel1; Variable to hold vertical displacement at start of interval var verticalvel2; Variable to hold vertical displacement at end of interval,
after change by gravity
var gravity = 2; Amount of change in vertical displacement. Arbitrary.
Makes for a nice arc.
var iballx = 20; Initial horizontal coordinate for the ball var ibally = 300; Initial vertical coordinate for the ball
function Ball(sx,sy,rad,stylestring) { Start of function to define a Ball. object. Use the parameters to set the properties.
this.sx = sx; Set the sx property of THIS object
this.sy = sy; …sy
this.rad = rad; …rad
this.draw = drawball; …draw. Since drawball is the name of a function, this makes draw a method that can be invoked
this.moveit = moveball; …moveit set to the function moveball this.fillstyle = stylestring; …fillstyle
} Close the Ball function
function drawball() { Header for the drawball function
ctx.fillStyle=this.fillstyle; Set up the fillStyle using the property of this object ctx.beginPath(); Start a path
ctx.arc(this.sx,this.sy ,this.rad,0,Math.PI*2,true);
Set up to draw a circle
ctx.fill(); Draw the path as a filled path
114
Code Explanation
} Close the function
function moveball(dx,dy) { Header for the moveball function this.sx +=dx; Increment the sx property by dx this.sy +=dy; Increment the sy property by dy
} Close function
var cball = new Ball(iballx,ibally, 10,"rgb(250,0,0)");
Create a new Ball object at the indicated position, radius, and color. Assign it to the variable cball. Note that nothing is drawn at this time. The information is just set up for later use.
function Myrectangle(sx,sy,swidth, sheight,stylestring) {
Header for function to construct a Myrectangle object
this.sx = sx; Sets the sx property of THIS object
this.sy = sy; …sy
this.swidth = swidth; …swidth this.sheight = sheight; …sheight this.fillstyle = stylestring; …stylestring
this.draw = drawrects; … draw. This sets up a method that can be invoked.
this.moveit = moveball; ….moveit. This sets up a method that can be invoked.
It is not used in this program.
} Close Myrectangle function
function drawrects() { Header for drawrects function ctx.fillStyle = this.fillstyle; Set the fillStyle
ctx.fillRect(this.sx,this.sy, this.swidth,this.sheight);
Draw the rectangle using the object properties
} Close function
115 Code Explanation var target = new Myrectangle(300,100,
80,200,"rgb(0,5,90)");
Build a Myrectangle object and assign to target
var ground = new Myrectangle(0,300, 600,30,"rgb(10,250,0)");
Build a Myrectangle object and assign to ground
everything.push(target); Add target to everything everything.push(ground); Add ground
everything.push(cball); Add cball (which will be drawn last, so on top of other stuff
function init(){ Header for init function ctx = document.getElementById
('canvas').getContext('2d');
Set up ctx in order to draw on the canvas
drawall(); Draw everything
} Close init
function fire() { Head for fire function
cball.sx = iballx; Reposition cball in x cball.sy = ibally; Reposition cball in y horvelocity = Number(document.
f.hv.value);
Set horizontal velocity from form. Make a number
verticalvel1 = Number(document.
f.vv.value);
Set initial vertical velocity from form
drawall(); Draw everything
tid = setInterval (change,100);
Start timing event
return false; Return false to prevent refresh of HTML page
} Close function
116
Code Explanation
function drawall() { Function header for drawall ctx.clearRect
(0,0,cwidth,cheight);
Erase canvas
var i; Declare var i for the for loop for (i=0;i<everything.length;i++)
{
For each item in everything array…
everything[i].draw();} …invoke the object's draw method. Close for loop.
} Close function
function change() { Header for change function var dx = horvelocity; Set dx to be horvelocity verticalvel2 =
verticalvel1 + gravity;
Compute new vertical velocity (add gravity)
var dy = (verticalvel1 + verticalvel2)*.5;
Compute average velocity for the time interval
verticalvel1 = verticalvel2; Now set old to be new
cball.moveit(dx,dy); Move cball computed amount var bx = cball.sx; Set bx to simplify the if var by = cball.sy; ... and by
if ((bx>=target.sx)&&(bx<=
(target.sx+target.swidth))&&
Is the ball within the target horizontally…
(by>=target.sy)&&(by<=
(target.sy+target.sheight))) {
and vertically?
clearInterval(tid); If so, stop motion
} Close if true clause
if (by>=ground.sy) { Is the ball beyond ground?
117 Code Explanation
clearInterval(tid); If so, stop motion
} Close if true clause
drawall(); Draw everything
} Close change function
</script> Close script element
</head> Close head element
<body onLoad="init();"> Open body and set call to init
<canvas id="canvas" width=
"600" height="400">
Define canvas
Your browser doesn't support the HTML5 element canvas.
Warning to users of non-compliant browsers
</canvas> Close canvas
<br/> Line break
<form name="f" id="f"
onSubmit="return fire();">
Starting form tag, with name and id. This sets up call to fire.
Set velocities and fire cannonball. <br/>
Label and line break
Horizontal displacement <input name=
"hv" id="hv" value="10" type=
"number" min="-100" max="100" />
Label and specification of input field
<br> Line break
Initial vertical displacement <input name="vv" id="vv" value="-25"
type="number" min="-100" max="100"/>
Label and specification of input field
<input type="submit" value="FIRE"/> Submit input element
</form> Close form element
118
Code Explanation
</body> Close body element
</html> Close html element
You certainly can make improvements to this application, but it probably makes more sense to first make sure you understand it as is and then move on to the next.