Web Games Development · Objects, mouse & gravity · ~150 minutes
new.draw(), moveit()).mousedown, mousemove and mouseup.Math.atan2, Math.cos and Math.sin.Create a folder named Week4 and copy the materials (chicken.jpg,
feathers.gif, hill.jpg, plateau.jpg) into it. Create each file below,
writing the code shown. Save and refresh after each change. Tick each checkpoint.
Week4\cannball1.html
<!DOCTYPE html>
<html lang="en">
<head><title>Cannonball</title></head>
<body>
<canvas id="canvas" width="600" height="400"></canvas>
<br />
<form name="f" onsubmit="return fire();">
Horizontal <input name="hv" value="10" type="number" />
Vertical <input name="vv" value="-25" type="number" />
<input type="submit" value="FIRE" />
</form>
<script>
var ctx = document.getElementById("canvas").getContext("2d");
var everything = [];
var tid, horvelocity, verticalvel1, verticalvel2, gravity = 2;
// TODO: create Ball and Myrectangle objects with a draw() method
// TODO: build the scene and push the objects into everything
function drawall() {
ctx.clearRect(0, 0, 600, 400);
for (var i = 0; i < everything.length; i++) { everything[i].draw(); }
}
function fire() {
// TODO: set the velocities and start the animation
return false;
}
function change() {
// TODO: apply gravity and move the ball
}
</script>
</body>
</html>
draw() method.
function Ball(sx, sy, rad, style) {
this.sx = sx; this.sy = sy; this.rad = rad; this.fillstyle = style;
this.draw = drawball; this.moveit = moveball;
}
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; }
function Myrectangle(sx, sy, swidth, sheight, style) {
this.sx = sx; this.sy = sy; this.swidth = swidth; this.sheight = sheight;
this.fillstyle = style; this.draw = drawrects; this.moveit = moverect;
}
function drawrects() { ctx.fillStyle = this.fillstyle; ctx.fillRect(this.sx, this.sy, this.swidth, this.sheight); }
function moverect(dx, dy) { this.sx += dx; this.sy += dy; }
var cball = new Ball(20, 300, 10, "rgb(250,0,0)");
var target = new Myrectangle(300, 100, 80, 200, "rgb(0,5,90)");
var ground = new Myrectangle(0, 300, 600, 30, "rgb(10,250,0)");
var everything = [];
everything.push(target);
everything.push(ground);
everything.push(cball);
change() for gravity.
function change() {
verticalvel2 = verticalvel1 + gravity;
var dy = (verticalvel1 + verticalvel2) * 0.5;
verticalvel1 = verticalvel2;
cball.moveit(horvelocity, dy);
drawall();
}
fire() to launch the ball.
function fire() {
cball.sx = 20; cball.sy = 300;
horvelocity = Number(document.f.hv.value);
verticalvel1 = Number(document.f.vv.value);
drawall();
tid = setInterval(change, 100);
return false;
}
Week4\cannBall2.html
<!DOCTYPE html>
<html lang="en">
<head><title>Cannonball</title></head>
<body>
<canvas id="canvas" width="600" height="400"></canvas>
<br />
<form name="f" onsubmit="return fire();">
Velocity <input name="vo" value="10" type="number" />
Angle <input name="ang" value="45" type="number" />
<input type="submit" value="FIRE" />
</form>
<script>
var ctx = document.getElementById("canvas").getContext("2d");
var everything = [];
var tid, outofcannon, horvelocity, verticalvel1, verticalvel2, gravity = 2;
// TODO: create the target, ground, ball and cannon objects
function drawall() {
ctx.clearRect(0, 0, 600, 400);
// TODO: draw each object (rotate the cannon)
}
function fire() {
// TODO: convert the angle to velocity components and start the animation
return false;
}
function change() {
// TODO: apply gravity, move the ball and check the target
}
</script>
</body>
</html>
draw() method.
function Ball(sx, sy, rad, style) {
this.sx = sx; this.sy = sy; this.rad = rad; this.fillstyle = style;
this.draw = drawball; this.moveit = moveball;
}
function Myrectangle(sx, sy, swidth, sheight, style) {
this.sx = sx; this.sy = sy; this.swidth = swidth; this.sheight = sheight;
this.fillstyle = style; this.draw = drawrects; this.moveit = moverect;
}
function Picture(sx, sy, swidth, sheight, file) {
var imga = new Image(); imga.src = file;
this.sx = sx; this.sy = sy; this.img = imga;
this.swidth = swidth; this.sheight = sheight; this.draw = drawAnImage;
}
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; }
function drawrects() { ctx.fillStyle = this.fillstyle; ctx.fillRect(this.sx, this.sy, this.swidth, this.sheight); }
function moverect(dx, dy) { this.sx += dx; this.sy += dy; }
function drawAnImage() { ctx.drawImage(this.img, this.sx, this.sy, this.swidth, this.sheight); }
everything.
var cannonx = 10, cannony = 280, cannonlength = 200, cannonht = 20;
var ballrad = 10;
var targetx = 500, targety = 50, targetw = 85, targeth = 280;
var htargetx = 450, htargety = 220, htargetw = 355, htargeth = 96;
var cball = new Ball(cannonx + cannonlength, cannony + cannonht * 0.5, ballrad, "rgb(250,0,0)");
var target = new Picture(targetx, targety, targetw, targeth, "hill.jpg");
var htarget = new Picture(htargetx, htargety, htargetw, htargeth, "plateau.jpg");
var ground = new Myrectangle(0, 300, 600, 30, "rgb(10,250,0)");
var cannon = new Myrectangle(cannonx, cannony, cannonlength, cannonht, "rgb(40,40,0)");
everything.push([target, false]);
everything.push([ground, false]);
everything.push([cball, false]);
everything.push([cannon, true, 0, cannonx, cannony + cannonht * 0.5]);
fire() to convert the angle and launch.
function fire() {
var angle = Number(document.f.ang.value);
var outofcannon = Number(document.f.vo.value);
var angleradians = angle * Math.PI / 180;
horvelocity = outofcannon * Math.cos(angleradians);
verticalvel1 = -outofcannon * Math.sin(angleradians);
everything[3][2] = -angleradians;
cball.sx = cannonx + cannonlength * Math.cos(angleradians);
cball.sy = cannony + cannonht * 0.5 - cannonlength * Math.sin(angleradians);
drawall();
tid = setInterval(change, 100);
return false;
}
drawall() to draw every object (rotating the cannon).
function drawall() {
ctx.clearRect(0, 0, 600, 400);
for (var i = 0; i < everything.length; i++) {
var ob = everything[i];
if (ob[1]) {
ctx.save();
ctx.translate(ob[3], ob[4]);
ctx.rotate(ob[2]);
ctx.translate(-ob[3], -ob[4]);
ob[0].draw();
ctx.restore();
} else {
ob[0].draw();
}
}
}
change() to move the ball and swap the target when it is hit (hill → plateau).
function change() {
var dx = horvelocity;
verticalvel2 = verticalvel1 + gravity;
var dy = (verticalvel1 + verticalvel2) * 0.5;
verticalvel1 = verticalvel2;
cball.moveit(dx, dy);
var bx = cball.sx, by = cball.sy;
if (bx >= target.sx && bx <= target.sx + target.swidth && by >= target.sy && by <= target.sy + target.sheight) {
clearInterval(tid);
everything[0][0] = htarget;
drawall();
}
if (by >= ground.sy) { clearInterval(tid); }
drawall();
}
Week4\slingshot.html
<!DOCTYPE html>
<html lang="en">
<head><title>Slingshot pulling back</title></head>
<body>
<canvas id="canvas" width="1200" height="600"></canvas>
<br />
Mouse down and drag ball, then release to shoot.
<script>
var ctx, canvas1, everything = [], tid;
var ballrad = 10, ballradsq = ballrad * ballrad;
var inmotion = false, horvelocity, verticalvel1, verticalvel2, gravity = 2;
var chicken = new Image(); chicken.src = "chicken.jpg";
var feathers = new Image(); feathers.src = "feathers.gif";
// TODO: create Sling, Ball and Picture objects
function init() {
ctx = document.getElementById("canvas").getContext("2d");
canvas1 = document.getElementById("canvas");
// TODO: add mousedown, mousemove and mouseup listeners
// TODO: build the scene and draw it
}
// TODO: add findball(), moveit(), finish(), drawall() and change()
</script>
</body>
</html>
var startrockx = 100, startrocky = 240;
function Sling(bx, by, s1x, s1y, s2x, s2y, s3x, s3y, style) {
this.bx = bx; this.by = by; this.s1x = s1x; this.s1y = s1y;
this.s2x = s2x; this.s2y = s2y; this.s3x = s3x; this.s3y = s3y;
this.strokeStyle = style; this.draw = drawsling; this.moveit = movesling;
}
function drawsling() {
ctx.strokeStyle = this.strokeStyle; ctx.lineWidth = 4;
ctx.beginPath();
ctx.moveTo(this.bx, this.by); ctx.lineTo(this.s1x, this.s1y);
ctx.moveTo(this.bx, this.by); ctx.lineTo(this.s2x, this.s2y);
ctx.moveTo(this.s1x, this.s1y); ctx.lineTo(this.s2x, this.s2y); ctx.lineTo(this.s3x, this.s3y);
ctx.stroke();
}
function movesling(dx, dy) { this.bx += dx; this.by += dy; this.s1x += dx; this.s1y += dy; this.s2x += dx; this.s2y += dy; this.s3x += dx; this.s3y += dy; }
function Ball(sx, sy, rad, style) {
this.sx = sx; this.sy = sy; this.rad = rad; this.fillstyle = style;
this.draw = drawball; this.moveit = moveball;
}
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; }
function Myrectangle(sx, sy, swidth, sheight, style) {
this.sx = sx; this.sy = sy; this.swidth = swidth; this.sheight = sheight;
this.fillstyle = style; this.draw = drawrects;
}
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;
}
function drawAnImage() { ctx.drawImage(this.img, this.sx, this.sy, this.swidth, this.sheight); }
var mysling = new Sling(startrockx, startrocky, startrockx + 80, startrocky - 10, startrockx + 80, startrocky + 10, startrockx + 70, startrocky + 180, "rgb(120,20,10)");
var cball = new Ball(startrockx, startrocky, ballrad, "rgb(250,0,0)");
var target = new Picture(700, 210, 209, 179, chicken);
var ground = new Myrectangle(0, 370, 1200, 30, "rgb(10,250,0)");
init() to wire the mouse events and build the scene.
function init() {
ctx = document.getElementById("canvas").getContext("2d");
canvas1 = document.getElementById("canvas");
canvas1.addEventListener("mousedown", findball, false);
canvas1.addEventListener("mousemove", moveit, false);
canvas1.addEventListener("mouseup", finish, false);
everything.push(target);
everything.push(ground);
everything.push(mysling);
everything.push(cball);
drawall();
}
findball() (hit-test) and distsq().
function findball(ev) {
var mx = ev.layerX, my = ev.layerY;
if (distsq(mx, my, cball.sx, cball.sy) < ballradsq) { inmotion = true; drawall(); }
}
function distsq(x1, y1, x2, y2) { return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); }
moveit() to drag the ball and the sling.
function moveit(ev) {
if (!inmotion) { return; }
cball.sx = ev.pageX; cball.sy = ev.pageY;
mysling.bx = ev.pageX; mysling.by = ev.pageY;
drawall();
}
finish() to turn the drag into a velocity (squared distance + atan2).
function finish(ev) {
if (!inmotion) { return; }
inmotion = false;
var outofcannon = distsq(mysling.bx, mysling.by, mysling.s1x, mysling.s1y) / 700;
var angleradians = -Math.atan2(mysling.s1y - mysling.by, mysling.s1x - mysling.bx);
horvelocity = outofcannon * Math.cos(angleradians);
verticalvel1 = -outofcannon * Math.sin(angleradians);
tid = setInterval(change, 100);
}
drawall() and change() (gravity + hit the chicken).
function drawall() {
ctx.clearRect(0, 0, 1200, 600);
for (var i = 0; i < everything.length; i++) { everything[i].draw(); }
}
function change() {
var dx = horvelocity;
verticalvel2 = verticalvel1 + gravity;
var dy = (verticalvel1 + verticalvel2) * 0.5;
verticalvel1 = verticalvel2;
cball.moveit(dx, dy);
var bx = cball.sx, by = cball.sy;
if (bx >= target.sx + 40 && bx <= target.sx + target.swidth - 40 && by >= target.sy + 40 && by <= target.sy + target.sheight - 40) {
target.img = feathers;
}
if (by >= ground.sy) { clearInterval(tid); }
drawall();
}
| Criterion | Points | Score |
|---|---|---|
Objects built with constructors and new | 3 | |
| Objects stored in an array and redrawn in a loop | 2 | |
| Mouse events wired correctly | 3 | |
| Drag turned into velocity with atan2 / cos / sin | 3 | |
| Gravity arc and collision detection work | 3 | |
| Runs with no console errors | 1 | |
| Total | 15 |
this incorrectly inside object methods.layerX / pageX coordinates.Progress and quiz scores are also tracked on the Week 4 lab page in the class website.