From 91060c38370e87b4fd924888893057bf99a853b0 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Wed, 5 Feb 2014 07:06:25 -0500 Subject: [PATCH 01/39] mini 4 files --- mini4/index.html | 20 ++++++++++++++++++++ mini4/main.js | 31 +++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 mini4/index.html create mode 100644 mini4/main.js diff --git a/mini4/index.html b/mini4/index.html new file mode 100644 index 0000000..719fb94 --- /dev/null +++ b/mini4/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/mini4/main.js b/mini4/main.js new file mode 100644 index 0000000..32ad592 --- /dev/null +++ b/mini4/main.js @@ -0,0 +1,31 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + rect = { + x: width / 2 - 200, + y: height / 2 - 150, + width: 400, + height: 300 + }; + + function clamp(value, min, max) { + return Math.min(Math.max(value, min), max); + } + + document.body.addEventListener("mousemove", function(event) { + var x = clamp(event.clientX, rect.x + 10, rect.x + rect.width - 10), + y = clamp(event.clientY, rect.y + 10, rect.y + rect.height - 10); + + context.clearRect(0, 0, width, height); + context.fillStyle = "#cccccc"; + context.fillRect(rect.x, rect.y, rect.width, rect.height); + + context.fillStyle = "#000000"; + context.beginPath(); + context.arc(x, y, 10, 0, Math.PI * 2, false); + context.fill(); + }); + +}; \ No newline at end of file From bb9002e3adb26e2b3089b0f714b2db87159ea1f5 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Fri, 7 Feb 2014 08:02:36 -0500 Subject: [PATCH 02/39] code for application 1 --- application1/index.html | 23 +++++++++++ application1/main.js | 51 ++++++++++++++++++++++++ application1/particle.js | 48 +++++++++++++++++++++++ application1/utils.js | 17 ++++++++ application1/vector.js | 83 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 222 insertions(+) create mode 100644 application1/index.html create mode 100644 application1/main.js create mode 100644 application1/particle.js create mode 100644 application1/utils.js create mode 100644 application1/vector.js diff --git a/application1/index.html b/application1/index.html new file mode 100644 index 0000000..e8000db --- /dev/null +++ b/application1/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/application1/main.js b/application1/main.js new file mode 100644 index 0000000..b539abc --- /dev/null +++ b/application1/main.js @@ -0,0 +1,51 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + gun = { + x: 100, + y: height, + angle: -Math.PI / 4 + }; + + draw(); + + document.body.addEventListener("mousedown", onMouseDown); + + function onMouseDown(event) { + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function onMouseMove(event) { + aimGun(event.clientX, event.clientY); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function aimGun(mouseX, mouseY) { + gun.angle = utils.clamp(Math.atan2(mouseY - gun.y, mouseX - gun.x), -Math.PI / 2, -0.3); + draw(); + } + + function draw() { + context.clearRect(0, 0, width, height); + + context.beginPath(); + context.arc(gun.x, gun.y, 24, 0, Math.PI * 2, false); + context.fill(); + + context.save(); + context.translate(gun.x, gun.y); + context.rotate(gun.angle); + context.fillRect(0, -8, 40, 16); + context.restore(); + } + +}; \ No newline at end of file diff --git a/application1/particle.js b/application1/particle.js new file mode 100644 index 0000000..5580676 --- /dev/null +++ b/application1/particle.js @@ -0,0 +1,48 @@ +var particle = { + position: null, + velocity: null, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + obj.gravity = vector.create(0, grav || 0); + return obj; + }, + + accelerate: function(accel) { + this.velocity.addTo(accel); + }, + + update: function() { + this.velocity.multiplyBy(this.friction); + this.velocity.addTo(this.gravity); + this.position.addTo(this.velocity); + }, + + angleTo: function(p2) { + return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); + }, + + distanceTo: function(p2) { + var dx = p2.position.getX() - this.position.getX(), + dy = p2.position.getY() - this.position.getY(); + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var grav = vector.create(0, 0), + dist = this.distanceTo(p2); + + grav.setLength(p2.mass / (dist * dist)); + grav.setAngle(this.angleTo(p2)); + this.velocity.addTo(grav); + } +}; \ No newline at end of file diff --git a/application1/utils.js b/application1/utils.js new file mode 100644 index 0000000..28df0b6 --- /dev/null +++ b/application1/utils.js @@ -0,0 +1,17 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return lerp(norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, min), max); + } +} \ No newline at end of file diff --git a/application1/vector.js b/application1/vector.js new file mode 100644 index 0000000..609f6d5 --- /dev/null +++ b/application1/vector.js @@ -0,0 +1,83 @@ +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } +}; \ No newline at end of file From 85096aaf7925b51f6e3875add1a20437d763d0c6 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Mon, 10 Feb 2014 07:50:39 -0500 Subject: [PATCH 03/39] episode 13 code --- episode13/friction1.js | 33 +++++++++++++ episode13/friction2.js | 26 +++++++++++ episode13/index.html | 22 +++++++++ episode13/particle.js | 48 +++++++++++++++++++ episode13/ship2.js | 102 +++++++++++++++++++++++++++++++++++++++++ episode13/vector.js | 83 +++++++++++++++++++++++++++++++++ 6 files changed, 314 insertions(+) create mode 100644 episode13/friction1.js create mode 100644 episode13/friction2.js create mode 100644 episode13/index.html create mode 100644 episode13/particle.js create mode 100644 episode13/ship2.js create mode 100644 episode13/vector.js diff --git a/episode13/friction1.js b/episode13/friction1.js new file mode 100644 index 0000000..8b719e7 --- /dev/null +++ b/episode13/friction1.js @@ -0,0 +1,33 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p = particle.create(width / 2, height / 2, 10, Math.random() * Math.PI * 2), + friction = vector.create(0.15, 0); + + p.radius = 10; + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + friction.setAngle(p.velocity.getAngle()); + + if(p.velocity.getLength() > friction.getLength()) { + p.velocity.subtractFrom(friction); + } + else { + p.velocity.setLength(0); + } + + p.update(); + + context.beginPath(); + context.arc(p.position.getX(), p.position.getY(), p.radius, 0, Math.PI * 2, false); + context.fill(); + + requestAnimationFrame(update); + } +}; \ No newline at end of file diff --git a/episode13/friction2.js b/episode13/friction2.js new file mode 100644 index 0000000..e5b5e40 --- /dev/null +++ b/episode13/friction2.js @@ -0,0 +1,26 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p = particle.create(width / 2, height / 2, 10, Math.random() * Math.PI * 2), + friction = 0.97; + + p.radius = 10; + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + p.velocity.multiplyBy(friction); + p.update(); + + context.beginPath(); + context.arc(p.position.getX(), p.position.getY(), p.radius, 0, Math.PI * 2, false); + context.fill(); + + requestAnimationFrame(update); + } + +}; \ No newline at end of file diff --git a/episode13/index.html b/episode13/index.html new file mode 100644 index 0000000..9ad4a10 --- /dev/null +++ b/episode13/index.html @@ -0,0 +1,22 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/episode13/particle.js b/episode13/particle.js new file mode 100644 index 0000000..5580676 --- /dev/null +++ b/episode13/particle.js @@ -0,0 +1,48 @@ +var particle = { + position: null, + velocity: null, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + obj.gravity = vector.create(0, grav || 0); + return obj; + }, + + accelerate: function(accel) { + this.velocity.addTo(accel); + }, + + update: function() { + this.velocity.multiplyBy(this.friction); + this.velocity.addTo(this.gravity); + this.position.addTo(this.velocity); + }, + + angleTo: function(p2) { + return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); + }, + + distanceTo: function(p2) { + var dx = p2.position.getX() - this.position.getX(), + dy = p2.position.getY() - this.position.getY(); + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var grav = vector.create(0, 0), + dist = this.distanceTo(p2); + + grav.setLength(p2.mass / (dist * dist)); + grav.setAngle(this.angleTo(p2)); + this.velocity.addTo(grav); + } +}; \ No newline at end of file diff --git a/episode13/ship2.js b/episode13/ship2.js new file mode 100644 index 0000000..a93b849 --- /dev/null +++ b/episode13/ship2.js @@ -0,0 +1,102 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight + ship = particle.create(width / 2, height / 2, 0, 0), + thrust = vector.create(0, 0), + angle = 0, + turningLeft = false, + turningRight = false, + thrusting = false; + + ship.friction = 0.99; + + document.body.addEventListener("keydown", function(event) { + // console.log(event.keyCode); + switch(event.keyCode) { + case 38: // up + thrusting = true; + break; + case 37: // left + turningLeft = true; + break; + case 39: // right + turningRight = true; + default: + break + } + }); + + document.body.addEventListener("keyup", function(event) { + // console.log(event.keyCode); + switch(event.keyCode) { + case 38: // up + thrusting = false; + break; + case 37: // left + turningLeft = false; + break; + case 39: // right + turningRight = false; + default: + break + } + }); + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + if(turningRight) { + angle += .05; + } + if(turningLeft) { + angle -= .05; + } + + if(thrusting) { + thrust.setLength(.1); + } + else { + thrust.setLength(0); + } + thrust.setAngle(angle); + + ship.accelerate(thrust); + ship.update(); + + if(ship.position.getX() > width) { + ship.position.setX(0); + } + if(ship.position.getX() < 0) { + ship.position.setX(width); + } + if(ship.position.getY() > height) { + ship.position.setY(0); + } + if(ship.position.getY() < 0) { + ship.position.setY(height); + } + + context.save(); + + context.translate(ship.position.getX(), ship.position.getY()); + context.rotate(angle); + context.beginPath(); + context.moveTo(10, 0); + context.lineTo(-10, -7); + context.lineTo(-10, 7 ); + context.lineTo(10, 0); + if(thrusting) { + context.moveTo(-10, 0); + context.lineTo(-18, 0); + } + context.stroke(); + + context.restore(); + + requestAnimationFrame(update); + } +}; \ No newline at end of file diff --git a/episode13/vector.js b/episode13/vector.js new file mode 100644 index 0000000..609f6d5 --- /dev/null +++ b/episode13/vector.js @@ -0,0 +1,83 @@ +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } +}; \ No newline at end of file From 1128a26e69f7b4fceea6ecdb1eb763a9fe5d05db Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Wed, 12 Feb 2014 10:23:22 -0500 Subject: [PATCH 04/39] mini 6 files --- episode12/particle.js | 1 + episode13/particle.js | 1 + mini6/index.html | 20 ++++++++++++++++++++ mini6/main.js | 30 ++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 mini6/index.html create mode 100644 mini6/main.js diff --git a/episode12/particle.js b/episode12/particle.js index cf32e72..4139869 100644 --- a/episode12/particle.js +++ b/episode12/particle.js @@ -4,6 +4,7 @@ var particle = { mass: 1, radius: 0, bounce: -1, + gravity: 0, create: function(x, y, speed, direction, grav) { var obj = Object.create(this); diff --git a/episode13/particle.js b/episode13/particle.js index 5580676..2269cf9 100644 --- a/episode13/particle.js +++ b/episode13/particle.js @@ -5,6 +5,7 @@ var particle = { radius: 0, bounce: -1, friction: 1, + gravity: 0, create: function(x, y, speed, direction, grav) { var obj = Object.create(this); diff --git a/mini6/index.html b/mini6/index.html new file mode 100644 index 0000000..719fb94 --- /dev/null +++ b/mini6/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/mini6/main.js b/mini6/main.js new file mode 100644 index 0000000..778165f --- /dev/null +++ b/mini6/main.js @@ -0,0 +1,30 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + centerX = width / 2, + centerY = height / 2; + + function distanceXY(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + } + + document.body.addEventListener("mousemove", function(event) { + context.clearRect(0, 0, width, height); + + var dist = distanceXY(centerX, centerY, event.clientX, event.clientY); + if(dist < 100) { + context.fillStyle = "#ff6666"; + } + else { + context.fillStyle = "#cccccc"; + } + + context.beginPath(); + context.arc(centerX, centerY, 100, 0, Math.PI * 360, false); + context.fill(); + }); +}; \ No newline at end of file From e7cafb6ff0f59886f7faf848bb52576f018a53ef Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Fri, 14 Feb 2014 09:53:28 -0500 Subject: [PATCH 05/39] app 2 files --- application2/index.html | 23 ++++++++++ application2/main.js | 97 ++++++++++++++++++++++++++++++++++++++++ application2/particle.js | 48 ++++++++++++++++++++ application2/utils.js | 17 +++++++ application2/vector.js | 83 ++++++++++++++++++++++++++++++++++ 5 files changed, 268 insertions(+) create mode 100644 application2/index.html create mode 100644 application2/main.js create mode 100644 application2/particle.js create mode 100644 application2/utils.js create mode 100644 application2/vector.js diff --git a/application2/index.html b/application2/index.html new file mode 100644 index 0000000..e892cce --- /dev/null +++ b/application2/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/application2/main.js b/application2/main.js new file mode 100644 index 0000000..a9db1d6 --- /dev/null +++ b/application2/main.js @@ -0,0 +1,97 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + gun = { + x: 100, + y: height, + angle: -Math.PI / 4 + }, + cannonball = particle.create(gun.x, gun.y, 15, gun.angle, 0.2), + canShoot = true; + + cannonball.radius = 7; + + draw(); + + document.body.addEventListener("mousedown", onMouseDown); + + document.body.addEventListener("keyup", function(event) { + switch(event.keyCode) { + case 32: // space + if(canShoot) { + shoot(); + } + break; + + default: + break; + } + }); + + function shoot() { + cannonball.position.setX(gun.x + Math.cos(gun.angle) * 40); + cannonball.position.setY(gun.y + Math.sin(gun.angle) * 40); + cannonball.velocity.setLength(15); + cannonball.velocity.setAngle(gun.angle); + + canShoot = false; + update(); + } + + function update() { + cannonball.update(); + draw(); + + if(cannonball.position.getY() > height) { + canShoot = true; + } + else { + requestAnimationFrame(update); + } + } + + function onMouseDown(event) { + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function onMouseMove(event) { + aimGun(event.clientX, event.clientY); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function aimGun(mouseX, mouseY) { + gun.angle = utils.clamp(Math.atan2(mouseY - gun.y, mouseX - gun.x), -Math.PI / 2, -0.3); + draw(); + } + + function draw() { + context.clearRect(0, 0, width, height); + + context.beginPath(); + context.arc(gun.x, gun.y, 24, 0, Math.PI * 2, false); + context.fill(); + + context.save(); + context.translate(gun.x, gun.y); + context.rotate(gun.angle); + context.fillRect(0, -8, 40, 16); + context.restore(); + + context.beginPath(); + context.arc(cannonball.position.getX(), + cannonball.position.getY(), + cannonball.radius, + 0, Math.PI * 2, false); + context.fill(); + } + +}; \ No newline at end of file diff --git a/application2/particle.js b/application2/particle.js new file mode 100644 index 0000000..5580676 --- /dev/null +++ b/application2/particle.js @@ -0,0 +1,48 @@ +var particle = { + position: null, + velocity: null, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + obj.gravity = vector.create(0, grav || 0); + return obj; + }, + + accelerate: function(accel) { + this.velocity.addTo(accel); + }, + + update: function() { + this.velocity.multiplyBy(this.friction); + this.velocity.addTo(this.gravity); + this.position.addTo(this.velocity); + }, + + angleTo: function(p2) { + return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); + }, + + distanceTo: function(p2) { + var dx = p2.position.getX() - this.position.getX(), + dy = p2.position.getY() - this.position.getY(); + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var grav = vector.create(0, 0), + dist = this.distanceTo(p2); + + grav.setLength(p2.mass / (dist * dist)); + grav.setAngle(this.angleTo(p2)); + this.velocity.addTo(grav); + } +}; \ No newline at end of file diff --git a/application2/utils.js b/application2/utils.js new file mode 100644 index 0000000..a34cfec --- /dev/null +++ b/application2/utils.js @@ -0,0 +1,17 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, min), max); + } +} \ No newline at end of file diff --git a/application2/vector.js b/application2/vector.js new file mode 100644 index 0000000..609f6d5 --- /dev/null +++ b/application2/vector.js @@ -0,0 +1,83 @@ +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } +}; \ No newline at end of file From 1bd28c5042f1c9623e5c314b69389d0eb29aa68c Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Mon, 17 Feb 2014 09:44:28 -0500 Subject: [PATCH 06/39] episode 14 files --- episode14/circle-circle.js | 43 ++++++++++++++++++++ episode14/circle-point.js | 30 ++++++++++++++ episode14/index.html | 23 +++++++++++ episode14/main.js | 9 +++++ episode14/particle.js | 49 ++++++++++++++++++++++ episode14/rect-point.js | 24 +++++++++++ episode14/rect-rect.js | 36 +++++++++++++++++ episode14/utils.js | 57 ++++++++++++++++++++++++++ episode14/vector.js | 83 ++++++++++++++++++++++++++++++++++++++ 9 files changed, 354 insertions(+) create mode 100644 episode14/circle-circle.js create mode 100644 episode14/circle-point.js create mode 100644 episode14/index.html create mode 100644 episode14/main.js create mode 100644 episode14/particle.js create mode 100644 episode14/rect-point.js create mode 100644 episode14/rect-rect.js create mode 100644 episode14/utils.js create mode 100644 episode14/vector.js diff --git a/episode14/circle-circle.js b/episode14/circle-circle.js new file mode 100644 index 0000000..6338230 --- /dev/null +++ b/episode14/circle-circle.js @@ -0,0 +1,43 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + circle0 = { + x: Math.random() * width, + y: Math.random() * height, + radius: 50 + Math.random() * 100 + }, + + circle1 = { + x: Math.random() * width, + y: Math.random() * height, + radius: 50 + Math.random() * 100 + }; + + document.body.addEventListener("mousemove", function(event) { + circle1.x = event.clientX; + circle1.y = event.clientY; + + if(utils.circleCollision(circle0, circle1)) { + context.fillStyle = "#f66"; + } + else { + context.fillStyle = "#999"; + } + + context.clearRect(0, 0, width, height); + context.beginPath(); + context.arc(circle0.x, circle0.y, circle0.radius, + 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(circle1.x, circle1.y, circle1.radius, + 0, Math.PI * 2, false); + context.fill(); + + }) + + +}; \ No newline at end of file diff --git a/episode14/circle-point.js b/episode14/circle-point.js new file mode 100644 index 0000000..4e09e9f --- /dev/null +++ b/episode14/circle-point.js @@ -0,0 +1,30 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + circle = { + x: Math.random() * width, + y: Math.random() * height, + radius: 50 + Math.random() * 100 + }; + + document.body.addEventListener("mousemove", function(event) { + + if(utils.circlePointCollision(event.clientX, event.clientY, circle)) { + context.fillStyle = "#f66"; + } + else { + context.fillStyle = "#999"; + } + + context.clearRect(0, 0, width, height); + context.beginPath(); + context.arc(circle.x, circle.y, circle.radius, + 0, Math.PI * 2, false); + context.fill(); + + }) + + +}; \ No newline at end of file diff --git a/episode14/index.html b/episode14/index.html new file mode 100644 index 0000000..b9547fa --- /dev/null +++ b/episode14/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/episode14/main.js b/episode14/main.js new file mode 100644 index 0000000..44dc5bd --- /dev/null +++ b/episode14/main.js @@ -0,0 +1,9 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + + +}; \ No newline at end of file diff --git a/episode14/particle.js b/episode14/particle.js new file mode 100644 index 0000000..2269cf9 --- /dev/null +++ b/episode14/particle.js @@ -0,0 +1,49 @@ +var particle = { + position: null, + velocity: null, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + obj.gravity = vector.create(0, grav || 0); + return obj; + }, + + accelerate: function(accel) { + this.velocity.addTo(accel); + }, + + update: function() { + this.velocity.multiplyBy(this.friction); + this.velocity.addTo(this.gravity); + this.position.addTo(this.velocity); + }, + + angleTo: function(p2) { + return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); + }, + + distanceTo: function(p2) { + var dx = p2.position.getX() - this.position.getX(), + dy = p2.position.getY() - this.position.getY(); + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var grav = vector.create(0, 0), + dist = this.distanceTo(p2); + + grav.setLength(p2.mass / (dist * dist)); + grav.setAngle(this.angleTo(p2)); + this.velocity.addTo(grav); + } +}; \ No newline at end of file diff --git a/episode14/rect-point.js b/episode14/rect-point.js new file mode 100644 index 0000000..6aba12b --- /dev/null +++ b/episode14/rect-point.js @@ -0,0 +1,24 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + rect = { + x: 300, + y: 200, + width: -200, + height: -100 + }; + + document.body.addEventListener("mousemove", function(event) { + + context.clearRect(0, 0, width, height); + if(utils.pointInRect(event.clientX, event.clientY, rect)) { + context.fillStyle = "#ff6666"; + } + else { + context.fillStyle = "#999999"; + } + context.fillRect(rect.x, rect.y, rect.width, rect.height); + }) +}; \ No newline at end of file diff --git a/episode14/rect-rect.js b/episode14/rect-rect.js new file mode 100644 index 0000000..1da4d0d --- /dev/null +++ b/episode14/rect-rect.js @@ -0,0 +1,36 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + rect0 = { + x: 200, + y: 200, + width: -200, + height: -100 + }, + rect1 = { + x: 0, + y: 0, + width: -100, + height: -200 + }; + + document.body.addEventListener("mousemove", function(event) { + rect1.x = event.clientX - 50; + rect1.y = event.clientY - 100; + + context.clearRect(0, 0, width, height); + if(utils.rectIntersect(rect0, rect1)) { + context.fillStyle = "#ff6666"; + } + else { + context.fillStyle = "#999999"; + } + context.fillRect(rect0.x, rect0.y, rect0.width, rect0.height); + context.fillRect(rect1.x, rect1.y, rect1.width, rect1.height); + }) + + + +}; \ No newline at end of file diff --git a/episode14/utils.js b/episode14/utils.js new file mode 100644 index 0000000..bd5b5e6 --- /dev/null +++ b/episode14/utils.js @@ -0,0 +1,57 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + } + +} \ No newline at end of file diff --git a/episode14/vector.js b/episode14/vector.js new file mode 100644 index 0000000..609f6d5 --- /dev/null +++ b/episode14/vector.js @@ -0,0 +1,83 @@ +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } +}; \ No newline at end of file From bccff933c8a8d1000ffc16440dc4205c2b2aa116 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Wed, 26 Feb 2014 11:43:42 -0500 Subject: [PATCH 07/39] mini7 files --- mini7/index.html | 21 ++++++++++++++++ mini7/main.js | 21 ++++++++++++++++ mini7/utils.js | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 mini7/index.html create mode 100644 mini7/main.js create mode 100644 mini7/utils.js diff --git a/mini7/index.html b/mini7/index.html new file mode 100644 index 0000000..e74c311 --- /dev/null +++ b/mini7/index.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/mini7/main.js b/mini7/main.js new file mode 100644 index 0000000..e378341 --- /dev/null +++ b/mini7/main.js @@ -0,0 +1,21 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var angle = Math.PI / 4; + + context.translate(width / 2, height / 2); + context.rotate(angle); + + context.beginPath(); + context.arc(0, 0, 20, 0, Math.PI * 2, 0); + context.fill(); + + context.lineWidth = 10; + context.beginPath(); + context.moveTo(0, 0); + context.lineTo(50, 0); + context.stroke(); +}; \ No newline at end of file diff --git a/mini7/utils.js b/mini7/utils.js new file mode 100644 index 0000000..5372d1f --- /dev/null +++ b/mini7/utils.js @@ -0,0 +1,65 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + } + +} \ No newline at end of file From 38d3b1dc2b707f9957736f5f21a471c25d4174fc Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Tue, 4 Mar 2014 08:13:03 -0500 Subject: [PATCH 08/39] app3, ep 15-16 files --- application3/code.sublime-project | 8 + application3/code.sublime-workspace | 444 ++++++++++++++++++++++++++++ application3/index.html | 23 ++ application3/main.js | 110 +++++++ application3/main2.js | 114 +++++++ application3/particle.js | 48 +++ application3/utils.js | 17 ++ application3/vector.js | 83 ++++++ episode15/index.html | 23 ++ episode15/particle.js | 49 +++ episode15/spring1.js | 50 ++++ episode15/utils.js | 57 ++++ episode15/vector.js | 83 ++++++ episode16/index.html | 23 ++ episode16/particle.js | 49 +++ episode16/spring1.js | 52 ++++ episode16/spring2.js | 91 ++++++ episode16/utils.js | 73 +++++ episode16/vector.js | 83 ++++++ 19 files changed, 1480 insertions(+) create mode 100644 application3/code.sublime-project create mode 100644 application3/code.sublime-workspace create mode 100644 application3/index.html create mode 100644 application3/main.js create mode 100644 application3/main2.js create mode 100644 application3/particle.js create mode 100644 application3/utils.js create mode 100644 application3/vector.js create mode 100644 episode15/index.html create mode 100644 episode15/particle.js create mode 100644 episode15/spring1.js create mode 100644 episode15/utils.js create mode 100644 episode15/vector.js create mode 100644 episode16/index.html create mode 100644 episode16/particle.js create mode 100644 episode16/spring1.js create mode 100644 episode16/spring2.js create mode 100644 episode16/utils.js create mode 100644 episode16/vector.js diff --git a/application3/code.sublime-project b/application3/code.sublime-project new file mode 100644 index 0000000..2862388 --- /dev/null +++ b/application3/code.sublime-project @@ -0,0 +1,8 @@ +{ + "folders": + [ + { + "path": "." + } + ] +} \ No newline at end of file diff --git a/application3/code.sublime-workspace b/application3/code.sublime-workspace new file mode 100644 index 0000000..c592dc9 --- /dev/null +++ b/application3/code.sublime-workspace @@ -0,0 +1,444 @@ +{ + "auto_complete": + { + "selected_items": + [ + [ + "for", + "forceAngle" + ], + [ + "ra", + "rawForce" + ], + [ + "forc", + "forceSpeed" + ], + [ + "inn", + "innerHeight" + ], + [ + "spl", + "splashURL" + ], + [ + "spri", + "springPoint" + ], + [ + "le", + "letter-spacing" + ], + [ + "max", + "max-width" + ], + [ + "bac", + "background-color" + ], + [ + "ba", + "background-color" + ], + [ + "fon", + "font-style" + ], + [ + "te", + "text-align" + ], + [ + "font", + "font-family" + ], + [ + "th", + "thrusting" + ], + [ + "tur", + "turningLeft" + ], + [ + "get", + "getAngle" + ], + [ + "cen", + "centerY" + ], + [ + "sp", + "speedY" + ], + [ + "ang", + "angleY" + ], + [ + "paep", + "paperCanvas" + ], + [ + "speed", + "speedX" + ] + ] + }, + "buffers": + [ + { + "file": "main.js", + "settings": + { + "buffer_size": 2544, + "line_ending": "Windows" + } + }, + { + "file": "code.sublime-project", + "settings": + { + "buffer_size": 44, + "line_ending": "Windows" + } + } + ], + "build_system": "", + "command_palette": + { + "height": 115.0, + "selected_items": + [ + [ + "install", + "Package Control: Install Package" + ], + [ + "package", + "Package Control: Install Package" + ] + ], + "width": 784.0 + }, + "console": + { + "height": 246.0, + "history": + [ + "os.path.expanduser(\"~\")", + "os.path.expandUser(\"~\")", + "os.name", + "include os", + "import os", + "os", + "~", + "import urllib.request,os; pf = 'Package Control.sublime-package'; ipp = sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHandler()) ); open(os.path.join(ipp, pf), 'wb').write(urllib.request.urlopen( 'http://sublime.wbond.net/' + pf.replace(' ','%20')).read())" + ] + }, + "distraction_free": + { + "menu_visible": true, + "show_minimap": false, + "show_open_files": false, + "show_tabs": false, + "side_bar_visible": false, + "status_bar_visible": false + }, + "file_history": + [ + "/C/Users/Keith/Documents/CodingMath/Application3/code/index.html", + "/C/Users/Keith/Documents/CodingMath/Application3/code/utils.js", + "/C/Users/Keith/Documents/CodingMath/Application3/code/main2.js", + "/C/Users/Keith/Documents/Sleepwalker/Sleepwalker.sublime-project", + "/C/Users/Keith/Documents/CodingMath/Site/posts/mini3.html", + "/C/Users/Keith/Documents/CodingMath/Site/styles/main.css", + "/C/Users/Keith/Documents/CodingMath/Site/index.html", + "/C/Users/Keith/Documents/CodingMath/Site/posts/episode10.html", + "/C/Users/Keith/Documents/CodingMath/Site/nav.html", + "/C/Users/Keith/Documents/CodingMath/Site/posts/mini2.html", + "/C/Users/Keith/Documents/CodingMath/Site/feed.rss2", + "/C/Users/Keith/Documents/CodingMath/Site/posts/update1.html", + "/C/Users/Keith/Documents/CodingMath/Site/posts/episode9.html", + "/C/Users/Keith/Documents/CodingMath/Site/posts/mini1.html", + "/C/Users/Keith/Documents/CodingMath/Site/.htaccess", + "/C/Users/Keith/Documents/CodingMath/Site/posts/episode1.html", + "/C/Users/Keith/Documents/CodingMath/Site/posts/episode2.html", + "/C/Users/Keith/Documents/CodingMath/Site/posts/episode3.html", + "/C/Users/Keith/Documents/CodingMath/Site/posts/episode4.html", + "/C/Users/Keith/Documents/CodingMath/Site/posts/episode5.html", + "/C/Users/Keith/Documents/CodingMath/Site/posts/episode6.html", + "/C/Users/Keith/Documents/CodingMath/Site/posts/qa1.html", + "/C/Users/Keith/Documents/CodingMath/Site/posts/episode7.html", + "/C/Users/Keith/Documents/CodingMath/Site/posts/episode8.html", + "/C/Users/Keith/Documents/CodingMath/Site/scripts/main.js", + "/C/Users/Keith/Documents/CodingMath/Site/posts/welcome.html", + "/C/Users/Keith/Documents/CodingMath/Site/posts/feed.rss2.xml", + "/C/Users/Keith/Documents/CodingMath/Site/Site.sublime-project", + "/C/Users/Keith/Documents/Coding Math/Site/Site.sublime-project", + "/C/Users/Keith/Documents/Coding Math/Episode 7/code/vector.js", + "/C/Users/Keith/Documents/Coding Math/Episode 7/code/vector.bak.js", + "/C/Users/Keith/Documents/Coding Math/Episode 6/code/index.html", + "/C/Users/Keith/Documents/Coding Math/episode 4/code/code.sublime-project", + "/C/Users/Keith/Documents/Coding Math/Episode 4/code/code.js", + "/C/Users/Keith/Documents/Coding Math/episode 4/code/trig02.js", + "/C/Users/Keith/Documents/Coding Math/Episode 4/code/bees.js", + "/C/Users/Keith/Documents/Coding Math/Episode 4/code/text.js", + "/C/Users/Keith/Documents/Coding Math/Episode 2/code/episode2.sublime-project", + "/C/Users/Keith/Documents/Coding Math/Episode 4/code/episode4.sublime-project", + "/C/Users/Keith/Documents/Coding Math/Episode 3/code/index.html", + "/C/Users/Keith/Documents/Coding Math/Episode 3/code/trig02.js", + "/C/Users/Keith/Documents/Coding Math/title.html", + "/C/Users/Keith/Documents/Coding Math/Episode 2/code/trig01.js", + "/C/Users/Keith/Documents/Coding Math/Episode 2/code/code.sublime-project", + "/C/Users/Keith/Documents/CodingMath/episode1/sample/index.html", + "/C/Users/Keith/Documents/CodingMath/episode1/sample/main.js", + "/C/Users/Keith/playing-with-curves/code/circle01.html", + "/C/Users/Keith/playing-with-curves/code/pinto.js", + "/C/Users/Keith/playing-with-curves/code/pinto.html", + "/C/Users/Keith/playing-with-curves/code/ellipse.js", + "/C/Users/Keith/playing-with-curves/code/ellipse.html", + "/C/Users/Keith/playing-with-curves/code/sine.js", + "/C/Users/Keith/playing-with-curves/code/sineanim.js", + "/C/Users/Keith/playing-with-curves/code/sineanim.html", + "/C/Users/Keith/playing-with-curves/code/circle02.js", + "/C/Users/Keith/playing-with-curves/code/sine.html", + "/C/Users/Keith/playing-with-curves/code/curve.js", + "/C/Users/Keith/playing-with-curves/code/circle02.html", + "/C/Users/Keith/playing-with-curves/book/pwc_ch00.md", + "/C/Users/Keith/playing-with-curves/code/lissajous01.js", + "/C/Users/Keith/playing-with-curves/book/pwc_ch01.md", + "/C/Users/Keith/playing-with-curves/code/sample.js", + "/C/Users/Keith/playing-with-curves/code/circle.html", + "/C/Users/Keith/experiments/fourier/scripts/main.js", + "/C/Users/Keith/experiments/fourier/scripts/exp.js", + "/C/Users/Keith/experiments/fourier/build.xml", + "/C/Users/Keith/code/experiments/waves/scripts/main.js", + "/C/Users/Keith/AppData/Roaming/Sublime Text 3/Packages/GitGutter/GitGutter.sublime-settings", + "/C/Users/Keith/AppData/Roaming/Sublime Text 3/Packages/User/GitGutter.sublime-settings" + ], + "find": + { + "height": 64.0 + }, + "find_in_files": + { + "height": 176.0, + "where_history": + [ + "" + ] + }, + "find_state": + { + "case_sensitive": false, + "find_history": + [ + "();\n", + "draw", + "_draw", + "console", + "draw", + "_draw", + "Object.create(bitobject).extend", + "\n ", + "header", + "http://codingmath.com", + "

", + "
", + "li", + ");\n", + "50", + ";\n", + "10", + "![", + "draw", + "π", + "4 π", + "2 π", + "PI", + "Trigonometry", + "chaos", + "console", + "children", + "console", + "draw" + ], + "highlight": true, + "in_selection": false, + "preserve_case": false, + "regex": false, + "replace_history": + [ + "update", + "_update", + "update", + "_update", + "bitobject.define", + "posts/episode8.html", + "

", + "

", + "a", + "4π", + "2π", + "π", + "curve" + ], + "reverse": false, + "show_context": true, + "use_buffer2": true, + "whole_word": false, + "wrap": true + }, + "groups": + [ + { + "selected": 1, + "sheets": + [ + { + "buffer": 0, + "file": "main.js", + "semi_transient": false, + "settings": + { + "buffer_size": 2544, + "regions": + { + }, + "selection": + [ + [ + 1059, + 1059 + ] + ], + "settings": + { + "syntax": "Packages/JavaScript/JavaScript.tmLanguage", + "translate_tabs_to_spaces": false + }, + "translation.x": 0.0, + "translation.y": 1266.0, + "zoom_level": 1.0 + }, + "stack_index": 1, + "type": "text" + }, + { + "buffer": 1, + "file": "code.sublime-project", + "semi_transient": false, + "settings": + { + "buffer_size": 44, + "regions": + { + }, + "selection": + [ + [ + 44, + 44 + ] + ], + "settings": + { + "syntax": "Packages/JavaScript/JSON.tmLanguage" + }, + "translation.x": 0.0, + "translation.y": 0.0, + "zoom_level": 1.0 + }, + "stack_index": 0, + "type": "text" + } + ] + } + ], + "incremental_find": + { + "height": 39.0 + }, + "input": + { + "height": 55.0 + }, + "layout": + { + "cells": + [ + [ + 0, + 0, + 1, + 1 + ] + ], + "cols": + [ + 0.0, + 1.0 + ], + "rows": + [ + 0.0, + 1.0 + ] + }, + "menu_visible": true, + "output.find_results": + { + "height": 0.0 + }, + "project": "code.sublime-project", + "replace": + { + "height": 74.0 + }, + "save_all_on_build": true, + "select_file": + { + "height": 0.0, + "selected_items": + [ + ], + "width": 0.0 + }, + "select_project": + { + "height": 1000.0, + "selected_items": + [ + [ + "", + "C:\\Users\\Keith\\Documents\\CodingMath\\Episode 12\\code\\code.sublime-project" + ] + ], + "width": 760.0 + }, + "select_symbol": + { + "height": 0.0, + "selected_items": + [ + ], + "width": 0.0 + }, + "settings": + { + }, + "show_minimap": true, + "show_open_files": false, + "show_tabs": true, + "side_bar_visible": true, + "side_bar_width": 300.0, + "status_bar_visible": true, + "template_settings": + { + } +} diff --git a/application3/index.html b/application3/index.html new file mode 100644 index 0000000..e8000db --- /dev/null +++ b/application3/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/application3/main.js b/application3/main.js new file mode 100644 index 0000000..6b8af4d --- /dev/null +++ b/application3/main.js @@ -0,0 +1,110 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + gun = { + x: 100, + y: height, + angle: -Math.PI / 4 + }, + cannonball = particle.create(gun.x, gun.y, 15, gun.angle, 0.2), + isShooting = false, + forceAngle = 0, + forceSpeed = 0.1, + rawForce = 0; + + cannonball.radius = 7; + + update (); + + document.body.addEventListener("mousedown", onMouseDown); + + document.body.addEventListener("keydown", function(event) { + switch(event.keyCode) { + case 32: // space + if(!isShooting) { + shoot(); + } + break; + + default: + break; + } + }); + + function shoot() { + cannonball.position.setX(gun.x + Math.cos(gun.angle) * 40); + cannonball.position.setY(gun.y + Math.sin(gun.angle) * 40); + cannonball.velocity.setLength(utils.map(rawForce, -1, 1, 2, 20)); + cannonball.velocity.setAngle(gun.angle); + + isShooting = true; + } + + function update() { + if(!isShooting) { + forceAngle += forceSpeed; + } + rawForce = Math.sin(forceAngle); + if(isShooting) { + cannonball.update(); + } + draw(); + + if(cannonball.position.getY() > height) { + isShooting = false; + } + requestAnimationFrame(update); + } + + function onMouseDown(event) { + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function onMouseMove(event) { + aimGun(event.clientX, event.clientY); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function aimGun(mouseX, mouseY) { + gun.angle = utils.clamp(Math.atan2(mouseY - gun.y, mouseX - gun.x), -Math.PI / 2, -0.3); + } + + function draw() { + context.clearRect(0, 0, width, height); + + context.fillStyle = "#ccc"; + context.fillRect(10, height - 10, 20, -100); + + context.fillStyle = "#666"; + context.fillRect(10, height - 10, 20, utils.map(rawForce, -1, 1, 0, -100)); + + context.fillStyle = "#000"; + + context.beginPath(); + context.arc(gun.x, gun.y, 24, 0, Math.PI * 2, false); + context.fill(); + + context.save(); + context.translate(gun.x, gun.y); + context.rotate(gun.angle); + context.fillRect(0, -8, 40, 16); + context.restore(); + + context.beginPath(); + context.arc(cannonball.position.getX(), + cannonball.position.getY(), + cannonball.radius, + 0, Math.PI * 2, false); + context.fill(); + } + +}; \ No newline at end of file diff --git a/application3/main2.js b/application3/main2.js new file mode 100644 index 0000000..5bb68ed --- /dev/null +++ b/application3/main2.js @@ -0,0 +1,114 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + gun = { + x: 100, + y: height, + angle: -Math.PI / 4 + }, + cannonball = particle.create(gun.x, gun.y, 15, gun.angle, 0.2), + isShooting = false, + forceAngle = 0, + forceSpeed = 0.1, + rawForce = 0; + + cannonball.radius = 7; + + update(); + + document.body.addEventListener("mousedown", onMouseDown); + + document.body.addEventListener("keydown", function(event) { + switch(event.keyCode) { + case 32: // space + if(!isShooting) { + shoot(); + } + break; + + default: + break; + } + }); + + function shoot() { + cannonball.position.setX(gun.x + Math.cos(gun.angle) * 40); + cannonball.position.setY(gun.y + Math.sin(gun.angle) * 40); + cannonball.velocity.setLength(utils.map(rawForce, -1, 1, 2, 20)); + cannonball.velocity.setAngle(gun.angle); + + isShooting = true; + } + + function update() { + if(isShooting) { + cannonball.update(); + } + else { + forceAngle += forceSpeed; + rawForce = Math.sin(forceAngle); + } + draw(); + + if(cannonball.position.getY() > height) { + isShooting = false; + } + requestAnimationFrame(update); + } + + function onMouseDown(event) { + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function onMouseMove(event) { + aimGun(event.clientX, event.clientY); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function aimGun(mouseX, mouseY) { + gun.angle = utils.clamp(Math.atan2(mouseY - gun.y, mouseX - gun.x), -Math.PI / 2, -0.3); + draw(); + } + + function draw() { + context.clearRect(0, 0, width, height); + + context.fillStyle = "#ccc"; + context.beginPath(); + context.rect(10, height - 10, 20, -100); + context.fill(); + + context.fillStyle = "#666"; + context.beginPath(); + context.rect(10, height - 10, 20, utils.map(rawForce, -1, 1, 0, -100)); + context.fill(); + + context.fillStyle = "#000"; + context.beginPath(); + context.arc(gun.x, gun.y, 24, 0, Math.PI * 2, false); + context.fill(); + + context.save(); + context.translate(gun.x, gun.y); + context.rotate(gun.angle); + context.fillRect(0, -8, 40, 16); + context.restore(); + + context.beginPath(); + context.arc(cannonball.position.getX(), + cannonball.position.getY(), + cannonball.radius, + 0, Math.PI * 2, false); + context.fill(); + } + +}; \ No newline at end of file diff --git a/application3/particle.js b/application3/particle.js new file mode 100644 index 0000000..5580676 --- /dev/null +++ b/application3/particle.js @@ -0,0 +1,48 @@ +var particle = { + position: null, + velocity: null, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + obj.gravity = vector.create(0, grav || 0); + return obj; + }, + + accelerate: function(accel) { + this.velocity.addTo(accel); + }, + + update: function() { + this.velocity.multiplyBy(this.friction); + this.velocity.addTo(this.gravity); + this.position.addTo(this.velocity); + }, + + angleTo: function(p2) { + return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); + }, + + distanceTo: function(p2) { + var dx = p2.position.getX() - this.position.getX(), + dy = p2.position.getY() - this.position.getY(); + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var grav = vector.create(0, 0), + dist = this.distanceTo(p2); + + grav.setLength(p2.mass / (dist * dist)); + grav.setAngle(this.angleTo(p2)); + this.velocity.addTo(grav); + } +}; \ No newline at end of file diff --git a/application3/utils.js b/application3/utils.js new file mode 100644 index 0000000..a34cfec --- /dev/null +++ b/application3/utils.js @@ -0,0 +1,17 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, min), max); + } +} \ No newline at end of file diff --git a/application3/vector.js b/application3/vector.js new file mode 100644 index 0000000..609f6d5 --- /dev/null +++ b/application3/vector.js @@ -0,0 +1,83 @@ +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } +}; \ No newline at end of file diff --git a/episode15/index.html b/episode15/index.html new file mode 100644 index 0000000..26a2d0a --- /dev/null +++ b/episode15/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/episode15/particle.js b/episode15/particle.js new file mode 100644 index 0000000..2269cf9 --- /dev/null +++ b/episode15/particle.js @@ -0,0 +1,49 @@ +var particle = { + position: null, + velocity: null, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + obj.gravity = vector.create(0, grav || 0); + return obj; + }, + + accelerate: function(accel) { + this.velocity.addTo(accel); + }, + + update: function() { + this.velocity.multiplyBy(this.friction); + this.velocity.addTo(this.gravity); + this.position.addTo(this.velocity); + }, + + angleTo: function(p2) { + return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); + }, + + distanceTo: function(p2) { + var dx = p2.position.getX() - this.position.getX(), + dy = p2.position.getY() - this.position.getY(); + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var grav = vector.create(0, 0), + dist = this.distanceTo(p2); + + grav.setLength(p2.mass / (dist * dist)); + grav.setAngle(this.angleTo(p2)); + this.velocity.addTo(grav); + } +}; \ No newline at end of file diff --git a/episode15/spring1.js b/episode15/spring1.js new file mode 100644 index 0000000..d480dc9 --- /dev/null +++ b/episode15/spring1.js @@ -0,0 +1,50 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + springPoint = vector.create(width / 2, height / 2), + weight = particle.create(Math.random() * width, Math.random() * height, + 50, Math.random() * Math.PI * 2), + k = 0.01 + Math.random() * .5; + + weight.radius = 20; + weight.friction = 0.5 + Math.random() * .5; + + document.body.addEventListener("mousemove", function(event) { + springPoint.setX(event.clientX); + springPoint.setY(event.clientY); + }); + + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + var distance = springPoint.subtract(weight.position), + springForce = distance.multiply(k); + + weight.velocity.addTo(springForce); + + weight.update(); + + context.beginPath(); + context.arc(weight.position.getX(), weight.position.getY(), weight.radius, + 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(springPoint.getX(), springPoint.getY(), 4, + 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.moveTo(weight.position.getX(), weight.position.getY()); + context.lineTo(springPoint.getX(), springPoint.getY()); + context.stroke(); + + requestAnimationFrame(update); + } + +}; \ No newline at end of file diff --git a/episode15/utils.js b/episode15/utils.js new file mode 100644 index 0000000..bd5b5e6 --- /dev/null +++ b/episode15/utils.js @@ -0,0 +1,57 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + } + +} \ No newline at end of file diff --git a/episode15/vector.js b/episode15/vector.js new file mode 100644 index 0000000..609f6d5 --- /dev/null +++ b/episode15/vector.js @@ -0,0 +1,83 @@ +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } +}; \ No newline at end of file diff --git a/episode16/index.html b/episode16/index.html new file mode 100644 index 0000000..9721461 --- /dev/null +++ b/episode16/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/episode16/particle.js b/episode16/particle.js new file mode 100644 index 0000000..2269cf9 --- /dev/null +++ b/episode16/particle.js @@ -0,0 +1,49 @@ +var particle = { + position: null, + velocity: null, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + obj.gravity = vector.create(0, grav || 0); + return obj; + }, + + accelerate: function(accel) { + this.velocity.addTo(accel); + }, + + update: function() { + this.velocity.multiplyBy(this.friction); + this.velocity.addTo(this.gravity); + this.position.addTo(this.velocity); + }, + + angleTo: function(p2) { + return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); + }, + + distanceTo: function(p2) { + var dx = p2.position.getX() - this.position.getX(), + dy = p2.position.getY() - this.position.getY(); + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var grav = vector.create(0, 0), + dist = this.distanceTo(p2); + + grav.setLength(p2.mass / (dist * dist)); + grav.setAngle(this.angleTo(p2)); + this.velocity.addTo(grav); + } +}; \ No newline at end of file diff --git a/episode16/spring1.js b/episode16/spring1.js new file mode 100644 index 0000000..036e6dd --- /dev/null +++ b/episode16/spring1.js @@ -0,0 +1,52 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + springPoint = vector.create(width / 2, height / 2), + weight = particle.create(Math.random() * width, Math.random() * height, + 50, Math.random() * Math.PI * 2, 0.5), + k = 0.1, + springLength = 100; + + weight.radius = 20; + weight.friction = 0.95; + + document.body.addEventListener("mousemove", function(event) { + springPoint.setX(event.clientX); + springPoint.setY(event.clientY); + }); + + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + var distance = springPoint.subtract(weight.position); + distance.setLength(distance.getLength() - springLength); + var springForce = distance.multiply(k); + + weight.velocity.addTo(springForce); + + weight.update(); + + context.beginPath(); + context.arc(weight.position.getX(), weight.position.getY(), weight.radius, + 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(springPoint.getX(), springPoint.getY(), 4, + 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.moveTo(weight.position.getX(), weight.position.getY()); + context.lineTo(springPoint.getX(), springPoint.getY()); + context.stroke(); + + requestAnimationFrame(update); + } + +}; \ No newline at end of file diff --git a/episode16/spring2.js b/episode16/spring2.js new file mode 100644 index 0000000..addc051 --- /dev/null +++ b/episode16/spring2.js @@ -0,0 +1,91 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + particleA = particle.create(utils.randomRange(0, width), + utils.randomRange(0, height), + utils.randomRange(0, 50), + utils.randomRange(0, Math.PI * 2), + 0.2), + particleB = particle.create(utils.randomRange(0, width), + utils.randomRange(0, height), + utils.randomRange(0, 50), + utils.randomRange(0, Math.PI * 2), + 0.2), + particleC = particle.create(utils.randomRange(0, width), + utils.randomRange(0, height), + utils.randomRange(0, 50), + utils.randomRange(0, Math.PI * 2), + 0.2), + k = 0.01, + separation = 200; + + particleA.friction = 0.9; + particleA.radius = 20; + + particleB.friction = 0.9; + particleB.radius = 20; + + particleC.friction = 0.9; + particleC.radius = 20; + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + spring(particleA, particleB, separation); + spring(particleB, particleC, separation); + spring(particleC, particleA, separation); + + checkEdges(particleA); + checkEdges(particleB); + checkEdges(particleC); + + particleA.update(); + particleB.update(); + particleC.update(); + + context.beginPath(); + context.arc(particleA.position.getX(), particleA.position.getY(), + particleA.radius, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(particleB.position.getX(), particleB.position.getY(), + particleB.radius, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(particleC.position.getX(), particleC.position.getY(), + particleC.radius, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.moveTo(particleA.position.getX(), particleA.position.getY()); + context.lineTo(particleB.position.getX(), particleB.position.getY()); + context.lineTo(particleC.position.getX(), particleC.position.getY()); + context.lineTo(particleA.position.getX(), particleA.position.getY()); + context.stroke(); + + requestAnimationFrame(update); + } + + function spring(p0, p1, separation) { + var distance = p0.position.subtract(p1.position); + distance.setLength(distance.getLength() - separation); + + var springForce = distance.multiply(k); + + p1.velocity.addTo(springForce); + p0.velocity.subtractFrom(springForce); + } + + function checkEdges(p) { + if(p.position.getY() + p.radius > height) { + p.position.setY(height - p.radius); + p.velocity.setY(p.velocity.getY() * -0.95); + } + } +}; \ No newline at end of file diff --git a/episode16/utils.js b/episode16/utils.js new file mode 100644 index 0000000..37ae5ef --- /dev/null +++ b/episode16/utils.js @@ -0,0 +1,73 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + } + +} \ No newline at end of file diff --git a/episode16/vector.js b/episode16/vector.js new file mode 100644 index 0000000..609f6d5 --- /dev/null +++ b/episode16/vector.js @@ -0,0 +1,83 @@ +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } +}; \ No newline at end of file From 20159d425921a4b60ed688bd3dcdd943b50d5704 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Tue, 11 Mar 2014 20:58:17 -0400 Subject: [PATCH 09/39] episode 17 files --- episode17/index.html | 23 ++++++++++++ episode17/orbit.js | 34 ++++++++++++++++++ episode17/particle.js | 58 ++++++++++++++++++++++++++++++ episode17/spring1.js | 59 ++++++++++++++++++++++++++++++ episode17/utils.js | 73 +++++++++++++++++++++++++++++++++++++ episode17/vector.js | 83 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 330 insertions(+) create mode 100644 episode17/index.html create mode 100644 episode17/orbit.js create mode 100644 episode17/particle.js create mode 100644 episode17/spring1.js create mode 100644 episode17/utils.js create mode 100644 episode17/vector.js diff --git a/episode17/index.html b/episode17/index.html new file mode 100644 index 0000000..26a2d0a --- /dev/null +++ b/episode17/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/episode17/orbit.js b/episode17/orbit.js new file mode 100644 index 0000000..0121e8a --- /dev/null +++ b/episode17/orbit.js @@ -0,0 +1,34 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + sun = particle.create(width / 2, height / 2, 0, 0); + planet = particle.create(width / 2 + 200, height / 2, 10, -Math.PI / 2); + + sun.mass = 20000; + + update(); + + + function update() { + context.clearRect(0, 0, width, height); + + // animation goes here + + planet.gravitateTo(sun); + planet.update(); + + context.beginPath(); + context.fillStyle = "#ffff00"; + context.arc(sun.x, sun.y, 20, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.fillStyle = "#0000ff"; + context.arc(planet.x, planet.y, 4, 0, Math.PI * 2, false); + context.fill(); + + requestAnimationFrame(update); + } +}; \ No newline at end of file diff --git a/episode17/particle.js b/episode17/particle.js new file mode 100644 index 0000000..76ad889 --- /dev/null +++ b/episode17/particle.js @@ -0,0 +1,58 @@ +var particle = { + x: 0, + y: 0, + vx: 0, + vy: 0, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.x = x; + obj.y = y; + obj.vx = Math.cos(direction) * speed; + obj.vy = Math.sin(direction) * speed; + obj.gravity = grav || 0; + return obj; + }, + + accelerate: function(ax, ay) { + this.vx += ax; + this.vy += ay; + }, + + update: function() { + this.vx *= this.friction; + this.vy *= this.friction; + this.vy += this.gravity; + this.x += this.vx; + this.y += this.vy; + }, + + angleTo: function(p2) { + return Math.atan2(p2.y - this.y, p2.x - this.x); + }, + + distanceTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y; + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y, + distSQ = dx * dx + dy * dy, + dist = Math.sqrt(distSQ), + force = p2.mass / distSQ, + ax = dx / dist * force, + ay = dy / dist * force; + + this.vx += ax; + this.vy += ay; + } +}; \ No newline at end of file diff --git a/episode17/spring1.js b/episode17/spring1.js new file mode 100644 index 0000000..896a012 --- /dev/null +++ b/episode17/spring1.js @@ -0,0 +1,59 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + springPoint = { + x: width / 2, + y: height / 2 + }, + weight = particle.create(Math.random() * width, Math.random() * height, + 50, Math.random() * Math.PI * 2, 0.5), + k = 0.1, + springLength = 100; + + weight.radius = 20; + weight.friction = 0.95; + + document.body.addEventListener("mousemove", function(event) { + springPoint.x = event.clientX ; + springPoint.y = event.clientY; + }); + + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + var dx = springPoint.x - weight.x, + dy = springPoint.y - weight.y, + distance = Math.sqrt(dx * dx + dy * dy), + springForce = (distance - springLength) * k, + ax = dx / distance * springForce, + ay = dy / distance * springForce; + + weight.vx += ax; + weight.vy += ay; + + weight.update(); + + context.beginPath(); + context.arc(weight.x, weight.y, weight.radius, + 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(springPoint.x, springPoint.y, 4, + 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.moveTo(weight.x, weight.y); + context.lineTo(springPoint.x, springPoint.y); + context.stroke(); + + requestAnimationFrame(update); + } + +}; \ No newline at end of file diff --git a/episode17/utils.js b/episode17/utils.js new file mode 100644 index 0000000..37ae5ef --- /dev/null +++ b/episode17/utils.js @@ -0,0 +1,73 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + } + +} \ No newline at end of file diff --git a/episode17/vector.js b/episode17/vector.js new file mode 100644 index 0000000..609f6d5 --- /dev/null +++ b/episode17/vector.js @@ -0,0 +1,83 @@ +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } +}; \ No newline at end of file From 89474f5b8ab7e2686d0d4607f0eb1cad7dd68c6f Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Fri, 14 Mar 2014 06:36:41 -0400 Subject: [PATCH 10/39] app4 and mini8 files --- application4/index.html | 23 +++++++ application4/main.js | 132 +++++++++++++++++++++++++++++++++++++++ application4/particle.js | 59 +++++++++++++++++ application4/utils.js | 73 ++++++++++++++++++++++ application4/vector.js | 83 ++++++++++++++++++++++++ mini8/index.html | 21 +++++++ mini8/main.js | 36 +++++++++++ mini8/test1.js | 7 +++ mini8/test2.js | 7 +++ mini8/utils.js | 74 ++++++++++++++++++++++ 10 files changed, 515 insertions(+) create mode 100644 application4/index.html create mode 100644 application4/main.js create mode 100644 application4/particle.js create mode 100644 application4/utils.js create mode 100644 application4/vector.js create mode 100644 mini8/index.html create mode 100644 mini8/main.js create mode 100644 mini8/test1.js create mode 100644 mini8/test2.js create mode 100644 mini8/utils.js diff --git a/application4/index.html b/application4/index.html new file mode 100644 index 0000000..e8000db --- /dev/null +++ b/application4/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/application4/main.js b/application4/main.js new file mode 100644 index 0000000..bfcad3d --- /dev/null +++ b/application4/main.js @@ -0,0 +1,132 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + gun = { + x: 100, + y: height, + angle: -Math.PI / 4 + }, + cannonball = particle.create(gun.x, gun.y, 15, gun.angle, 0.2), + isShooting = false, + forceAngle = 0, + forceSpeed = 0.1, + rawForce = 0, + target = {}; + + cannonball.radius = 7; + + setTarget(); + update (); + + function setTarget() { + target.x = utils.randomRange(200, width); + target.y = height; + target.radius = utils.randomRange(10, 40); + } + + document.body.addEventListener("mousedown", onMouseDown); + + document.body.addEventListener("keydown", function(event) { + switch(event.keyCode) { + case 32: // space + if(!isShooting) { + shoot(); + } + break; + + default: + break; + } + }); + + function shoot() { + var force = utils.map(rawForce, -1, 1, 2, 20); + cannonball.x = gun.x + Math.cos(gun.angle) * 40; + cannonball.y = gun.y + Math.sin(gun.angle) * 40; + cannonball.vx = Math.cos(gun.angle) * force; + cannonball.vy = Math.sin(gun.angle) * force; + + isShooting = true; + } + + function update() { + if(!isShooting) { + forceAngle += forceSpeed; + } + rawForce = Math.sin(forceAngle); + if(isShooting) { + cannonball.update(); + checkTarget(); + } + draw(); + + if(cannonball.y > height) { + isShooting = false; + } + requestAnimationFrame(update); + } + + function checkTarget() { + if(utils.circleCollision(target, cannonball)) { + // create amazing collision reaction!!! + setTarget(); + } + } + + function onMouseDown(event) { + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function onMouseMove(event) { + aimGun(event.clientX, event.clientY); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function aimGun(mouseX, mouseY) { + gun.angle = utils.clamp(Math.atan2(mouseY - gun.y, mouseX - gun.x), -Math.PI / 2, -0.3); + } + + function draw() { + context.clearRect(0, 0, width, height); + + context.fillStyle = "#ccc"; + context.fillRect(10, height - 10, 20, -100); + + context.fillStyle = "#666"; + context.fillRect(10, height - 10, 20, utils.map(rawForce, -1, 1, 0, -100)); + + context.fillStyle = "#000"; + + context.beginPath(); + context.arc(gun.x, gun.y, 24, 0, Math.PI * 2, false); + context.fill(); + + context.save(); + context.translate(gun.x, gun.y); + context.rotate(gun.angle); + context.fillRect(0, -8, 40, 16); + context.restore(); + + context.beginPath(); + context.arc(cannonball.x, + cannonball.y, + cannonball.radius, + 0, Math.PI * 2, false); + context.fill(); + + context.fillStyle = "red"; + context.beginPath(); + context.arc(target.x, target.y, target.radius, 0, Math.PI * 2, false); + context.fill(); + } + +}; \ No newline at end of file diff --git a/application4/particle.js b/application4/particle.js new file mode 100644 index 0000000..7e15dc5 --- /dev/null +++ b/application4/particle.js @@ -0,0 +1,59 @@ +var particle = { + x: 0, + y: 0, + vx: 0, + vy: 0, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + + create: function(x, y, speed, direction, grav) { + console.log("x: ", x); + var obj = Object.create(this); + this.x = x; + this.y = y; + this.vx = Math.cos(direction) * speed; + this.vy = Math.sin(direction) * speed; + obj.gravity = grav || 0; + return obj; + }, + + accelerate: function(ax, ay) { + this.vx += ax; + this.vy += ay; + }, + + update: function() { + this.vx *= this.friction; + this.vy *= this.friction; + this.vy += this.gravity; + this.x += this.vx; + this.y += this.vy; + }, + + angleTo: function(p2) { + return Math.atan2(p2.y - this.y, p2.x - this.x); + }, + + distanceTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y; + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var dx = this.x - p2.x, + dy = this.y - p2.y, + distSQ = dx * dx + dy * dy, + distance = Math.sqrt(distSQ), + force = p2.mass / distSQ, + ax = dx / distance * force, + ay = dy / distance * force; + + this.vx += ax; + this.vy += ay; + } +}; \ No newline at end of file diff --git a/application4/utils.js b/application4/utils.js new file mode 100644 index 0000000..37ae5ef --- /dev/null +++ b/application4/utils.js @@ -0,0 +1,73 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + } + +} \ No newline at end of file diff --git a/application4/vector.js b/application4/vector.js new file mode 100644 index 0000000..609f6d5 --- /dev/null +++ b/application4/vector.js @@ -0,0 +1,83 @@ +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } +}; \ No newline at end of file diff --git a/mini8/index.html b/mini8/index.html new file mode 100644 index 0000000..e74c311 --- /dev/null +++ b/mini8/index.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/mini8/main.js b/mini8/main.js new file mode 100644 index 0000000..0696243 --- /dev/null +++ b/mini8/main.js @@ -0,0 +1,36 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + gridSize = 40; + + drawGrid(); + + document.body.addEventListener("mousemove", function(event) { + context.clearRect(0, 0, width, height); + drawGrid(); + + var x = utils.roundNearest(event.clientX, gridSize), + y = utils.roundNearest(event.clientY, gridSize); + + context.beginPath(); + context.arc(x, y, 20, 0, Math.PI * 2, false); + context.fill(); + }); + + function drawGrid() { + context.beginPath(); + context.strokeStyle = "#ccc"; + for(var x = 0; x <= width; x += gridSize) { + context.moveTo(x, 0); + context.lineTo(x, height); + } + for(var y = 0; y <= height; y += gridSize) { + context.moveTo(0, y); + context.lineTo(width, y); + } + context.stroke(); + } + +}; \ No newline at end of file diff --git a/mini8/test1.js b/mini8/test1.js new file mode 100644 index 0000000..e8f3ee3 --- /dev/null +++ b/mini8/test1.js @@ -0,0 +1,7 @@ +window.onload = function() { + + console.log(utils.roundToPlaces(Math.PI, 1)); + console.log(utils.roundToPlaces(Math.PI, 3)); + console.log(utils.roundToPlaces(Math.PI, 5)); + +}; \ No newline at end of file diff --git a/mini8/test2.js b/mini8/test2.js new file mode 100644 index 0000000..db9e1c2 --- /dev/null +++ b/mini8/test2.js @@ -0,0 +1,7 @@ +window.onload = function() { + + console.log(utils.roundToPlaces(123456789, -1)); + console.log(utils.roundToPlaces(123456789, -2)); + console.log(utils.roundToPlaces(123456789, -3)); + +}; \ No newline at end of file diff --git a/mini8/utils.js b/mini8/utils.js new file mode 100644 index 0000000..f31970f --- /dev/null +++ b/mini8/utils.js @@ -0,0 +1,74 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + } + +} \ No newline at end of file From de561ee92405e6dd82adb0f11eca0ff8528320af Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Mon, 17 Mar 2014 14:50:05 -0400 Subject: [PATCH 11/39] episode 18 files --- episode18/index.html | 23 +++++++ episode18/main.js | 132 ++++++++++++++++++++++++++++++++++++ episode18/multigravity.js | 63 +++++++++++++++++ episode18/particle.js | 138 ++++++++++++++++++++++++++++++++++++++ episode18/spring1.js | 56 ++++++++++++++++ episode18/utils.js | 73 ++++++++++++++++++++ episode18/vector.js | 83 +++++++++++++++++++++++ 7 files changed, 568 insertions(+) create mode 100644 episode18/index.html create mode 100644 episode18/main.js create mode 100644 episode18/multigravity.js create mode 100644 episode18/particle.js create mode 100644 episode18/spring1.js create mode 100644 episode18/utils.js create mode 100644 episode18/vector.js diff --git a/episode18/index.html b/episode18/index.html new file mode 100644 index 0000000..cb3cccd --- /dev/null +++ b/episode18/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/episode18/main.js b/episode18/main.js new file mode 100644 index 0000000..928ac35 --- /dev/null +++ b/episode18/main.js @@ -0,0 +1,132 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + gun = { + x: 100, + y: height, + angle: -Math.PI / 4 + }, + cannonball = particle.create(gun.x, gun.y, 15, gun.angle, 0.2), + isShooting = false, + forceAngle = 0, + forceSpeed = 0.1, + rawForce = 0, + target = {}; + + cannonball.radius = 7; + + setTarget(); + update (); + + function setTarget() { + target.x = utils.randomRange(200, width); + target.y = height; + target.radius = utils.randomRange(10, 40); + } + + document.body.addEventListener("mousedown", onMouseDown); + + document.body.addEventListener("keydown", function(event) { + switch(event.keyCode) { + case 32: // space + if(!isShooting) { + shoot(); + } + break; + + default: + break; + } + }); + + function shoot() { + var force = utils.map(rawForce, -1, 1, 2, 20); + cannonball.x = gun.x + Math.cos(gun.angle) * 40; + cannonball.y = gun.y + Math.sin(gun.angle) * 40; + cannonball.setSpeed(force); + cannonball.setHeading(gun.angle); + + isShooting = true; + } + + function update() { + if(!isShooting) { + forceAngle += forceSpeed; + } + rawForce = Math.sin(forceAngle); + if(isShooting) { + cannonball.update(); + checkTarget(); + } + draw(); + + if(cannonball.y > height) { + isShooting = false; + } + requestAnimationFrame(update); + } + + function checkTarget() { + if(utils.circleCollision(target, cannonball)) { + // create amazing collision reaction!!! + setTarget(); + } + } + + function onMouseDown(event) { + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function onMouseMove(event) { + aimGun(event.clientX, event.clientY); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function aimGun(mouseX, mouseY) { + gun.angle = utils.clamp(Math.atan2(mouseY - gun.y, mouseX - gun.x), -Math.PI / 2, -0.3); + } + + function draw() { + context.clearRect(0, 0, width, height); + + context.fillStyle = "#ccc"; + context.fillRect(10, height - 10, 20, -100); + + context.fillStyle = "#666"; + context.fillRect(10, height - 10, 20, utils.map(rawForce, -1, 1, 0, -100)); + + context.fillStyle = "#000"; + + context.beginPath(); + context.arc(gun.x, gun.y, 24, 0, Math.PI * 2, false); + context.fill(); + + context.save(); + context.translate(gun.x, gun.y); + context.rotate(gun.angle); + context.fillRect(0, -8, 40, 16); + context.restore(); + + context.beginPath(); + context.arc(cannonball.x, + cannonball.y, + cannonball.radius, + 0, Math.PI * 2, false); + context.fill(); + + context.fillStyle = "red"; + context.beginPath(); + context.arc(target.x, target.y, target.radius, 0, Math.PI * 2, false); + context.fill(); + } + +}; \ No newline at end of file diff --git a/episode18/multigravity.js b/episode18/multigravity.js new file mode 100644 index 0000000..55c22df --- /dev/null +++ b/episode18/multigravity.js @@ -0,0 +1,63 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + sun1 = particle.create(300, 200, 0, 0), + sun2 = particle.create(800, 600, 0, 0), + emitter = { + x: 100, + y: 0 + }, + particles = [], + numParticles = 100; + + + sun1.mass = 10000; + sun1.radius = 10; + sun2.mass = 20000; + sun2.radius = 20; + + for(var i = 0; i < numParticles; i += 1) { + var p = particle.create(emitter.x, emitter.y, utils.randomRange(7, 8), Math.PI / 2 + utils.randomRange(-0.1, 0.1)); + p.addGravitation(sun1); + p.addGravitation(sun2); + p.radius = 3; + particles.push(p); + } + + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + draw(sun1, "yellow"); + draw(sun2, "yellow"); + + for(var i = 0; i < numParticles; i += 1) { + var p = particles[i]; + p.update(); + draw(p, "black"); + if(p.x > width || + p.x < 0 || + p.y > height || + p.y < 0) { + p.x = emitter.x; + p.y = emitter.y; + p.setSpeed(utils.randomRange(7, 8)); + p.setHeading(Math.PI / 2 + utils.randomRange(-.1, .1)); + } + } + + requestAnimationFrame(update); + } + + function draw(p, color) { + context.fillStyle = color; + context.beginPath(); + context.arc(p.x, p.y, p.radius, 0, Math.PI * 2, false); + context.fill(); + } + +}; \ No newline at end of file diff --git a/episode18/particle.js b/episode18/particle.js new file mode 100644 index 0000000..b6ef621 --- /dev/null +++ b/episode18/particle.js @@ -0,0 +1,138 @@ +var particle = { + x: 0, + y: 0, + vx: 0, + vy: 0, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + springs: null, + gravitations: null, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.x = x; + obj.y = y; + obj.vx = Math.cos(direction) * speed; + obj.vy = Math.sin(direction) * speed; + obj.gravity = grav || 0; + obj.springs = []; + obj.gravitations = []; + return obj; + }, + + addGravitation: function(p) { + this.removeGravitation(p); + this.gravitations.push(p); + }, + + removeGravitation: function(p) { + for(var i = 0; i < this.gravitations.length; i += 1) { + if(p === this.gravitations[i]) { + this.gravitations.splice(i, 1); + return; + } + } + }, + + addSpring: function(point, k, length) { + this.removeSpring(point); + this.springs.push({ + point: point, + k: k, + length: length || 0 + }); + }, + + removeSpring: function(point) { + for(var i = 0; i < this.springs.length; i += 1) { + if(point === this.springs[i].point) { + this.springs.splice(i, 1); + return; + } + } + }, + + getSpeed: function() { + return Math.sqrt(this.vx * this.vx + this.vy * this.vy); + }, + + setSpeed: function(speed) { + var heading = this.getHeading(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + getHeading: function() { + return Math.atan2(this.vy, this.vx); + }, + + setHeading: function(heading) { + var speed = this.getSpeed(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + accelerate: function(ax, ay) { + this.vx += ax; + this.vy += ay; + }, + + update: function() { + this.handleSprings(); + this.handleGravitations(); + this.vx *= this.friction; + this.vy *= this.friction; + this.vy += this.gravity; + this.x += this.vx; + this.y += this.vy; + }, + + handleGravitations: function() { + for(var i = 0; i < this.gravitations.length; i += 1) { + this.gravitateTo(this.gravitations[i]); + } + }, + + handleSprings: function() { + for(var i = 0; i < this.springs.length; i += 1) { + var spring = this.springs[i]; + this.springTo(spring.point, spring.k, spring.length); + } + }, + + angleTo: function(p2) { + return Math.atan2(p2.y - this.y, p2.x - this.x); + }, + + distanceTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y; + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y, + distSQ = dx * dx + dy * dy, + dist = Math.sqrt(distSQ), + force = p2.mass / distSQ, + ax = dx / dist * force, + ay = dy / dist * force; + + this.vx += ax; + this.vy += ay; + }, + + springTo: function(point, k, length) { + var dx = point.x - this.x, + dy = point.y - this.y, + distance = Math.sqrt(dx * dx + dy * dy), + springForce = (distance - length || 0) * k; + this.vx += dx / distance * springForce, + this.vy += dy / distance * springForce; + } +}; \ No newline at end of file diff --git a/episode18/spring1.js b/episode18/spring1.js new file mode 100644 index 0000000..1b81c3c --- /dev/null +++ b/episode18/spring1.js @@ -0,0 +1,56 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + springPoint = { + x: width / 2, + y: height / 2 + }, + springPoint2 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + weight = particle.create(Math.random() * width, Math.random() * height, + 50, Math.random() * Math.PI * 2, 0.5), + k = 0.1, + springLength = 100; + + weight.radius = 20; + weight.friction = 0.95; + weight.addSpring(springPoint, k, springLength); + weight.addSpring(springPoint2, k, springLength); + + document.body.addEventListener("mousemove", function(event) { + springPoint.x = event.clientX ; + springPoint.y = event.clientY; + }); + + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + weight.update(); + + context.beginPath(); + context.arc(weight.x, weight.y, weight.radius, + 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(springPoint.x, springPoint.y, 4, + 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.moveTo(springPoint2.x, springPoint2.y); + context.lineTo(weight.x, weight.y); + context.lineTo(springPoint.x, springPoint.y); + context.stroke(); + + requestAnimationFrame(update); + } + +}; \ No newline at end of file diff --git a/episode18/utils.js b/episode18/utils.js new file mode 100644 index 0000000..37ae5ef --- /dev/null +++ b/episode18/utils.js @@ -0,0 +1,73 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + } + +} \ No newline at end of file diff --git a/episode18/vector.js b/episode18/vector.js new file mode 100644 index 0000000..609f6d5 --- /dev/null +++ b/episode18/vector.js @@ -0,0 +1,83 @@ +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } +}; \ No newline at end of file From 5da2cf3634ca79a86ed8ef28bca64d95aa4cf995 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Mon, 24 Mar 2014 12:55:26 -0400 Subject: [PATCH 12/39] episode 19 files --- episode19/demo1.js | 74 ++++++++++++++++++ episode19/demo2.js | 96 +++++++++++++++++++++++ episode19/demo3.js | 106 +++++++++++++++++++++++++ episode19/demo4.js | 125 ++++++++++++++++++++++++++++++ episode19/demo5.js | 130 +++++++++++++++++++++++++++++++ episode19/demo6.js | 180 +++++++++++++++++++++++++++++++++++++++++++ episode19/index.html | 21 +++++ episode19/main1.js | 53 +++++++++++++ episode19/main2.js | 44 +++++++++++ episode19/main3.js | 49 ++++++++++++ episode19/utils.js | 106 +++++++++++++++++++++++++ 11 files changed, 984 insertions(+) create mode 100644 episode19/demo1.js create mode 100644 episode19/demo2.js create mode 100644 episode19/demo3.js create mode 100644 episode19/demo4.js create mode 100644 episode19/demo5.js create mode 100644 episode19/demo6.js create mode 100644 episode19/index.html create mode 100644 episode19/main1.js create mode 100644 episode19/main2.js create mode 100644 episode19/main3.js create mode 100644 episode19/utils.js diff --git a/episode19/demo1.js b/episode19/demo1.js new file mode 100644 index 0000000..51b154e --- /dev/null +++ b/episode19/demo1.js @@ -0,0 +1,74 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: 100, + y: 500 + }, + p1 = { + x: 600, + y: 200 + }, + pA = {}, + t = 0; + + context.scale(1.5, 1.5); + context.font = "16px Arial"; + draw(); + + document.body.addEventListener("click", function() { + draw(); + }); + + function draw() { + context.clearRect(0, 0, width, height); + + context.beginPath(); + context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); + context.fill(); + + pA.x = utils.lerp(t, p0.x, p1.x); + pA.y = utils.lerp(t, p0.y, p1.y); + + context.beginPath(); + context.arc(pA.x, pA.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(pA.x, pA.y); + context.stroke(); + + labelPointLeft(p0, "p0"); + labelPointLeft(p1, "p1 "); + labelPoint(pA, "pA"); + labelT(); + + t += .1; + t = Math.min(t, 1); + + } + + function labelPoint(p, name) { + context.fillText(name, p.x + 10, p.y + 10); + context.fillText("x: " + Math.round(p.x), p.x + 10, p.y + 25); + context.fillText("y: " + Math.round(p.y), p.x + 10, p.y + 40); + } + + function labelPointLeft(p, name) { + context.fillText(name, p.x - 40, p.y - 40); + context.fillText("x: " + Math.round(p.x), p.x - 40, p.y - 25); + context.fillText("y: " + Math.round(p.y), p.x - 40, p.y - 10); + } + + function labelT() { + context.fillText("t = " + utils.roundToPlaces(t, 1), 200, 250); + } + +}; \ No newline at end of file diff --git a/episode19/demo2.js b/episode19/demo2.js new file mode 100644 index 0000000..52dff70 --- /dev/null +++ b/episode19/demo2.js @@ -0,0 +1,96 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: 100, + y: 500 + }, + p1 = { + x: 600, + y: 200 + }, + p2 = { + x: 1000, + y: 400 + }, + pA = {}, + pB = {}, + t = 0; + + context.scale(1.5, 1.5); + context.font = "16px Arial"; + draw(); + + document.body.addEventListener("click", function() { + draw(); + }); + + function draw() { + context.clearRect(0, 0, width, height); + + context.beginPath(); + context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p2.x, p2.y, 4, 0, Math.PI * 2, false); + context.fill(); + + pA.x = utils.lerp(t, p0.x, p1.x); + pA.y = utils.lerp(t, p0.y, p1.y); + + pB.x = utils.lerp(t, p1.x, p2.x); + pB.y = utils.lerp(t, p1.y, p2.y); + + context.beginPath(); + context.arc(pA.x, pA.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(pB.x, pB.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(pA.x, pA.y); + context.moveTo(p1.x, p1.y); + context.lineTo(pB.x, pB.y); + context.stroke(); + + labelPointLeft(p0, "p0"); + labelPointLeft(p1, "p1"); + labelPointLeft(p2, "p2"); + labelPoint(pA, "pA"); + labelPoint(pB, "pB"); + labelT(); + + t += .1; + t = Math.min(t, 1); + + } + + function labelPoint(p, name) { + context.fillStyle = "black"; + context.fillText(name, p.x + 10, p.y + 10); + context.fillText("x: " + Math.round(p.x), p.x + 10, p.y + 25); + context.fillText("y: " + Math.round(p.y), p.x + 10, p.y + 40); + } + + function labelPointLeft(p, name) { + context.fillStyle = "gray"; + context.fillText(name, p.x - 40, p.y - 40); + context.fillText("x: " + Math.round(p.x), p.x - 40, p.y - 25); + context.fillText("y: " + Math.round(p.y), p.x - 40, p.y - 10); + } + + function labelT() { + context.fillText("t = " + utils.roundToPlaces(t, 1), 200, 300); + } + +}; \ No newline at end of file diff --git a/episode19/demo3.js b/episode19/demo3.js new file mode 100644 index 0000000..b709cac --- /dev/null +++ b/episode19/demo3.js @@ -0,0 +1,106 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: 100, + y: 500 + }, + p1 = { + x: 600, + y: 200 + }, + p2 = { + x: 1000, + y: 400 + }, + pA = {}, + pB = {}, + t = 0, + maxT = 0; + + context.scale(1.5, 1.5); + context.font = "16px Arial"; + draw(); + + document.body.addEventListener("click", function() { + draw(); + }); + + function draw() { + context.clearRect(0, 0, width, height); + + context.strokeStyle = "#ccc"; + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.lineTo(p2.x, p2.y); + context.stroke(); + context.beginPath(); + context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.strokeStyle = "black"; + + context.beginPath(); + context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p2.x, p2.y, 4, 0, Math.PI * 2, false); + context.fill(); + + for(var t = 0; t <= maxT; t += .1) { + pA.x = utils.lerp(t, p0.x, p1.x); + pA.y = utils.lerp(t, p0.y, p1.y); + + pB.x = utils.lerp(t, p1.x, p2.x); + pB.y = utils.lerp(t, p1.y, p2.y); + + context.beginPath(); + context.moveTo(pA.x, pA.y); + context.lineTo(pB.x, pB.y); + context.stroke(); + } + + context.beginPath(); + context.arc(pA.x, pA.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(pB.x, pB.y, 4, 0, Math.PI * 2, false); + context.fill(); + + + // labelPointLeft(p0, "p0"); + // labelPointLeft(p1, "p1"); + // labelPointLeft(p2, "p2"); + // labelPoint(pA, "pA"); + // labelPoint(pB, "pB"); + labelT(); + + maxT += .1; + maxT = Math.min(t, 1); + + } + + function labelPoint(p, name) { + context.fillStyle = "black"; + context.fillText(name, p.x + 10, p.y + 10); + context.fillText("x: " + Math.round(p.x), p.x + 10, p.y + 25); + context.fillText("y: " + Math.round(p.y), p.x + 10, p.y + 40); + } + + function labelPointLeft(p, name) { + context.fillStyle = "gray"; + context.fillText(name, p.x - 40, p.y - 40); + context.fillText("x: " + Math.round(p.x), p.x - 40, p.y - 25); + context.fillText("y: " + Math.round(p.y), p.x - 40, p.y - 10); + } + + function labelT() { + context.fillText("t = " + utils.roundToPlaces(maxT, 1), 200, 250); + } + +}; \ No newline at end of file diff --git a/episode19/demo4.js b/episode19/demo4.js new file mode 100644 index 0000000..b966be7 --- /dev/null +++ b/episode19/demo4.js @@ -0,0 +1,125 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: 100, + y: 500 + }, + p1 = { + x: 100, + y: 300 + }, + p2 = { + x: 1000, + y: 400 + }, + pA = {}, + pB = {}, + pFinal = {}, + t = 0, + maxT = 0; + + context.scale(1.5, 1.5); + context.font = "16px Arial"; + draw(); + + document.body.addEventListener("click", function() { + draw(); + }); + + function draw() { + context.clearRect(0, 0, width, height); + + context.strokeStyle = "#ccc"; + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.lineTo(p2.x, p2.y); + context.stroke(); + + context.beginPath(); + context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p2.x, p2.y, 4, 0, Math.PI * 2, false); + context.fill(); + + + context.strokeStyle = "red"; + context.beginPath(); + context.moveTo(p0.x, p0.y); + + for(t = 0; t <= maxT; t += .1) { + pA.x = utils.lerp(t, p0.x, p1.x); + pA.y = utils.lerp(t, p0.y, p1.y); + + pB.x = utils.lerp(t, p1.x, p2.x); + pB.y = utils.lerp(t, p1.y, p2.y); + + pFinal.x = utils.lerp(t, pA.x, pB.x); + pFinal.y = utils.lerp(t, pA.y, pB.y); + + context.lineTo(pFinal.x, pFinal.y); + } + context.stroke(); + + context.beginPath(); + context.strokeStyle = "gray"; + context.moveTo(pA.x, pA.y); + context.lineTo(pB.x, pB.y); + context.stroke(); + + context.beginPath(); + context.arc(pA.x, pA.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(pB.x, pB.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.fillStyle = "red"; + context.beginPath(); + context.arc(pFinal.x, pFinal.y, 4, 0, Math.PI * 2, false); + context.fill(); + context.fillStyle = "black"; + + + + // labelPointLeft(p0, "p0"); + // labelPointLeft(p1, "p1"); + // labelPointLeft(p2, "p2"); + // labelPoint(pA, "pA"); + // labelPoint(pB, "pB"); + labelT(); + + maxT += .1; + maxT = Math.min(t, 1); + + } + + function labelPoint(p, name) { + context.fillStyle = "black"; + context.fillText(name, p.x + 10, p.y + 10); + context.fillText("x: " + Math.round(p.x), p.x + 10, p.y + 25); + context.fillText("y: " + Math.round(p.y), p.x + 10, p.y + 40); + } + + function labelPointLeft(p, name) { + context.fillStyle = "gray"; + context.fillText(name, p.x - 40, p.y - 40); + context.fillText("x: " + Math.round(p.x), p.x - 40, p.y - 25); + context.fillText("y: " + Math.round(p.y), p.x - 40, p.y - 10); + } + + function labelT() { + context.fillText("t = " + utils.roundToPlaces(maxT, 1), 200, 250); + } + +}; \ No newline at end of file diff --git a/episode19/demo5.js b/episode19/demo5.js new file mode 100644 index 0000000..c9000cf --- /dev/null +++ b/episode19/demo5.js @@ -0,0 +1,130 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: 100, + y: 500 + }, + p1 = { + x: 600, + y: 200 + }, + p2 = { + x: 1000, + y: 400 + }, + pA = {}, + pB = {}, + pFinal = {}, + t = 0, + maxT = 0, + dir = 0.01; + + context.scale(1.5, 1.5); + context.font = "16px Arial"; + draw(); + + function draw() { + context.clearRect(0, 0, width, height); + + context.strokeStyle = "#ccc"; + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.lineTo(p2.x, p2.y); + context.stroke(); + + context.beginPath(); + context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p2.x, p2.y, 4, 0, Math.PI * 2, false); + context.fill(); + + + context.strokeStyle = "red"; + context.beginPath(); + context.moveTo(p0.x, p0.y); + + for(t = 0; t <= maxT; t += Math.abs(dir)) { + pA.x = utils.lerp(t, p0.x, p1.x); + pA.y = utils.lerp(t, p0.y, p1.y); + + pB.x = utils.lerp(t, p1.x, p2.x); + pB.y = utils.lerp(t, p1.y, p2.y); + + pFinal.x = utils.lerp(t, pA.x, pB.x); + pFinal.y = utils.lerp(t, pA.y, pB.y); + + context.lineTo(pFinal.x, pFinal.y); + } + context.stroke(); + + context.beginPath(); + context.strokeStyle = "gray"; + context.moveTo(pA.x, pA.y); + context.lineTo(pB.x, pB.y); + context.stroke(); + + context.beginPath(); + context.arc(pA.x, pA.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(pB.x, pB.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.fillStyle = "red"; + context.beginPath(); + context.arc(pFinal.x, pFinal.y, 4, 0, Math.PI * 2, false); + context.fill(); + context.fillStyle = "black"; + + + + // labelPointLeft(p0, "p0"); + // labelPointLeft(p1, "p1"); + // labelPointLeft(p2, "p2"); + // labelPoint(pA, "pA"); + // labelPoint(pB, "pB"); + labelT(); + + maxT += dir; + if(maxT >= 1) { + maxT = 1; + dir *= -1; + } + if(maxT <= 0) { + maxT = 0; + dir *= -1; + } + + requestAnimationFrame(draw); + } + + function labelPoint(p, name) { + context.fillStyle = "black"; + context.fillText(name, p.x + 10, p.y + 10); + context.fillText("x: " + Math.round(p.x), p.x + 10, p.y + 25); + context.fillText("y: " + Math.round(p.y), p.x + 10, p.y + 40); + } + + function labelPointLeft(p, name) { + context.fillStyle = "gray"; + context.fillText(name, p.x - 40, p.y - 40); + context.fillText("x: " + Math.round(p.x), p.x - 40, p.y - 25); + context.fillText("y: " + Math.round(p.y), p.x - 40, p.y - 10); + } + + function labelT() { + context.fillText("t = " + utils.roundToPlaces(maxT, 2), 200, 250); + } + +}; \ No newline at end of file diff --git a/episode19/demo6.js b/episode19/demo6.js new file mode 100644 index 0000000..ab2d52d --- /dev/null +++ b/episode19/demo6.js @@ -0,0 +1,180 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: 100, + y: 500 + }, + p1 = { + x: 400, + y: 200 + }, + p2 = { + x: 1000, + y: 400 + }, + p3 = { + x: 800, + y: 50 + }, + pA = {}, + pB = {}, + pC = {}, + pM = {}, + pN = {}, + pFinal = {}, + t = 0, + maxT = 0, + dir = 0.005, + animating = false;; + + context.scale(1.5, 1.5); + context.font = "16px Arial"; + + draw(); + document.body.addEventListener("click", function() { + animating = true; + draw(); + }); + + function draw() { + context.clearRect(0, 0, width, height); + + context.strokeStyle = "#ccc"; + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.lineTo(p2.x, p2.y); + context.lineTo(p3.x, p3.y); + context.stroke(); + + context.beginPath(); + context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p2.x, p2.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p3.x, p3.y, 4, 0, Math.PI * 2, false); + context.fill(); + + + context.strokeStyle = "red"; + context.beginPath(); + context.moveTo(p0.x, p0.y); + + for(t = 0; t <= maxT; t += Math.abs(dir)) { + pA.x = utils.lerp(t, p0.x, p1.x); + pA.y = utils.lerp(t, p0.y, p1.y); + + pB.x = utils.lerp(t, p1.x, p2.x); + pB.y = utils.lerp(t, p1.y, p2.y); + + pC.x = utils.lerp(t, p2.x, p3.x); + pC.y = utils.lerp(t, p2.y, p3.y); + + pM.x = utils.lerp(t, pA.x, pB.x); + pM.y = utils.lerp(t, pA.y, pB.y); + + pN.x = utils.lerp(t, pB.x, pC.x); + pN.y = utils.lerp(t, pB.y, pC.y); + + pFinal.x = utils.lerp(t, pM.x, pN.x); + pFinal.y = utils.lerp(t, pM.y, pN.y); + + context.lineTo(pFinal.x, pFinal.y); + } + context.stroke(); + + context.beginPath(); + context.strokeStyle = "green"; + context.moveTo(pA.x, pA.y); + context.lineTo(pB.x, pB.y); + context.lineTo(pC.x, pC.y); + context.stroke(); + + context.beginPath(); + context.strokeStyle = "blue"; + context.moveTo(pM.x, pM.y); + context.lineTo(pN.x, pN.y); + context.stroke(); + + context.fillStyle = "green"; + context.beginPath(); + context.arc(pA.x, pA.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(pB.x, pB.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(pC.x, pC.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.fillStyle = "blue"; + context.beginPath(); + context.arc(pM.x, pM.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(pN.x, pN.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.fillStyle = "red"; + context.beginPath(); + context.arc(pFinal.x, pFinal.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.fillStyle = "black"; + + + + // labelPointLeft(p0, "p0"); + // labelPointLeft(p1, "p1"); + // labelPointLeft(p2, "p2"); + // labelPoint(pA, "pA"); + // labelPoint(pB, "pB"); + labelT(); + + maxT += dir; + if(maxT >= 1) { + maxT = 1; + dir *= -1; + } + if(maxT <= 0) { + maxT = 0; + dir *= -1; + } + + if(animating) + requestAnimationFrame(draw); + } + + function labelPoint(p, name) { + context.fillStyle = "black"; + context.fillText(name, p.x + 10, p.y + 10); + context.fillText("x: " + Math.round(p.x), p.x + 10, p.y + 25); + context.fillText("y: " + Math.round(p.y), p.x + 10, p.y + 40); + } + + function labelPointLeft(p, name) { + context.fillStyle = "gray"; + context.fillText(name, p.x - 40, p.y - 40); + context.fillText("x: " + Math.round(p.x), p.x - 40, p.y - 25); + context.fillText("y: " + Math.round(p.y), p.x - 40, p.y - 10); + } + + function labelT() { + context.fillText("t = " + utils.roundToPlaces(maxT, 2), 200, 250); + } + +}; \ No newline at end of file diff --git a/episode19/index.html b/episode19/index.html new file mode 100644 index 0000000..ec278a5 --- /dev/null +++ b/episode19/index.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/episode19/main1.js b/episode19/main1.js new file mode 100644 index 0000000..7538236 --- /dev/null +++ b/episode19/main1.js @@ -0,0 +1,53 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + p1 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + p2 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + p3 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }; + + context.beginPath(); + context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p2.x, p2.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p3.x, p3.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.bezierCurveTo(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); + context.stroke(); + + var pFinal = {}; + + for(var t = 0; t <= 1; t += 0.01) { + utils.cubicBezier(p0, p1, p2, p3, t, pFinal); + context.beginPath(); + context.arc(pFinal.x, pFinal.y, 10, 0, Math.PI * 2, false); + context.stroke(); + } + +}; \ No newline at end of file diff --git a/episode19/main2.js b/episode19/main2.js new file mode 100644 index 0000000..c794624 --- /dev/null +++ b/episode19/main2.js @@ -0,0 +1,44 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + p1 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + p2 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + p3 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + maxT = 0, + pFinal = {}; + + + draw(); + + function draw() { + context.clearRect(0, 0, width, height); + context.beginPath(); + context.moveTo(p0.x, p0.y); + for(var t = 0; t <= maxT; t += 0.01) { + utils.cubicBezier(p0, p1, p2, p3, t, pFinal); + context.lineTo(pFinal.x, pFinal.y); + } + context.stroke(); + maxT += 0.01; + if(maxT > 1) { + maxT = 0; + } + + requestAnimationFrame(draw); + } +}; \ No newline at end of file diff --git a/episode19/main3.js b/episode19/main3.js new file mode 100644 index 0000000..da0e8a9 --- /dev/null +++ b/episode19/main3.js @@ -0,0 +1,49 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + p1 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + p2 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + p3 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + t = 0, + direction = 0.01, + pFinal = {}; + + + draw(); + + function draw() { + context.clearRect(0, 0, width, height); + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.bezierCurveTo(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); + context.stroke(); + + utils.cubicBezier(p0, p1, p2, p3, t, pFinal); + context.beginPath(); + context.arc(pFinal.x, pFinal.y, 10, 0, Math.PI * 2, false); + context.fill(); + + t += direction; + if(t > 1 || t < 0) { + direction = -direction; + } + + requestAnimationFrame(draw); + } +}; \ No newline at end of file diff --git a/episode19/utils.js b/episode19/utils.js new file mode 100644 index 0000000..7c659e4 --- /dev/null +++ b/episode19/utils.js @@ -0,0 +1,106 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + } + +} \ No newline at end of file From 283afed4bbe65b1978bebf7322ffd60613f5c4ff Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Mon, 24 Mar 2014 12:57:10 -0400 Subject: [PATCH 13/39] mini9 files --- mini9/highres.js | 45 ++++++++++++++++++++++++++ mini9/index.html | 21 +++++++++++++ mini9/main.js | 35 +++++++++++++++++++++ mini9/main2.js | 38 ++++++++++++++++++++++ mini9/main3.js | 14 +++++++++ mini9/utils.js | 82 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 235 insertions(+) create mode 100644 mini9/highres.js create mode 100644 mini9/index.html create mode 100644 mini9/main.js create mode 100644 mini9/main2.js create mode 100644 mini9/main3.js create mode 100644 mini9/utils.js diff --git a/mini9/highres.js b/mini9/highres.js new file mode 100644 index 0000000..746b944 --- /dev/null +++ b/mini9/highres.js @@ -0,0 +1,45 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + results = [], + running = true; + + document.body.addEventListener("click", function() { + running = !running; + }); + + for(var i = 0; i < width; i += 1) { + results[i] = 0; + } + + update(); + + function update() { + + for(var n = 0; n < 1000; n += 1) { + addResult(); + } + for(var i = 0; i < width; i += 1) { + var h = -results[i]; + context.fillRect(i, height, 1, h ); + } + if(running) { + requestAnimationFrame(update); + } + } + + function addResult() { + var iterations = 2, + total = 0; + + for(var i = 0; i < iterations; i += 1) { + total += utils.randomRange(0, width); + } + result = Math.floor(total / iterations); + + results[result] += 1; + } + +}; \ No newline at end of file diff --git a/mini9/index.html b/mini9/index.html new file mode 100644 index 0000000..ec278a5 --- /dev/null +++ b/mini9/index.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/mini9/main.js b/mini9/main.js new file mode 100644 index 0000000..51b87a1 --- /dev/null +++ b/mini9/main.js @@ -0,0 +1,35 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + results = []; + + for(var i = 0; i < 100; i += 1) { + results[i] = 0; + } + + update(); + + function update() { + addResult(); + draw(); + requestAnimationFrame(update); + } + + function addResult() { + var r0 = utils.randomRange(0, 100), + r1 = utils.randomRange(0, 100), + result = Math.floor((r0 + r1) / 2); + + results[result] += 1; + } + + function draw() { + var w = width / 100; + for(var i = 0; i < 100; i += 1) { + var h = results[i] * -10; + context.fillRect(w * i, height, w, h); + } + } +}; \ No newline at end of file diff --git a/mini9/main2.js b/mini9/main2.js new file mode 100644 index 0000000..c448558 --- /dev/null +++ b/mini9/main2.js @@ -0,0 +1,38 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + results = []; + + for(var i = 0; i < 100; i += 1) { + results[i] = 0; + } + + update(); + + function update() { + addResult(); + draw(); + requestAnimationFrame(update); + } + + function addResult() { + var iterations = 3, + total = 0; + for(var i = 0; i < iterations; i += 1) { + total += utils.randomRange(0, 100); + } + result = Math.floor(total / iterations); + results[result] += 1; + } + + function draw() { + var w = width / 100; + for(var i = 0; i < 100; i += 1) { + var h = results[i] * -10; + context.fillRect(w * i, height, w, h); + } + } + +}; \ No newline at end of file diff --git a/mini9/main3.js b/mini9/main3.js new file mode 100644 index 0000000..e220e64 --- /dev/null +++ b/mini9/main3.js @@ -0,0 +1,14 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + for(var i = 0; i < 100000; i += 1) { + var x = utils.randomDist(0, width, 5), + y = utils.randomDist(0, height, 5); + + context.fillRect(x, y, 1, 1); + } + +}; \ No newline at end of file diff --git a/mini9/utils.js b/mini9/utils.js new file mode 100644 index 0000000..4d85a81 --- /dev/null +++ b/mini9/utils.js @@ -0,0 +1,82 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + randomDist: function(min, max, iterations) { + var total = 0; + + for(var i = 0; i < iterations; i += 1) { + total += utils.randomRange(min, max); + } + return total / iterations; + } + +} \ No newline at end of file From f671d4b49f862925b000ddca08e16c6ba903b465 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Mon, 31 Mar 2014 23:18:21 -0400 Subject: [PATCH 14/39] episode 20 files --- episode20/index.html | 21 ++++++++ episode20/main1.js | 46 ++++++++++++++++ episode20/main2.js | 36 +++++++++++++ episode20/main3.js | 33 ++++++++++++ episode20/utils.js | 123 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 259 insertions(+) create mode 100644 episode20/index.html create mode 100644 episode20/main1.js create mode 100644 episode20/main2.js create mode 100644 episode20/main3.js create mode 100644 episode20/utils.js diff --git a/episode20/index.html b/episode20/index.html new file mode 100644 index 0000000..ec278a5 --- /dev/null +++ b/episode20/index.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/episode20/main1.js b/episode20/main1.js new file mode 100644 index 0000000..044e788 --- /dev/null +++ b/episode20/main1.js @@ -0,0 +1,46 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: Math.random() * width, + y: Math.random() * height + }, + p1 = { + x: Math.random() * width, + y: Math.random() * height + }, + p2 = { + x: Math.random() * width, + y: Math.random() * height + }, + cp = {}; + + cp.x = p1.x * 2 - (p0.x + p2.x) / 2; + cp.y = p1.y * 2 - (p0.y + p2.y) / 2; + + drawPoint(p0); + drawPoint(p1); + drawPoint(p2); + drawPoint(cp); + + context.strokeStyle = "lightgray"; + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(cp.x, cp.y); + context.lineTo(p2.x, p2.y); + context.stroke(); + + context.strokeStyle = "black"; + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.quadraticCurveTo(cp.x, cp.y, p2.x, p2.y); + context.stroke(); + + function drawPoint(p) { + context.beginPath(); + context.arc(p.x, p.y, 3, 0, Math.PI * 2, false); + context.fill(); + } +}; \ No newline at end of file diff --git a/episode20/main2.js b/episode20/main2.js new file mode 100644 index 0000000..9d2c7bc --- /dev/null +++ b/episode20/main2.js @@ -0,0 +1,36 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + points = [], + numPoints = 10; + + for(var i = 0; i < numPoints; i += 1) { + var p = { + x: Math.random() * width, + y: Math.random() * height + }; + + context.beginPath(); + context.arc(p.x, p.y, 3, 0, Math.PI * 2, false); + context.fill(); + + points.push(p); + } + + context.strokeStyle = "lightgray"; + context.beginPath(); + context.moveTo(points[0].x, points[0].y); + for(var i = 1; i < numPoints; i += 1) { + context.lineTo(points[i].x, points[i].y); + } + context.stroke(); + + context.strokeStyle = "black"; + + context.beginPath(); + utils.multicurve(points, context); + context.stroke(); + +}; \ No newline at end of file diff --git a/episode20/main3.js b/episode20/main3.js new file mode 100644 index 0000000..68347c9 --- /dev/null +++ b/episode20/main3.js @@ -0,0 +1,33 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: Math.random() * width, + y: Math.random() * height + }, + p1 = { + x: Math.random() * width, + y: Math.random() * height + }, + p2 = { + x: Math.random() * width, + y: Math.random() * height + }, + p3 = { + x: Math.random() * width, + y: Math.random() * height + }; + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.bezierCurveTo(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); + context.stroke(); + + context.strokeStyle = "red"; + context.beginPath(); + utils.multicurve([p0, p1, p2, p3], context); + context.stroke(); + +}; \ No newline at end of file diff --git a/episode20/utils.js b/episode20/utils.js new file mode 100644 index 0000000..3c0f824 --- /dev/null +++ b/episode20/utils.js @@ -0,0 +1,123 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + }, + + multicurve: function(points, context) { + var p0, p1, midx, midy; + + context.moveTo(points[0].x, points[0].y); + + for(var i = 1; i < points.length - 2; i += 1) { + p0 = points[i]; + p1 = points[i + 1]; + midx = (p0.x + p1.x) / 2; + midy = (p0.y + p1.y) / 2; + context.quadraticCurveTo(p0.x, p0.y, midx, midy); + } + p0 = points[points.length - 2]; + p1 = points[points.length - 1]; + context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); + } + +} \ No newline at end of file From b8c170f9135198b63c5cae7ed3b30b1cd7e2cb1d Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Mon, 7 Apr 2014 09:28:36 -0400 Subject: [PATCH 15/39] episode 21 files --- episode21/index.html | 27 +++++++++ episode21/main.js | 46 ++++++++++++++ episode21/particle.js | 138 ++++++++++++++++++++++++++++++++++++++++++ episode21/utils.js | 123 +++++++++++++++++++++++++++++++++++++ 4 files changed, 334 insertions(+) create mode 100644 episode21/index.html create mode 100644 episode21/main.js create mode 100644 episode21/particle.js create mode 100644 episode21/utils.js diff --git a/episode21/index.html b/episode21/index.html new file mode 100644 index 0000000..5a12f32 --- /dev/null +++ b/episode21/index.html @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/episode21/main.js b/episode21/main.js new file mode 100644 index 0000000..aac23c0 --- /dev/null +++ b/episode21/main.js @@ -0,0 +1,46 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + targetCanvas = document.getElementById("target"), + targetContext = targetCanvas.getContext("2d"), + width = canvas.width = targetCanvas.width = window.innerWidth, + height = canvas.height = targetCanvas.height = window.innerHeight, + p = particle.create(0, height / 2, 10, 0); + + targetContext.beginPath(); + targetContext.arc(width / 2, height / 2, 200, 0, Math.PI * 2, false); + targetContext.fill(); + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + p.update(); + context.beginPath(); + context.arc(p.x, p.y, 4, 0, Math.PI * 2, false); + context.fill(); + + var imageData = targetContext.getImageData(p.x, p.y, 1, 1); + if(imageData.data[3] > 0) { + targetContext.globalCompositeOperation = "destination-out"; + targetContext.beginPath(); + targetContext.arc(p.x, p.y, 20, 0, Math.PI * 2, false); + targetContext.fill(); + + resetParticle(); + } + else if(p.x > width) { + resetParticle(); + } + requestAnimationFrame(update); + } + + function resetParticle() { + p.x = 0; + p.y = height / 2; + p.setHeading(utils.randomRange(-0.1, 0.1)); + } + + +}; \ No newline at end of file diff --git a/episode21/particle.js b/episode21/particle.js new file mode 100644 index 0000000..b6ef621 --- /dev/null +++ b/episode21/particle.js @@ -0,0 +1,138 @@ +var particle = { + x: 0, + y: 0, + vx: 0, + vy: 0, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + springs: null, + gravitations: null, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.x = x; + obj.y = y; + obj.vx = Math.cos(direction) * speed; + obj.vy = Math.sin(direction) * speed; + obj.gravity = grav || 0; + obj.springs = []; + obj.gravitations = []; + return obj; + }, + + addGravitation: function(p) { + this.removeGravitation(p); + this.gravitations.push(p); + }, + + removeGravitation: function(p) { + for(var i = 0; i < this.gravitations.length; i += 1) { + if(p === this.gravitations[i]) { + this.gravitations.splice(i, 1); + return; + } + } + }, + + addSpring: function(point, k, length) { + this.removeSpring(point); + this.springs.push({ + point: point, + k: k, + length: length || 0 + }); + }, + + removeSpring: function(point) { + for(var i = 0; i < this.springs.length; i += 1) { + if(point === this.springs[i].point) { + this.springs.splice(i, 1); + return; + } + } + }, + + getSpeed: function() { + return Math.sqrt(this.vx * this.vx + this.vy * this.vy); + }, + + setSpeed: function(speed) { + var heading = this.getHeading(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + getHeading: function() { + return Math.atan2(this.vy, this.vx); + }, + + setHeading: function(heading) { + var speed = this.getSpeed(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + accelerate: function(ax, ay) { + this.vx += ax; + this.vy += ay; + }, + + update: function() { + this.handleSprings(); + this.handleGravitations(); + this.vx *= this.friction; + this.vy *= this.friction; + this.vy += this.gravity; + this.x += this.vx; + this.y += this.vy; + }, + + handleGravitations: function() { + for(var i = 0; i < this.gravitations.length; i += 1) { + this.gravitateTo(this.gravitations[i]); + } + }, + + handleSprings: function() { + for(var i = 0; i < this.springs.length; i += 1) { + var spring = this.springs[i]; + this.springTo(spring.point, spring.k, spring.length); + } + }, + + angleTo: function(p2) { + return Math.atan2(p2.y - this.y, p2.x - this.x); + }, + + distanceTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y; + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y, + distSQ = dx * dx + dy * dy, + dist = Math.sqrt(distSQ), + force = p2.mass / distSQ, + ax = dx / dist * force, + ay = dy / dist * force; + + this.vx += ax; + this.vy += ay; + }, + + springTo: function(point, k, length) { + var dx = point.x - this.x, + dy = point.y - this.y, + distance = Math.sqrt(dx * dx + dy * dy), + springForce = (distance - length || 0) * k; + this.vx += dx / distance * springForce, + this.vy += dy / distance * springForce; + } +}; \ No newline at end of file diff --git a/episode21/utils.js b/episode21/utils.js new file mode 100644 index 0000000..3c0f824 --- /dev/null +++ b/episode21/utils.js @@ -0,0 +1,123 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + }, + + multicurve: function(points, context) { + var p0, p1, midx, midy; + + context.moveTo(points[0].x, points[0].y); + + for(var i = 1; i < points.length - 2; i += 1) { + p0 = points[i]; + p1 = points[i + 1]; + midx = (p0.x + p1.x) / 2; + midy = (p0.y + p1.y) / 2; + context.quadraticCurveTo(p0.x, p0.y, midx, midy); + } + p0 = points[points.length - 2]; + p1 = points[points.length - 1]; + context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); + } + +} \ No newline at end of file From 6143569f85830dcaf1428a598b2441e40c5d7977 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Mon, 14 Apr 2014 17:00:57 -0400 Subject: [PATCH 16/39] episode 22 files --- episode22/index.html | 23 +++++++ episode22/main.js | 22 +++++++ episode22/main2.js | 60 +++++++++++++++++ episode22/particle.js | 138 ++++++++++++++++++++++++++++++++++++++++ episode22/postcard0.jpg | Bin 0 -> 51476 bytes episode22/postcard1.jpg | Bin 0 -> 60833 bytes episode22/postcard2.jpg | Bin 0 -> 80327 bytes episode22/postcard3.jpg | Bin 0 -> 63487 bytes episode22/postcard4.jpg | Bin 0 -> 65510 bytes episode22/postcard5.jpg | Bin 0 -> 46842 bytes episode22/postcard6.jpg | Bin 0 -> 75915 bytes episode22/postcards.js | 48 ++++++++++++++ episode22/stars.js | 20 ++++++ episode22/stars.png | Bin 0 -> 30731 bytes episode22/utils.js | 123 +++++++++++++++++++++++++++++++++++ 15 files changed, 434 insertions(+) create mode 100644 episode22/index.html create mode 100644 episode22/main.js create mode 100644 episode22/main2.js create mode 100644 episode22/particle.js create mode 100644 episode22/postcard0.jpg create mode 100644 episode22/postcard1.jpg create mode 100644 episode22/postcard2.jpg create mode 100644 episode22/postcard3.jpg create mode 100644 episode22/postcard4.jpg create mode 100644 episode22/postcard5.jpg create mode 100644 episode22/postcard6.jpg create mode 100644 episode22/postcards.js create mode 100644 episode22/stars.js create mode 100644 episode22/stars.png create mode 100644 episode22/utils.js diff --git a/episode22/index.html b/episode22/index.html new file mode 100644 index 0000000..3723d24 --- /dev/null +++ b/episode22/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/episode22/main.js b/episode22/main.js new file mode 100644 index 0000000..b53403f --- /dev/null +++ b/episode22/main.js @@ -0,0 +1,22 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + fl = 300, + shapePos = { + x: 500, + y: 300, + z: 10000 + }; + + context.translate(width / 2, height / 2); + + var perspective = fl / (fl + shapePos.z); + context.translate(shapePos.x * perspective, shapePos.y * perspective); + context.scale(perspective, perspective); + context.fillRect(-100, -100, 200, 200); + + + +}; \ No newline at end of file diff --git a/episode22/main2.js b/episode22/main2.js new file mode 100644 index 0000000..61c9d28 --- /dev/null +++ b/episode22/main2.js @@ -0,0 +1,60 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + fl = 300, + shapes = [], + numShapes = 100; + + for(var i = 0; i < numShapes; i += 1) { + shapes[i] = { + x: utils.randomRange(-1000, 1000), + y: utils.randomRange(-1000, 1000), + z: utils.randomRange(0, 10000), + char: String.fromCharCode(utils.randomRange(65, 91)) + }; + } + + context.translate(width / 2, height / 2); + context.font = "200px Arial"; + + update(); + + function update() { + context.clearRect(-width / 2, -height / 2, width, height); + for(var i = 0; i < numShapes; i += 1) { + var shape = shapes[i], + perspective = fl / (fl + shape.z); + + context.save(); + context.translate(shape.x * perspective, shape.y * perspective); + context.scale(perspective, perspective); + // square: + // context.fillRect(-100, -100, 200, 200); + + // circle: + // context.beginPath(); + // context.arc(0, 0, 100, 0, Math.PI * 2, false); + // context.fill(); + + // letter: + context.fillText(shape.char, -100, -100) + + context.restore(); + + // move away: + // shape.z += 5; + // if(shape.z > 10000) { + // shape.z = 0; + // } + + // move toward: + shape.z -= 5; + if(shape.z < 0) { + shape.z = 10000; + } + } + requestAnimationFrame(update); + } +}; \ No newline at end of file diff --git a/episode22/particle.js b/episode22/particle.js new file mode 100644 index 0000000..b6ef621 --- /dev/null +++ b/episode22/particle.js @@ -0,0 +1,138 @@ +var particle = { + x: 0, + y: 0, + vx: 0, + vy: 0, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + springs: null, + gravitations: null, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.x = x; + obj.y = y; + obj.vx = Math.cos(direction) * speed; + obj.vy = Math.sin(direction) * speed; + obj.gravity = grav || 0; + obj.springs = []; + obj.gravitations = []; + return obj; + }, + + addGravitation: function(p) { + this.removeGravitation(p); + this.gravitations.push(p); + }, + + removeGravitation: function(p) { + for(var i = 0; i < this.gravitations.length; i += 1) { + if(p === this.gravitations[i]) { + this.gravitations.splice(i, 1); + return; + } + } + }, + + addSpring: function(point, k, length) { + this.removeSpring(point); + this.springs.push({ + point: point, + k: k, + length: length || 0 + }); + }, + + removeSpring: function(point) { + for(var i = 0; i < this.springs.length; i += 1) { + if(point === this.springs[i].point) { + this.springs.splice(i, 1); + return; + } + } + }, + + getSpeed: function() { + return Math.sqrt(this.vx * this.vx + this.vy * this.vy); + }, + + setSpeed: function(speed) { + var heading = this.getHeading(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + getHeading: function() { + return Math.atan2(this.vy, this.vx); + }, + + setHeading: function(heading) { + var speed = this.getSpeed(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + accelerate: function(ax, ay) { + this.vx += ax; + this.vy += ay; + }, + + update: function() { + this.handleSprings(); + this.handleGravitations(); + this.vx *= this.friction; + this.vy *= this.friction; + this.vy += this.gravity; + this.x += this.vx; + this.y += this.vy; + }, + + handleGravitations: function() { + for(var i = 0; i < this.gravitations.length; i += 1) { + this.gravitateTo(this.gravitations[i]); + } + }, + + handleSprings: function() { + for(var i = 0; i < this.springs.length; i += 1) { + var spring = this.springs[i]; + this.springTo(spring.point, spring.k, spring.length); + } + }, + + angleTo: function(p2) { + return Math.atan2(p2.y - this.y, p2.x - this.x); + }, + + distanceTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y; + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y, + distSQ = dx * dx + dy * dy, + dist = Math.sqrt(distSQ), + force = p2.mass / distSQ, + ax = dx / dist * force, + ay = dy / dist * force; + + this.vx += ax; + this.vy += ay; + }, + + springTo: function(point, k, length) { + var dx = point.x - this.x, + dy = point.y - this.y, + distance = Math.sqrt(dx * dx + dy * dy), + springForce = (distance - length || 0) * k; + this.vx += dx / distance * springForce, + this.vy += dy / distance * springForce; + } +}; \ No newline at end of file diff --git a/episode22/postcard0.jpg b/episode22/postcard0.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a54b4d5396d1b260071b6c4997308ddeb957c8c3 GIT binary patch literal 51476 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 }`^Wn74Pea}1faUWvhgL_LI9El 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�lkq{t#37q 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 z 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

MU-Ym>$9&~I`V{mu3>G4NV=z^kxsFV+ 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 literal 0 HcmV?d00001 diff --git a/episode22/postcard3.jpg b/episode22/postcard3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f2877d39c13a8e340c0d56c21ecd82cd1f10e5f3 GIT binary patch literal 63487 zcmeFacUTn7voJd3j1on%1X0O3OHLv|a#UeiU|p64mW;510R_pyfQU%WISVLJKyr>t z5+sX6iFd&8`u@)O&hy=SpYQ&2ZJwE_uCA`GuIa9sv1-fXq2nor0u@h~EdXd}Tmc9H z03ZVZEF1s}giP>3@Fz@&3jo+4j055`!2|y%9vg(ov9N(l;58pSD1YKl`qTV`Px{bf z;hpjv0%3-q@FWOd`h$-k$cG8UeE|<45T*vNcpxKKAns{jMi9;i55m(wO(Y!2st&cX z;bGOWvUlTQRk!l6g27l7-0a*?uB?KhJgkC};=;ha17hGT7x4S4V1u-Vvg+C+U6Ckz zq!X)>66+;nn4=BS19ce?5)c%T5)hFR6k!#RkP;G>5)lQ306;~A69AwJ00ALE0jxJa z^mBX+>g3H2*}_4&aDKu^CvyLUpMrSSWNhF9h`R&ACq>LkM8eA23Mwc86%dgSvK5jL zv9X5Q2nkwCN=Qi9T7g`_`CQbIyPB0^FkB2o$xViF3PGo++vXy~Y@XsD>@C`eDs&&!X>f1a_(NJz-Y$bqGO~4l6q{PwG%&X)4|?5Sg*mLJTmmAM^l2a{k#$b|69EV= ziq`djLL{BDQ85&Ag--t#;eRaw*FPd0j{u}Nr(;q8azKq=muU;BeaLk(w7c&0o$$~V zFV0yHE}aU}C(AOi&z)LDCU?0;pz5MD#ZA|IuU=88%y9Uo*jx7?HNenc?`Fic-a50X z6!SdM>Alr*Bu{U>`l#IC4Vv@n19~DJ>gCJma0m1LZ?D$6mCg^jpgRmPen$E)n`H;i zNq^73?Rg9sQa<%gaDtWw4O8C4UqOrJyXTx4DzCy{y1DSV9{qX zg3LKP9LJmF1mEq~#uoAI^>(kD7KHMnAj1}C*}prC6)|nqb6p(H2+fSw#y~^{=d=*)4PL4|~xsXfCXYESdCoR2eOeCpiWr*Y<9G&5S9v*dgKbc}XoFL?dFxH#){%H2X)R!)wJGX$qv8mvW=scu~&s< z)dXK?`{_eAwR}E!e9J6Jg2a_=m_xVHweJ>+=}ggjPBvr7!{%-sca8YEhOT{$Cp>t3 zGej-$#aG^A;A5`OcBk&)_A&4rv#KrCsmrxcbkLMl=jW&qcJIJ)J#@n3O!P6}5}sK5 zj$k66VZi&|!5sQI^)Z03JK93ep-Y(gMRdPC0HOQQ8IdjSD-rT(&wKYu(IQ;yf54GK^_9>RM z!wrGi{N1*tW5B0w;V`$xJ!0be{j^7MQNwY;I-5`O+CLXGcjI+9ehx|ddIZl#pq0>NJ(;z8pEDmF1hXtHT3QW!NP;|bl0?>s`D%+d|b9nq5~4J%9|VCCr0k@S)aFr34SUDI467{lmY9|HpQ zw!3krU-HAcB^w`5d^!s0*hU;;Zs633mQ3%9s=_bl4>SoFCdZy7>K#4kHC;jOF@5Z> z41UF+sktmwkncvZI%at=f!T+dB`r?5A!*;0d}7G1%wM8!CwVl&?YP8HW_t{LP54r) zxrb}^h?ay-Kxq{Ik_k~N?(?C~n}J!(dbAcb(Rpy@fDI2~~r?K0?&5-Kn+v&?;0d3+xYN`xVj zC6J*w?uE_bc6+Krjph)u=^mVmx23go=9S_WO%7`{kzcxSGplNkyPFcoug*^UZ83dN zKYN$G-Mow`T>H#kt8IWf&X`6QnNFMIXX|X9DgY&z=R*{*UGU+pjDwH4x%)9-$zY}+ zO`?onJC;n)tWxk~3nI11665oTRv3THXkc;f$SuTieW7n)zuHIkv19$0=<)%nM)&Ge z=8-!-&D;E8ssjjcCs^AQDN2Xe$dtl>J9!lp$3XHN!X{)?gOLD!Ra3hrJ|w7hZIKsl zYJbSYIZSg-bx`t5d^ zy?c*3OA@?he58t&-u{q48QG%%qp9>8dlVE3}mIF zloE;vExy&`e;{M?ooE|t8frQQ8v6B*fhmK`Hzjq01B1m(iD3=~3y3fD-yqFX;>;`f(6RP?@%;H`S8KKNn@UMuwkC__c|8^04gYJ*?>zOsC{c4UAkq^`86#}TvdaYUinvqd+uGV)zI6Xsuj444nCEg2sJ z@k3A4mqnmG*_l;jw6ZBr4@Ip%^4POzOssvD_GS4p5VC0uA6;ZI+LhLXhCDhH0)<1s z#ichLwyJe@p)W#Io-RHgAPXt!*j&NN?;6jeMP!Xv2Gh-64`SMm<8H_v*c%zB%zQ0@ zySBM>WH;ch8E-CLw27G#%-EOWFzKxn`vxD@`czTZTk|NM8#S~GzlToWH{FxU+M>sF zt?r@Q!DXX+AKo;c=N!A(Yg@EJgARb`AvUX1M_w(On>?#tO|mE7De6fb4=o);Ur0zf z2Hre!5ftLx47IFCX8E#$7u|dyZJ+0J=NRzEETRYXwO+^ZQD-@3JZx$%7%)xudChoh zJ?pGETyEwp!6;85cSipr7K2$A+5>7NT8ggod)c36#6&Gw&zw1O>*9a`ssG0R=1E~IFd)`WZshaymE4#Rs?rT(!Q+fF`8HVU zF;>^5CjDwjP6J{%6M9f2XCg?~<=fPD zoT;Ts3^{Yr`9U+RLv63Q`-mHo>ngB3r{CjLVEV+wanKlgeTzf1!)>*6XVi9Z6)vZ8 zSVb#l#MIQ&i!eEpjqrr0%I}nfQWwsf!_mSJ^h`uyWmb`3hwQ`h{*aEG60)c8VE4T^ zv<5r@GWNz-)QjCo?5d3AsH zf_KOmrU!lh7$8`<+}~rdm{s_dY0>wbY^M)~T`PNhp`^Ceqkv{NB&F=;*CtadtoJ@; z_r!!s*M|4BYHPt)p7f9+V)%qu@j$CXN#%VQc4CF5=)v* zq{Wh{IS)|YG5>;jP%wW5GpLt`bMAai?sZCtlT^Ue)b|cmc3+GoV#DJ z+?2)RK)pB(-Nr3*OER(9;(HFL>qZ}s+?T_2x)F|h%ps=CX*qUjh5gUurE}dnX=jGv zQ zZbtiu&(PwBXq9vLW6SQ0v3iTnW<3LjmLc%q>3ac{!)o!Fqjz4rE3VI_O7Q!yQGwc1s(I%E7dN(W>6U+;*> zoO^V3=t7!hdv5BUG+J)_pofMGzI5gz)MM=1+KtZJ&O1I2aW-C#fP0r^m6iO(Q#yFY zuxLDCX?5oa=h1j4>FBMk!!NTJl0T7Oy& z!0{V&Yxv+9rkW=v8sityest>#db(>Rv1G*Tz0&yicU8CAk@J}yZmcg#LVyU)dKhm= zJAB@5{&F%mYPSLy@7gOJPH=NXwI>dgeNiX3eI*VlEx^q2s`@%~Kr9^K{IvL`+gIHy z-q5aW#xFvA%KQ-5cfhZgMINKVLbVKE*Fl^Ki$N?IKNQ-FVYwt={E-^x_F4R)_^#%X zQFJGG64Tzpo8b!FIO=hmWmS#P3Y%WKv?wR2lx%gE`*Xn&r_siS1IL$*@QOQnOOfxS(# zw?kIM$r1)o{3ZKxOF3D4K@-dpTmu!4DqjJqoUzpftEj9zh;v3kmAi4-K-mG;+s2zO z#vR@XI&&i9s~vLI^R zBjX`(aDoBb-odJs1ta4*EcUR2`KX0^Uc=?cGBjwh#5#ACcV-85$$g%L!GUG`xGVO1 zazlD_=^i``{txvPO8oa#hf6hN9JkA>ON2-Fq+T2Y7JKNVn?=jK&GmWrOP=1|4!fA| zLnV~`>K;$kmcxy)j_U1&P0+03=p5n4yl^W>W1&VkAW&gFaxH$Cx0qexV_>P~tvpug zBG(tWd5!yrGLV`cA(y8sEE-S0!TlcQ9Ru&>zSc!uD%oZz)X8v`Q}n=+t3gY)EHsVo zsqMf1LZ2k{>REhAA)TbN03nOI_yU_2`DZrq+4*t!H(u183!y2wfzppc2hI6&OIJ~H zYHOIIuXCWffJ`J0^=uK1Z>gTZbHRj+SV|lS@ak?qKO19>3^uELJ5!EI-*=)5Te_+PScH6#n zM?^%)d<}KjZdZH2vT-L&FE?oQ{brsOdG)+A>#`M1&HON&@fdhJx2)K{vYU?Oy?r@7 zeXl7m*~Tx@Gh(4>Fu`L>Zo0QLvWY3hf5i){F_%x8sbtLtd4z)d1zePXp>uAk7~!P* zurB45d93xNYzJk+P;kj}*fWc=lTkvJh1%l@JDm^;eA$8UTgQEHzbe6)p)tPro4ny- zCOahbZiifXH%DZR_WTx)0Zs7Dej_2#u*k2{EwJY@e6hjFHGjrvKsF?#)-I=W%UuxD zF}5;M1HS)%BCEg6zZnnrXRTNVLXQrk3o<`cUN0x8cq8w>g6tV>E^{1|G>+Bpi+m?f z_S{I;sn>lJQ-$K;j9q!|zSvk*J?cBUv_(DE_PS@viaC+5@V$nYKTS!_P*V}SRvMA8 zJsszeAC)?=fG^`a0wjOiv1qPrmhM40P=~XbUCit8VH_w~#T0D@QB}uGmtuup<=n1F z+z-YYv4Fn8+Pv?33$^3RqHkSd#1MRc-03Wd$sFyfJ$o<89Mznr?_2x4b8nH|`jdxc z_+0pQxlpRK6Dtf_+MKpo`?A@tFkx>xcO(lUf7qR5UayP@)AlcUdNd-22ir~ytk`FG zAu@vrSd9z2?Kb#6w^SW(#r?3eIII`k;8o(_JHo-|VD6+^uGD#`>%m+VB(-ZGeA_!_ zpQj*BC#4Emu#a{&X{}6!jL=y=wHQ1%eETunFFtMwgIYvk45hdIf(MR}L;fNC3?&_% zpCCizt@O-%a7MAp@z>AN2gKnS807A)U9~hK^#FLiN|PW!UR%)bZkMipo0VLHB7JRj zw07^4BK#v?LCun!NI6CG{a}mns#@nK6Fnw9pIO_}&UsgAi|CiZ2%vz%c< zG7Kd};5SOfVPa@J_>WW}`2+ib(xu2EWbJ5~Z@RDXozPGI&`^G>rU@M8*5UjzWLH5a zbCKmHT4iC>F1ho7m`19(e%Q1Rn{Y>G9x>8%6j9rD41AzEd}AUTid(!&<{B4Wl4%V>x8)Y5PfBTQ>Nv54`GHFSEa zuhW@yt9u%*SW^4G8r#)^;Z41lJH!GW*DNu*8G@7D1wc zKJNdJyit(!uR@XV1+Y1d8eC$*ZG1aO5)LjqFp2)ViS@uKDG=YEtz;U=ho0v4V%I zj>BxVCOrd3VWaT)gIfK~gh~DGZOFo5RF^}7g97jT7jdltU%BLCU>}7s+i;C~gt_%r zdo4r2=Mx=z9=YdynCFgJOm$4tlCe7q<8F&o(8-`pfWO+SR|q~|94ViWyss%%-RV&U zm*u}!I|qKaml#>y9U6Hl76^WCNyl3WkI*$0ydFRxH{k7&%7+x&hb+3Tz|3vVnrUE9 z|9iVNlZ`wN0;0hSgMd))n3^lQ&DELZgNd!`58 ziIp+4*uy`{m@fv8YhhabFrRMPL|&lurCDu;-!~gch)7GbrR`di?U%$T9dc#4HxjQD zp;Qdob-K!Fi>xSChs_Hu7v#R5K_Ad>^hJmsP1 zBEs1bawd7ipKE7m&9LLBGqrIp<6_ublH=jy6}HKL+*iVU0)T{~h8FILcM1Tc8L`X& z90pD`#uFzG05D>E0$l&QuCh};oTq%ww&)d5VcC&MQ0@Ap&gJ3JoVH1wwtWWAXTjsd zUjzUoPA)Je>`+?2D@rboO8-rMbW{A^}oaGp&VRK@w%Q4@_N6?iQS

Hxp3E!g4!o=-f*C!Ky^5?{RhjS)J< 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 literal 0 HcmV?d00001 diff --git a/episode22/postcard4.jpg b/episode22/postcard4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8f27343956e5c17762f997cfc389bc9ea15a4a7f GIT binary patch literal 65510 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 literal 0 HcmV?d00001 diff --git a/episode22/postcard5.jpg b/episode22/postcard5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..00b32aa623762830563b0609a2a854cca0c2bcae GIT binary patch literal 46842 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%0D$@Dh^yaR_;XG1NDdQe0F$DddA-~tig zLHLC|^CnQqOa#Ziz$T7b(Y3?~^S_N=$U}xdE$!_^+PCyh6DUN5n^T{hsBF5kgLD5n zs&EizjVrm5}RVf(+ z6YG_fGD45aA z>j38%$5uB6eRlA`I--`%azYu`!xE0$Z`OLyZHJNF<)uU?UQ4H2A z^%NT3t&${{+YY1S%WZ`xm8y=+*}?UsY(G7b${(Cxpuaj+EEkUosG7_^(rj-&Seg6+#{}70ehoIdlE=rYsj4KDFQw|?PSRZW z&Rr|C@pMm_Us&{&t9I?dR}K{RI@`})u=_{^bcjHQqCjWS=0}Xq&Cib`1_CVa+%fW8 zSLhevVl1eBp3CHlTSF3HFm=s#f;_KhQ1O^ROjKi#pO1|F{n(B|>F)@ol8SoEQ>AnA zL?Gg5MTLOdde~Gy5qLrba)nnl5*~)}DRZ6g>5p6ArzW$iR1v?B>VYnTWe-)iJR}0D zu31$c6JH!)i7n@&-(b0q=B9tlzxIK=8e_Lsu*tC#wjJJ11Zw+IqGEDFk@-bj9mYL2 z?`D|JJX95JwWwK_jVNfwRww4HW)lH@T(%4gG(vw4hqqVEauoBFb6@f4qB_mRX9DSp zke^pp&Im=jiLN;j;`4fr4)lb@iY;rt+qvIvGZ`j&yw#tBz5n5C<;sazpE)XfWU#%T zf1ze=ul;jecrRz8rp=6ffyal!0m=6tg9qC@MC7jyC53W7wl8Uctrg+$VfUT~Sj_G> z{*be&5u;(DG<1&Pz|(l;(hE0xRXZ`$5k;c++$k78PvKnYpne{M$NOLlW$!@lk?oyS+@WQ)}A11$<^U01WeO#PQST% z+TY$xDl7Lb#P)IFm@Nv@(9E9|dUV~QX9%B=buJZ0FzM*=u+fE=SiJW_lw4c38bM=l z3#%A)=zIx%;>dmD9+{Xt4-W<&gY}ZtF5cGm;QiaZ7$Try7-Me4c<1yLZ2IZa{)8up z!pJWW)2F?Ix^W&9Jvka-TLd=QOsSZMxdGVtWxsf+Sr6~$JB@Gc zN)0U=2@F0;Uc|CB*mw%;YPRg?;q`&m;DylCjORP`Hj>$0N4Ip1gTE)b)IqlTMl~O; zkYo>5Pa*<_Mc{k>9S178!}gwc!Rx}0)<)II=OU>}@(#>ZEK00nt@}%o6wyRLw)m*z zV^p}lzfr$vQ&paPq@pL%w_-HNLUm-(&whGjj=;2`3uBU!7II{Ukk<$KM?S-!{~FJ! zrE01QSZTVZ#8nNdu1M8ohW9t zQYf?J%|In^L}JU@z{6&IV7(};71_MjH!}z7#0ko`WPmFPi-Hq@r(yRNj;IMPp@WvV zDmF&@wvwahhRhh^weMU5d&tY);Ly;@ojYq`4{fvMH|9N(?_z?TFHcDHDD<20%#~on zS6p9ZIaxHZ^49X;dg!+80-{G!D|^;MnVbU34&-u79P^>OmYTRPI3qtaxiv}a7b|KXUsk@fe3CJ#6mx3(I?MU$m0idSqu#X999eCmNDK3y(b!sJotH zPwdQ^f!}5jaLdn6u4k(>4Y;|gn{<9819xmCEOojIS-4fW_`bRci#lb8eX{PhR<767 zz1@@vHqgL>lm!t$>_N>36_ZCNCY+vkM}4$^pWf8u;1&-prtXYB;6X6QmDu;V^KkRn z$uIg`UYKx!@@yxMxL>F}-l_F%p>!ul;6&8idZovayiT#2pp>FkfsYp-eII_*%%iBk zjp8VHkJz;S>^tbsn0!t_(ZWDNr7m*>T^HH=)vZoV0p`V4#+Q%X7xOqBzZ2KA5L}x1C4$$9`ZKpTO-p<|?1HB^RjP@$KpyU%4S9zS3PBal% z`|9CCu4i%1Sf)%&QiE!)tSNjY`=N`UH$!)0`yy&$5mN=Ru zr=nRJ$)6cka;+>iF|zlLq%`xIn8!yswVT--%;%mYQy@?xHSzN1WfJp_UhSm|2k!U9 z8js9u3Cs=VXl8y<&vnIeyR&k2bW$2G27E6IUI%M%`tzN8lWHCB;%sWI&i7JADyX-V z)~+pLw@a8mu{pnI+s0gqgM>XWwK?oD2kGi9F1|_chKF_)4Bx@%m$~BcS*68Pa`*Tz zFhWa0qPMJiD%T0sxgXo|G7nxU!CJ3VGFyE!DQP@U1e$}_M^-{dzJ-A^v{iF`@Wtmn zv@aR4+9;o!IoD&`tCL>`ylnl}`rdUqydCe(y%j7)hrN3r?u+z^_FL%V4pk|8hl?ZIQ_~njyzc#2%QT6c zHH9f)^1_UVftSFEs)pf=oz%<)B4AKlojW{>Uq6lM));&>vo4rs-K+5=gNHg;SbU1ti_eE$mNR%?p;oxUi2?^=qZm)z^Q(owskIf@z&l{&5*;^ zwqQG9uISTpsLAZ>l&3zA4RPb8JppX@>h3x)6;{RMVlU`@#Hb!fNyx$#5svUxa8#s~ z@!z(Yz?~noBB;+l9^8_d9}4xKUkw#lEr7wXQ3kM`50w5E04(%r4E#0hXay0#7P)2- z0pznwZwE!(t*;O;csfxHJ4OGHQ)-N4%KFbAvnFU7P5OEmtKO+n>@4aVA_Ct=#@M2^4qs9|T>M56 zzbZQ+Y|Fnmi3x^j)&`|MDwV#Wu1{I%E!}TCr3#xJIxhi)C1#>M`fV{STfA$BWG6oe z*u0Aqty0r`@K{I)B_nLIbavFiGE6Kx_A$(@Ah*fSDZ=8LQYg~zbJ@sdZehaC{b@mG z#@K7H0$kJnfDX~w!lOQ~vTc+2&S|#VVsK`sG<98n(Ujq`a8G^a#5Chr9(7ky3)Z$E1G=<*Svym=y!nCEMESHNO%Am|)AV&%2jYvmQ5 zi=E5S!AH?+Y=pcQR}FBrE;?VGX*%Eb24K9?7fs6-ykhV)+idd=ZsZ@-8&hjuHXg#c z==4l9ek)CLC{6K<;LJ?*MmdR3;hQ6w=|h!fio)p$oY>fetTu&#FHEyRM#EW^ zo#fh;j5f*}%;^D4&y<%YCWh3ml$;9$S6WYUh5JHdu9T(CCnzf6cmg_<@R}di!aGkl zS4RPE=rc@EONEceQ)g~Gu~C!X4qFv=LJp2|TZ;Jer3K)!b;XOS!)q)=L?*$@Q$9a$mljigo})L)keK%u3kSgR0|n@cS|{ z44bpyK$btzTWye2d4*j0nU@N3?Rsu7%}EXYovmA*sh1_As~A%rN5Z^56&__AoCp+l zKnGNm2I`dMR|DieX5a*YeX`_9%ooJmaX`O%j_g{>NXZUR+3Yg zq@ojd^q)U|AWdc~ETIgya2$^@^V}&}nHjE`Dif5CE-t1nEZZsz&K|NOtb{)=>x8jg z@{yFfFrL6U_gD^yhIC-Wh~4#-8HpKwE%2B@n{Reg@!)!uYR+}r?i2eF+=|7b$J$k< z@}7R7u%w)_1F-=e*iy{K^AK7ZpFC-!cxLr(Hngxg_^8OIBOKLC=&76)a0@&L?i7(n z=N9fH@>4J=(`#zQczV>dF+H1)?I-w$H%Q)0!pLXXv%OpH#2xCLF23jgrZ#kRS@UD^ zYf#VnyiaN##u=wdF>PRu+$6tfGo0FfC@tvm^9qHVw^!wQH4cn)Ac#N|fohxYRjc{T zC8ZXI7nOXlr1CE{5pwQTZ@2ol*1~Sb;-dk^iEL+|+)VqHwfIaI!f>0@>HWP6Zbs{} zUbmd1o_T!D6I9~MoeWDSof~mZ;jbI&#(8U+E*iS? zi-dnU>yw@804%57omzSNaUvUEevtDtYxv${c#YHzlMT#R)t0t_VrDcc_@Y|R*vA%l>}~u4iDIq$>@pUe&2lXw}+iOFwCq$ zD1UtT=O{6(51rn*U~%_iB}^v-vzCf}z6q{bN{gHK!R}N_nt8Po`-$^HZGRnj9g~y> zluj5Lk(17|z!M-|h!p_kIjGM|I`#noUa~-d{oft1?WQ@nn}!)zZ{u1_lwi2xpEV`D zDDJjPQ`x0`1w-(xard+c0O-IoI+U-8pRcE%FNmZdv6%Y!nmM7-h~48YLzFKZj`Bm2 z2qc*F)JAxd;!L|~&D;Y?94Fj;Noh#ry*%OG#*Rq1x$b#$5VdzwwwJ)v8;y1`gZuh< znmApAfkb-16z~Sn;GYX12$%tIz!&fXJV{vrw4T4X!Pss#ClJ1<9}>|!`MD!}-BG() zf^?c)Zf&Crr}i|cO3H#v0u27DG3#$NHu3azN27c|`aTk;wx=)ZXC=T&I(h$!oOSgv z`W4akMrr>QLHYg_Iqih-`9(2y_4WT1(M2M3enmh%{+0C!n1|~RMeJz_IIDj`81)n6bfzxo8y=?wbtT}j? z`|pZ1gCX|trrxmQ7f3nmUd%9Ww5O#T9Bf>$hq|L&f2xm>L^un|bOP<`i$)^QDAylJ z=zmg3BK(GD_=!L3?&|hCf$k>(l>JpZ_U!;w;wa`^l88^bRGsX2b&QGN*0j0VoS0HqV!59RFhkC6)Vl>uqH6E&%O z|LQ{^@*jN=IPt5m?ul{sS6AGv6r~Ts9R~NYK%6EGCdl8)q1dH?Xjbs1+Km|M{8ko~ zt2f%u^KU3hw70vf`>%OY*Nl|A$u17egTc|y7p)IR!Mz=Q;m#leFu&yabDF2!Vt(;p>#y}nmfAwjf)Wm2h+g=eGPpK%#BX} zoU*8YqW{KB;wOOj-o|?li9yu>78~bzkk8gflci8 zPxjsMcZgIF_^t)Jv*x#5cyFw+@4}=mygToZlQ@9=A4qZVP6KZg2#$j0N5?^Y4!{K( zkNhz%`D0x2$GGH=amgR!l0U{Je~e517?=DpF8O0z^2fO3k8#N#cgk}BJjVe*+Y0a~hjgsN1ZaWB zrf9$kG`0`~%`e~W$9IXEn4naU0{39I_?Vc{}ozwpK)*1p3#~5EtnN_C;dN{o=8yR*8GrM!`} zk*7A?&D|i#8*Ub4Yz_O#ApI}4sSG8NQDd&33gCFLbx(y}swipr8Q@^Z>DGDii$&&iKT$w*7dDoe=7 zsK_a*$S4T@xP-vcyq#TC&g$s>C<~0K3;n26KtOli43@)7=-gAUvW=Iy>~X(C9<5wxQ4^HmoDCEcxp=g%+Qe`WqRjr}6;>g{JD zXV@=pPw?P$R}g2I6dVCZ!co3HAg>Hb6?-~Ddj4YmTh>1t<2OblqyNl`ME=Uw$5+=M ztj2$8WgpVPr_@=v58BTg2G{imMH3bh{8b~B({NWu*d;?#b8Q`WSGW(Do2;y|jE?*X zMR{p?8C_Xo0Wp&9?#?Q5a3y6WX%{&O&{2Y{gtU?z zOhVbwSy{sI*s)^@%Ak`1Ck4l!>G$jf91;IpWrO1eRI&44o&Lu_(n9$DfDrDao~eRx zM7e@;N&Glo7t;85Mr~?Rq#=WF2b1nXd$~ycO9^`wHgNX=+wanka?Idff0ek~T~!=m zB!e%oUpV^1orMJVknaC&HSMJj0F9LXW1rY#^Fh1#1~_`dwOqkw{5d`SW%l>GpNpT8 z!Q4O{!NEyUN=WLb2KH(t_0J0LYUj79<|jKif04jn6Q{<{3GUDHj|To|;Ex9WXyA_q z{%GL;BMtnu^@5|or9}X^u_BJsp9h!C_NHe|^bAky?(Pxk4NkkG&}5)BED|(VC#|E; zU$7FS`V3mb(tu{Upxvt@%*WHnOpj#W4}fcILDFKI1pjrd_3T;Fc1jqS3JU&(|6hVw zV4mKf-8#e+YoaN52zD5B7pANv zXaEmDzum$n2u`g8xYTjqg8!q_*9oFQ3_M zGYDt%U%0UEtnua8D*^0roQRs|K*SQO@q9U5TJO>Tg@s-*WhGCi^W161dl|L4fVq z4!~|N2{5;^1JLN7z&oH3_yn{8-2fIC1-=5az&BtG z*aE%8Q9&3WY>@pB0mwm!I7Akr1kr%#LQX@@LM}iYAg&M;#19ezxdyodxd%yvJcVRI z3Lq7bcaRT|c1S;D41$Avhv3PeWb|b0WPD_zWKv{GWLjjW$jr%X$y~|2$b!hOlf{rd zB1AUZf1BjG|1Y%%iNK zY^R){T&1F-+D|1;rA}o+NORHs)On))dn>kwE(p&wH~zT2o^>M80i8fKbT-pZO zLE2?HIyxabWx6wT?sS*w9?|8~y{8+a+oWfuKSHlfZ$s}#A48u>Uqjzdzs$hEAj)u@ z!HU6`A%-D~p^jmgVS|y4QIgS+(U~!vF^RF1v4e4eiH7MQlNOU5QxH=;QxQ`u(;PDm zvnaDRvmCc@kRyqsier=$$|=fe$cf;L zn+~pviiui^Mv9h+PK$Ag z8HxpoWs40SVmPFE$m>x0p{~P}hm{U{98Nymc7*JR{1LY!Nk>}6$;1`J-Nlo|+mBKl zRX&P3ntrrbf?h&P!e1g=VoZ`#^0eet$uh|WDG@0vsk>55QajS}(g^8i(pVW*nUgYC zW!}hqmpvj2lTDKCI>vBJ?^yV;@?%SK;&O1g6uCZmHhClYNcmcM0{DxRw?eK0PEkbB zLGg)VuM)eGsZx~Edu0mc6UyPrZ)I;Xq1rV% zP#t}p+d7|hS#{6pCh89B3F*1&W$S&@m)8&0uQ8x7IAw6xpx2Pk5N4QV`0b?P$xb4~ZRBktY>cfk94H(t9bP$XJDNDA zJFYqzIz4gv2GfQmz-FC~J3ny7!PVjS;8QN@F85rfUDaLhgAO({-QwNm+_l{k-Ip#J zTui;V?qTAQ=|MzTBJz;bNC#vEiWTL7sz>vq1JUiC;+_$nqh2ar552y5pYnd;1M#u- zDfeXu7gNoChx~5%jrnW%C;4v#SOgRWvIL?6n=c)?bnDVokY3R9VDeyCaBawekSif$ zp<1C&!ysW!VYT7H;n%~zUe>?-@(S%0k1H)#rLW$*x^m6(+MDZq*Dqh6xS@X|JAyI7 zJEAvIH8S-k`AzqmpKl$z_4wA#ZRgt`??~T?zq1_$i~1NX6a6Tf7~>N2IaVPyC5|!< z71wiD^X|)gEcb%$P24xSU;04s!R-et5A7d*h?k2`O`uKiOBj80`ce5~k;ie5w-enG zyOT~Ndam?5 z>jn3VJ1+>CsLauqXJ6K5DQ0E8;(ZmHO_uGKjeBkLx-Ca1r#x38_h}wy-kp3P-!Ffr zz@eb0@Kj-Kky24^@xkIJC2S?POChC~O23u4m5r8PC~vPgSyB5&^-W2oWM$^t18njP;tbvhfn47)yc8+W(& zoa^c9wdo!0bMBk&NAxcZ_z!GhFAq`--X3BeiXY}3P9Hfuk~gX_S~aFK);w-Dj-7x_ z%zp9tvi;J-@S*bRL_~Cb!j12la75oh5 zH@~x>t7eklSxPD>7?AmZUWZx80SeIZtkxMyHb>C$EW7O8r&Jt!eqYCqaXNhy@xHor zP+QLIUV0(Sr&eA^?0!a(!aj3n-@1-*YSC*nv|RhIKhV{CR&3FE?hyC)iDi=SS-9Vg zhkO2K{|ooCN(SfM0&hNgS^mCndgHLN;RW|gw;pFzeCWq*9#J`Ibus96;;T0w2WIel zerll<6rk^1a%w0Px%*iU$yKfv#TigyO0O$-WuF#&V}I8^CVYb9tdsZBF%dcKtDN`D z4yMBjYpHxXiZe}i$9oP z7@p}rEH@m$=&7~WF6gB8M$c6vIcKlkd8OmlY11I9p9px~%`O$KDB!WKSl_zUIR7xb zAmC+CxQlKa@0Dq6FnVRIRL;N}bFvpOk(nfmxFq%hdpN4a6}wZy}Ot)qP4xTh17 z4JuB^q$+>Ba(?mlA#BtCI#ltOlf9Xz^BI!I_En$r)?L?+c;X z5pB9L4XW%?cgI9%d;v6!r%YzAJYsmvWOhAX(5j<5tse0l zV|H=voqutkPed2vy3g$8tp0)nxLZerhZjv_l9x+$>Mt4t7clFFfC^&V4lt|3Xxw8cvn!jef~PS%cTiJxC_eMg$z{*}E%;tG-DN z@hDjmW-)ep?M5*hhB+O=!SXAiO1(PvR$fY(dG{mN%s9q)E|o{G&2}>1$4KTt7gtuA z5*b^%dPCnzTV1>Zb38d#ImBTz$Pl#BARo>-qmWm9sJe9K@F2`N2N+k(o4B5Q-)Z}a z$_5j!LOnt^Gv&orKHah^;Y#kIqjBptsw zY2^Fd?TPLH{-LGPU~3&{v`lXD!i07wU)Q>K03RM!czHoAZzATaF4MBrL~r

_NVU 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 literal 0 HcmV?d00001 diff --git a/episode22/postcards.js b/episode22/postcards.js new file mode 100644 index 0000000..cea41ca --- /dev/null +++ b/episode22/postcards.js @@ -0,0 +1,48 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + fl = 300, + cards = [], + numCards = 21; + + for(var i = 0; i < numCards; i += 1) { + var card = { + x: utils.randomRange(-1000, 1000), + y: utils.randomRange(-1000, 1000), + z: utils.randomRange(0, 5000), + img: document.createElement("img") + }; + card.img.src = "postcard" + (i % 7) + ".jpg"; + cards.push(card); + } + + context.translate(width / 2, height / 2); + context.font = "200px Arial"; + + update(); + + function update() { + context.clearRect(-width / 2, -height / 2, width, height); + for(var i = 0; i < numCards; i += 1) { + var card = cards[i], + perspective = fl / (fl + card.z); + + context.save(); + context.translate(card.x * perspective, card.y * perspective); + context.scale(perspective, perspective); + + context.translate(-card.img.width / 2, -card.img.height / 2); + context.drawImage(card.img, 0, 0); + + context.restore(); + + card.z -= 5; + if(card.z < 0) { + card.z = 5000; + } + } + requestAnimationFrame(update); + } +}; \ No newline at end of file diff --git a/episode22/stars.js b/episode22/stars.js new file mode 100644 index 0000000..3d8b16f --- /dev/null +++ b/episode22/stars.js @@ -0,0 +1,20 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + context.fillRect(0, 0, width, height); + context.fillStyle = "white"; + + for(var i = 0; i < 800; i += 1) { + context.beginPath(); + context.arc(utils.randomRange(0, width), + utils.randomRange(0, height), + utils.randomRange(0, 1), + 0, Math.PI * 2, false); + context.fill(); + } + + +}; \ No newline at end of file diff --git a/episode22/stars.png b/episode22/stars.png new file mode 100644 index 0000000000000000000000000000000000000000..c906d9e94038d2e2cffd4525199030d61c37c582 GIT binary patch literal 30731 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 B>#G0& literal 0 HcmV?d00001 diff --git a/episode22/utils.js b/episode22/utils.js new file mode 100644 index 0000000..3c0f824 --- /dev/null +++ b/episode22/utils.js @@ -0,0 +1,123 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + }, + + multicurve: function(points, context) { + var p0, p1, midx, midy; + + context.moveTo(points[0].x, points[0].y); + + for(var i = 1; i < points.length - 2; i += 1) { + p0 = points[i]; + p1 = points[i + 1]; + midx = (p0.x + p1.x) / 2; + midy = (p0.y + p1.y) / 2; + context.quadraticCurveTo(p0.x, p0.y, midx, midy); + } + p0 = points[points.length - 2]; + p1 = points[points.length - 1]; + context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); + } + +} \ No newline at end of file From 50f682e99a0eec48ed9ffa137514bf2baac3c025 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Wed, 16 Apr 2014 21:59:57 -0400 Subject: [PATCH 17/39] files for mini 10 and 11 --- mini10/circle.js | 28 +++++++++ mini10/index.html | 22 ++++++++ mini10/main.js | 19 +++++++ mini10/main2.js | 28 +++++++++ mini10/particle.js | 138 +++++++++++++++++++++++++++++++++++++++++++++ mini10/utils.js | 106 ++++++++++++++++++++++++++++++++++ mini11/bezier.js | 90 +++++++++++++++++++++++++++++ mini11/index.html | 21 +++++++ mini11/main.js | 45 +++++++++++++++ mini11/utils.js | 106 ++++++++++++++++++++++++++++++++++ 10 files changed, 603 insertions(+) create mode 100644 mini10/circle.js create mode 100644 mini10/index.html create mode 100644 mini10/main.js create mode 100644 mini10/main2.js create mode 100644 mini10/particle.js create mode 100644 mini10/utils.js create mode 100644 mini11/bezier.js create mode 100644 mini11/index.html create mode 100644 mini11/main.js create mode 100644 mini11/utils.js diff --git a/mini10/circle.js b/mini10/circle.js new file mode 100644 index 0000000..897247f --- /dev/null +++ b/mini10/circle.js @@ -0,0 +1,28 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + centerX = width / 2, + centerY = height / 2, + maxRadius = 100; + + for (var i = 0; i < 10; i += 1) { + var radius = 20, + angle = Math.PI * 2 / 10 * i, + x = centerX + Math.cos(angle) * radius, + y = centerY + Math.sin(angle) * radius; + context.beginPath(); + context.arc(x, y, 5, 0, Math.PI * 2, false); + context.fill(); + } + for (var i = 0; i < 10; i += 1) { + var radius = 100, + angle = Math.PI * 2 / 10 * i, + x = centerX + Math.cos(angle) * radius, + y = centerY + Math.sin(angle) * radius; + context.beginPath(); + context.arc(x, y, 5, 0, Math.PI * 2, false); + context.fill(); + } +}; \ No newline at end of file diff --git a/mini10/index.html b/mini10/index.html new file mode 100644 index 0000000..4ded490 --- /dev/null +++ b/mini10/index.html @@ -0,0 +1,22 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/mini10/main.js b/mini10/main.js new file mode 100644 index 0000000..536954f --- /dev/null +++ b/mini10/main.js @@ -0,0 +1,19 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + centerX = width / 2, + centerY = height / 2, + maxRadius = 100; + + for (var i = 0; i < 1000; i += 1) { + var radius = Math.sqrt(Math.random()) * maxRadius, + angle = utils.randomRange(0, Math.PI * 2), + x = centerX + Math.cos(angle) * radius, + y = centerY + Math.sin(angle) * radius; + context.beginPath(); + context.arc(x, y, 1, 0, Math.PI * 2, false); + context.fill(); + }; +}; \ No newline at end of file diff --git a/mini10/main2.js b/mini10/main2.js new file mode 100644 index 0000000..1b3639f --- /dev/null +++ b/mini10/main2.js @@ -0,0 +1,28 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + particles = []; + + for (var i = 0; i < 200; i += 1) { + var p = particle.create(width / 2, height / 2, 0, 0); + p.vx = utils.randomRange(-1, 1); + p.vy = utils.randomRange(-1, 1); + particles.push(p); + }; + + update(); + + function update() { + context.clearRect(0, 0, width, height); + for(var i = 0; i < 200; i += 1) { + var p = particles[i]; + p.update(); + context.beginPath(); + context.arc(p.x, p.y, 3, 0, Math.PI * 2, false); + context.fill(); + } + requestAnimationFrame(update); + } +}; \ No newline at end of file diff --git a/mini10/particle.js b/mini10/particle.js new file mode 100644 index 0000000..b6ef621 --- /dev/null +++ b/mini10/particle.js @@ -0,0 +1,138 @@ +var particle = { + x: 0, + y: 0, + vx: 0, + vy: 0, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + springs: null, + gravitations: null, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.x = x; + obj.y = y; + obj.vx = Math.cos(direction) * speed; + obj.vy = Math.sin(direction) * speed; + obj.gravity = grav || 0; + obj.springs = []; + obj.gravitations = []; + return obj; + }, + + addGravitation: function(p) { + this.removeGravitation(p); + this.gravitations.push(p); + }, + + removeGravitation: function(p) { + for(var i = 0; i < this.gravitations.length; i += 1) { + if(p === this.gravitations[i]) { + this.gravitations.splice(i, 1); + return; + } + } + }, + + addSpring: function(point, k, length) { + this.removeSpring(point); + this.springs.push({ + point: point, + k: k, + length: length || 0 + }); + }, + + removeSpring: function(point) { + for(var i = 0; i < this.springs.length; i += 1) { + if(point === this.springs[i].point) { + this.springs.splice(i, 1); + return; + } + } + }, + + getSpeed: function() { + return Math.sqrt(this.vx * this.vx + this.vy * this.vy); + }, + + setSpeed: function(speed) { + var heading = this.getHeading(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + getHeading: function() { + return Math.atan2(this.vy, this.vx); + }, + + setHeading: function(heading) { + var speed = this.getSpeed(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + accelerate: function(ax, ay) { + this.vx += ax; + this.vy += ay; + }, + + update: function() { + this.handleSprings(); + this.handleGravitations(); + this.vx *= this.friction; + this.vy *= this.friction; + this.vy += this.gravity; + this.x += this.vx; + this.y += this.vy; + }, + + handleGravitations: function() { + for(var i = 0; i < this.gravitations.length; i += 1) { + this.gravitateTo(this.gravitations[i]); + } + }, + + handleSprings: function() { + for(var i = 0; i < this.springs.length; i += 1) { + var spring = this.springs[i]; + this.springTo(spring.point, spring.k, spring.length); + } + }, + + angleTo: function(p2) { + return Math.atan2(p2.y - this.y, p2.x - this.x); + }, + + distanceTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y; + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y, + distSQ = dx * dx + dy * dy, + dist = Math.sqrt(distSQ), + force = p2.mass / distSQ, + ax = dx / dist * force, + ay = dy / dist * force; + + this.vx += ax; + this.vy += ay; + }, + + springTo: function(point, k, length) { + var dx = point.x - this.x, + dy = point.y - this.y, + distance = Math.sqrt(dx * dx + dy * dy), + springForce = (distance - length || 0) * k; + this.vx += dx / distance * springForce, + this.vy += dy / distance * springForce; + } +}; \ No newline at end of file diff --git a/mini10/utils.js b/mini10/utils.js new file mode 100644 index 0000000..7c659e4 --- /dev/null +++ b/mini10/utils.js @@ -0,0 +1,106 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + } + +} \ No newline at end of file diff --git a/mini11/bezier.js b/mini11/bezier.js new file mode 100644 index 0000000..441d912 --- /dev/null +++ b/mini11/bezier.js @@ -0,0 +1,90 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + handle0 = { + x: 100, + y: 100, + radius: 15 + }, + handle1 = { + x: 400, + y: 400, + radius: 15 + }, + handle2 = { + x: 700, + y: 100, + radius: 15 + }, + handle3 = { + x: 1000, + y: 500, + radius: 15 + }, + handles = [handle0, handle1, handle2, handle3], + offset = {}, + isDragging = false, + dragHandle; + + draw(); + + function draw() { + context.clearRect(0, 0, width, height); + + context.beginPath(); + context.moveTo(handle0.x, handle0.y); + context.bezierCurveTo(handle1.x, handle1.y, + handle2.x, handle2.y, + handle3.x, handle3.y); + context.stroke(); + + context.fillStyle = "gray"; + for(var i = 0; i < 4; i += 1) { + var handle = handles[i]; + if(isDragging && handle === dragHandle) { + context.shadowColor = "black"; + context.shadowOffsetX = 4; + context.shadowOffsetY = 4; + context.shadowBlur = 8; + } + context.beginPath(); + context.arc(handle.x, handle.y, handle.radius, 0, Math.PI * 2, false); + context.fill(); + + context.shadowColor = null; + context.shadowOffsetX = null; + context.shadowOffsetY = null; + context.shadowBlur = null; + } + } + + document.body.addEventListener("mousedown", function(event) { + for(var i = 0; i < 4; i += 1) { + var handle = handles[i]; + if(utils.circlePointCollision(event.clientX, event.clientY, handle)) { + isDragging = true; + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + dragHandle = handle; + offset.x = event.clientX - handle.x; + offset.y = event.clientY - handle.y; + draw(); + } + } + }); + + function onMouseMove(event) { + dragHandle.x = event.clientX - offset.x; + dragHandle.y = event.clientY - offset.y; + draw(); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + isDragging = false; + draw(); + } +}; \ No newline at end of file diff --git a/mini11/index.html b/mini11/index.html new file mode 100644 index 0000000..e74c311 --- /dev/null +++ b/mini11/index.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/mini11/main.js b/mini11/main.js new file mode 100644 index 0000000..1c6b685 --- /dev/null +++ b/mini11/main.js @@ -0,0 +1,45 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + handle = { + x: width / 2, + y: height / 2, + radius: 20 + }, + offset = {}; + + draw(); + + function draw() { + context.clearRect(0, 0, width, height); + + context.fillStyle = "gray"; + context.beginPath(); + context.arc(handle.x, handle.y, handle.radius, 0, Math.PI * 2, false); + context.fill(); + } + + document.body.addEventListener("mousedown", function(event) { + if(utils.circlePointCollision(event.clientX, event.clientY, handle)) { + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + offset.x = event.clientX - handle.x; + offset.y = event.clientY - handle.y; + } + }); + + function onMouseMove(event) { + handle.x = event.clientX;// - offset.x; + handle.y = event.clientY;// - offset.y; + draw(); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + } + + +}; \ No newline at end of file diff --git a/mini11/utils.js b/mini11/utils.js new file mode 100644 index 0000000..7c659e4 --- /dev/null +++ b/mini11/utils.js @@ -0,0 +1,106 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + } + +} \ No newline at end of file From ee209a11ab7a21a7c0d7d81f7ea8b435b782b7e7 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Tue, 22 Apr 2014 02:16:49 -0400 Subject: [PATCH 18/39] episode 23 files --- episode23/final.js | 68 ++++++++++++++++++++ episode23/index.html | 24 +++++++ episode23/particle.js | 138 ++++++++++++++++++++++++++++++++++++++++ episode23/postcard0.jpg | Bin 0 -> 51476 bytes episode23/postcard1.jpg | Bin 0 -> 60833 bytes episode23/postcard2.jpg | Bin 0 -> 80327 bytes episode23/postcard3.jpg | Bin 0 -> 63487 bytes episode23/postcard4.jpg | Bin 0 -> 65510 bytes episode23/postcard5.jpg | Bin 0 -> 46842 bytes episode23/postcard6.jpg | Bin 0 -> 75915 bytes episode23/postcards.js | 61 ++++++++++++++++++ episode23/spiral.js | 63 ++++++++++++++++++ episode23/star.png | Bin 0 -> 31761 bytes episode23/stars.js | 64 +++++++++++++++++++ episode23/stars.png | Bin 0 -> 30731 bytes episode23/utils.js | 123 +++++++++++++++++++++++++++++++++++ 16 files changed, 541 insertions(+) create mode 100644 episode23/final.js create mode 100644 episode23/index.html create mode 100644 episode23/particle.js create mode 100644 episode23/postcard0.jpg create mode 100644 episode23/postcard1.jpg create mode 100644 episode23/postcard2.jpg create mode 100644 episode23/postcard3.jpg create mode 100644 episode23/postcard4.jpg create mode 100644 episode23/postcard5.jpg create mode 100644 episode23/postcard6.jpg create mode 100644 episode23/postcards.js create mode 100644 episode23/spiral.js create mode 100644 episode23/star.png create mode 100644 episode23/stars.js create mode 100644 episode23/stars.png create mode 100644 episode23/utils.js diff --git a/episode23/final.js b/episode23/final.js new file mode 100644 index 0000000..4544081 --- /dev/null +++ b/episode23/final.js @@ -0,0 +1,68 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + fl = 300, + cards = [], + numCards = 200, + centerZ = 1000, + baseAngle = 0, + rotationSpeed = 0.01; + + + for(var i = 0; i < numCards; i += 1) { + var card = { + angle: utils.randomRange(0, Math.PI * 2), + radius: utils.randomRange(100, 1100), + y: utils.randomRange(2000, -2000) + }; + card.x = Math.cos(card.angle + baseAngle) * card.radius; + card.z = centerZ + Math.sin(card.angle + baseAngle) * card.radius; + cards.push(card); + } + + context.translate(width / 2, height / 2); + context.fillStyle = "white"; + + document.body.addEventListener("mousemove", function(event) { + rotationSpeed = (event.clientX - width / 2) * 0.00005; + ypos = (event.clientY - height / 2) * 2; + }); + + update(); + + function update() { + baseAngle += rotationSpeed; + cards.sort(zsort); + context.clearRect(-width / 2, -height / 2, width, height); + for(var i = 0; i < numCards; i += 1) { + var card = cards[i], + perspective = fl / (fl + card.z); + + context.save(); + context.scale(perspective, perspective); + context.translate(card.x, card.y); + context.globalAlpha = utils.map(card.y, 2000, -2000, 1, 0); + + context.beginPath(); + context.arc(0, 0, 40, 0, Math.PI * 2, false); + context.fill(); + + context.restore(); + + card.x = Math.cos(card.angle + baseAngle) * card.radius; + card.z = centerZ + Math.sin(card.angle + baseAngle) * card.radius; + card.y -= 10; + + if(card.y < -2000) { + card.y = 2000; + } + } + requestAnimationFrame(update); + } + + function zsort(cardA, cardB) { + return cardB.z - cardA.z; + } +}; \ No newline at end of file diff --git a/episode23/index.html b/episode23/index.html new file mode 100644 index 0000000..1fdfdf9 --- /dev/null +++ b/episode23/index.html @@ -0,0 +1,24 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/episode23/particle.js b/episode23/particle.js new file mode 100644 index 0000000..b6ef621 --- /dev/null +++ b/episode23/particle.js @@ -0,0 +1,138 @@ +var particle = { + x: 0, + y: 0, + vx: 0, + vy: 0, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + springs: null, + gravitations: null, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.x = x; + obj.y = y; + obj.vx = Math.cos(direction) * speed; + obj.vy = Math.sin(direction) * speed; + obj.gravity = grav || 0; + obj.springs = []; + obj.gravitations = []; + return obj; + }, + + addGravitation: function(p) { + this.removeGravitation(p); + this.gravitations.push(p); + }, + + removeGravitation: function(p) { + for(var i = 0; i < this.gravitations.length; i += 1) { + if(p === this.gravitations[i]) { + this.gravitations.splice(i, 1); + return; + } + } + }, + + addSpring: function(point, k, length) { + this.removeSpring(point); + this.springs.push({ + point: point, + k: k, + length: length || 0 + }); + }, + + removeSpring: function(point) { + for(var i = 0; i < this.springs.length; i += 1) { + if(point === this.springs[i].point) { + this.springs.splice(i, 1); + return; + } + } + }, + + getSpeed: function() { + return Math.sqrt(this.vx * this.vx + this.vy * this.vy); + }, + + setSpeed: function(speed) { + var heading = this.getHeading(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + getHeading: function() { + return Math.atan2(this.vy, this.vx); + }, + + setHeading: function(heading) { + var speed = this.getSpeed(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + accelerate: function(ax, ay) { + this.vx += ax; + this.vy += ay; + }, + + update: function() { + this.handleSprings(); + this.handleGravitations(); + this.vx *= this.friction; + this.vy *= this.friction; + this.vy += this.gravity; + this.x += this.vx; + this.y += this.vy; + }, + + handleGravitations: function() { + for(var i = 0; i < this.gravitations.length; i += 1) { + this.gravitateTo(this.gravitations[i]); + } + }, + + handleSprings: function() { + for(var i = 0; i < this.springs.length; i += 1) { + var spring = this.springs[i]; + this.springTo(spring.point, spring.k, spring.length); + } + }, + + angleTo: function(p2) { + return Math.atan2(p2.y - this.y, p2.x - this.x); + }, + + distanceTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y; + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y, + distSQ = dx * dx + dy * dy, + dist = Math.sqrt(distSQ), + force = p2.mass / distSQ, + ax = dx / dist * force, + ay = dy / dist * force; + + this.vx += ax; + this.vy += ay; + }, + + springTo: function(point, k, length) { + var dx = point.x - this.x, + dy = point.y - this.y, + distance = Math.sqrt(dx * dx + dy * dy), + springForce = (distance - length || 0) * k; + this.vx += dx / distance * springForce, + this.vy += dy / distance * springForce; + } +}; \ No newline at end of file diff --git a/episode23/postcard0.jpg b/episode23/postcard0.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a54b4d5396d1b260071b6c4997308ddeb957c8c3 GIT binary patch literal 51476 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 }`^Wn74Pea}1faUWvhgL_LI9El z02?^S8dylC2Y_FDAntwz=Um1BXbJ#1{$~z)kUa1Qi2EV`2SW5?rx#Ge#VlT)y}P@M zI1i6Ag4^nH(;7Dz4&(8*a^d0Q=H&t1lJ<770y{$7>8&9ELL$kq+0xEH54DkGFcQ+> z)o_uA*h5u(+#q^Bn)+ZLN3fU;gR~U=EpKsemHDM^N(jq>vH;`S2YhP&DE@QI0u@$mBV@bhy4 z99)Qdz@9#DE@uSeF9`||1lSFFg>lngN(As*4|hohK+~%xxcu77_gnbCEcQG5%5J|3 z*?@m@y8w{Ql_EA^9*7eJ261*r0K9ycrubnan9FbGe~JEeGyY)I(D_!7_1CeA9V4$}Fi`&B8U{-(-D9p+Z z!sFlqvAb-Ui@3ZS#0r4U^#Ryil0h2^wnA9Z1D}5UkqH4{bwJGJ{z)!gK`uT)ePI72 z&?9*HfTTF@PgbBVsO`P~j`eD*<-b^gzGwqL_5VA}8XDpXaInYajZ;;SWDpXTR}>Ky zQ&Qp=6O|JZlobk zEXL2p2kgb<5)u=%;j-rC2XjHd)gvmKxp*H6@rLF)hTJDOWOmqWz~3P`<*{iuNFzf}Ii7AjB#aD(st zR6!5o`j0YK-BjEPeEErqBm=_A6JoAVxXg+Q{&b50LPbMCMn?ku^oxOvjPhqL@IlNUelY-7FqeKY&@oVe6EXq` z8HETHga$aqkkvuIW(7FLAmNY8!XW+Omtt0c%zBH-EqI$*UQjPSyBdsmEu?VsNluOM zb$uK6j=?!hmIqkaG3a}{|A--?Rp~yI+{eunQ|xe zTLNWNM>p=5xVPAb;`g8Hoh6#&&P4{s^3A&nkT0Ni`;*rQWM#%{_$groZB|u4@AEU7M0y& z)Q?eTfi8rVV4k?6w?FKgAr`B8g5pe#fiC-|{u|HE2gRzy(TRs#GYd(Gc(?a zS@a7Z8^ObnOj(+M_ilUFcw_0m(`jwhG~H^?{cK`7vAPu{%cWrrMX-2>dNm2(zKa~fg_t9gK^`-nVEM!B$RC$>C_HoH?(OTxZjOQ?{MM^Y{{}0gBbWS zc1}Au&VGM8WUBZThVSRqJ7_xjak|S-ML)$bb+9R>=uI~r!j@vIkCcu{IRD)8kq~PN zN1;~!ySb?ParftPq}&-BMz5^rDgVQ~S4vZ-+XkOA)Ns+biMTK&Md$*|(Qf2Ld537k$)GIo zvXAK+h8I|EMpfPLVVQ_-)SoCwI--LN8Lqu5Q%ftP5y}XZ2A2evKB@or{ z^gJI6o zJ8BWFU$l_U4o-)7wzDv2K*qc@9iUe;>g=9INm5;B`f2sL3>sd~eZ`{vst3_|`J=e4h(|LK@#w+Q&DPmL`7uX%zWOtuy01Bt< zjM{dUA<^Fx?2pC2@!c2+xmDR}jHxT_T`Eee&s_P<_An03*i(8G`4IY0p%q=nF(*y~ z!i2l`D4)z6-p#9fug>=^fS>>wmaQDcJIM9MKZCA-@R67-V})fqmHab2jPQq@9F4;< z=@ayw6;vrh1=}wZWMrgy=HqgwJg7ap5~obH$J~6abxG0CkWRMPzpz86x{;x7AGO`j zeDA8|Pb*s-k-0ab&2a=)BNfQ1J=uAQt(JuSq@IMEXf(VcOfeRF-C0un$*$MY0&as{ zM|DO)XWUGaC@hNYiPB8H3Vpd{dpD`aeJ{}xcZ?;^H)eNIou?L5Rp3o4XRfuim{eys zkqjbV?yb)t*M|@wMw5*z7JQ7X+Gm2y-zieHihtqIc-o;$QTrz$5dLAet5{Zw`$?rF$Agmpehi8PI7u)!$IDAv^94GE&< zCV#U`t2DO0dB4etK?h~~uC#;CyZqy`^0c)eQ+Q2N#Rt5su3Yznmn8KBM?<7|VpI9! za#+r-?G_}$SX^y;dAFpDi?=ky;WKDuJO&cpMrhS}%brp=P}>a*3IyK z)KyVYU(jG2>5DktHYNu(yywsv7~YRuRxI(3t?H2aING;g5}Og@1xln0bvPMR_R8O> z&sWHEq&#>X;RUNlAt@~%CMQ8#(N+|upfWW;@?=7GHMP`KMut`f3MpIEisrJjNlIm` zcNHa6d}7TgNus>)t6r|+iGhE!+|E5?lHf#2vJM;(LExa&+n8MtB*^K zh}U@V7T*jVKe9LWaYa9o46wJ^ULd(0Lr1*W{aPlvGvNC7LQzWlm&tGYv5ncB^&dlu^G%5T%yZ2WAdkr3NLpHdT%-~OlC3W-B;;}f0xSo^*AVOK%M-WB^@s85sqAX-APrw z;1^7ZGp1QIl8xJr?UvohLzYBTyIThxj+&gFo10PDDfkY`;fSa*iHxAmJjh{C?Q0rgXQ#ZT(CY4~^7*e1+2s}m*DZn*I?K309|>7`nRv=yrnjOa_lWWp zG`_5DGIru=?kTdX1PoW0;fl| zRJd#nnqNDRpT3?ZxdES)E@1~cc8$nu(2qL;dK7ekBU&Mix<433l!Xr`V} z4{j9Qa8_J(5Hp&)RfDhnP?%@%6JvAhhi7%LHssqd9RUw@auV4> zQIs1JZ~bZSceK(ZR8#!xuH>ESlHPU3;iTxfh~)_>uA*Y&G9%T~Pc1{=xSSM>a;J*( z`il6`V?pv~dAHcLI!+t!-d04>0pDU!S_z+aOfpLRI63{{R_qj(p_Ch$gT~FmdqyW+ zi>HS}e1tUlYhLvVT&=@fnTPiAywo@bZG_MZ5XvJgUW}ZNdvyKvN%A#SwZ0GQR9YGD z6*lVHvMxSnIc*av{dwNT@8By}U}M5=ZG=K>7coxZVx$s^3X_C> zCCBp4VH@2&=)~Nm1t1CbNv$tzkLY4n#in zrco~nA;*oS5#ghGe&W)^7O5X05A;w*LaK=RX^$b3DI`+o!@Wu}ria*%CvS&^1*Z;X z#_f8(=10GUrkWE=^M<2NWj&r4{JJ{4?UowyB%$i6Ywgf|4Sf0{{7>7Pw-YM!R$c4z zRzFJ(ca5f^rxKk4sWok_Fs3|jhP1ZlFcKqP6o=DFrV2RT)+DAEV=rPC7t1-TXg02Ps9tBMYe?gPjwLQu-n)*1qs@pr?=wnB z&HGxfyG|{4vOK49piNfe%6^?DvTly43u~a7HDdHAXLZ_WJ0x!78>e~U!o^dBXOVtr zV4{+_xbFw_?&Pt|DMFG8Q?JgvIydG#4jOig*0sTB#IfbAZfr_Qt0n7qPWh`T&}J_{ zNttIR#KhOj*hP+cN!l-l7etQJTDx*%C%gA>*csGuoL_XkSs6Cs1tT-sjj)_EB(D~z zRgGrHXzEE0WtV2D?B+7LzpL6-L+!oWMSL?wo#mOE5Y`j@&~F1BhxoCxNGCp0Dp&MYhv1DUn!%u8neZ2yE zN3ya@!HqSMH5NnWE%4j%gP*;Q5EuL4xNrmM+kV)XIT=#EI+K3mdg-`clNOp)Oy{~Bg&ILET+v{0;}gxTpN z!-;N5oo)VDzbdYe18>!HPGq0L?ixPX!Lfv|RXs@)R34b6k7Hfy^1EK*C&O@()?qVF zWIf!ZFbQdFwDNQ@A zU5N)G#G+%ZhSrrS9h^4nJ^t@!dQ(1uIql?Lh+lxjxiTY)C#bR}SK`&rnFr!01&53d znl-cd>=G5}h(ZpgzC{-3uo;C)G0p`fbVf_?>_JQ>XBmEMTJFhCHBbwPvY?!palh6k`TBakDkU|Z`OW)Z`^|EE= zM8D3kxr-Yy)fi$Wvnby@_VSPpud=iB4J$I+N18&jJ!(#}lxy`Q!o^~G$f2vHtoYrB z)Vd#}nM%3JFF^dYiOpeRrDYTw+{BPQLQ=UZ;(`*N(ibiy5Bm3pb-Uf|g1-)BJVqy~ z4x{#*Q%hO2dqJ-nelO>(@IK)uhe?FFDx4hH68v869f`9k*?d3SX&s~&T$sE%a*I!r zIBpSUaV%PKzn!`4{E47Np~-^1^E_fuIQxah1&Bh5ZqIFb^@HJ)0#qmcyaAzyHY!VX z-s(lSW@56d2@dr7u=L~Fr|-Yc36Q!&qrFNQoqTj-PqbjLEc7$rcrQ(^weww1Rn=5v z9bL=He(IMC5D$wGucR?GF%9wlce=!ntbP`6?wv(^Qf%*?dwaOO>F`BaR`6P3;%DQp z@+UgtjRhyfZm!9sHyJqxx4v+#GcV5FzqwtG!W3A_xKigJ zVO=(qht7KE3tM0{PGc~e8Z~_pUMWnA8nujjx8DZ_Xr#?9Qnb}G#jX$e#xI<(9KP~W z_i?DQsk2XHNJRL>=)9rfq?-e;mh>B^z_&tGt7B1oms9yyV+FJTo&*qb+PgXo{-KaK0f-5JguA#rf}^iI#VPSCNyZQ zm=XgGWv+R3d&;<7sJPdkk+NfZ2h9gDdM-*gSu-x5ny+^b8~AGkGVQ=3^GSncd> z3V(8{ck<2qM6tZGspG`^;Tsdo%)u3>)=Zr*1D=GxeI#f?vQMa1dzVHuc`>TNgh9I6 z-$HcTx%SEOK@CoC8G)Wb+PcGyg!3C7cTb9ZqM38fHvr!?H`D1;WX4|{^kKFcez!y) ztX+$e+I|_uQXdxIHN0#>(A}LU?Kt}iE3QhGAH&*&Xs12)n}0-IX0IzZEzl?d1Rd4(`yx*e&m6 zLV|vEi=FC~WBtjz=Q|c=W+=>^?9Ug8Sc@Q7El*E0rJpd<81CJ;4auLJZy|0NtCc9~ z6dv1B7x>7;KJ3ZKp2>m6)w>^%%Fmd1vqS-S46$IoiV_w)yC(rwPuBOozZIM-Cj04N zOLP+ITIMAQ{KEG(rK2W$mx?vh?Ic_~0=zPaPPW9jMish}9C?Ux888Sj(X^hNlVgW2 zs=L$iP+DWh4p@c|vkg(n;^P>OyLUcC`(&&WI8`o__>#2s{M&PNV#>nB2F;UM>-L9C zg#HQ;NV2|8`}SMY;%*wnTfP?{YO*9D4$bf>(z;iQ{t>v3I5ZhDV=}*}Wk+b^w>k#t z)PK>&c7M0fBYiP8=XsqHu_{3Iam9{4K%sn{;w)%$Gx{O~fYdiPqfc0%teMKz;pt{zeB?e@A>_L_%!zMD-++ z1bqb6E`&X#s-Q>7q1-K)xp(DVS93k`6`cFNjZ7&?iI<2Kyw(j1Z}qVzVq&wAe7K!; z>ISnZk>$z5EhS*4$9Nc1rx~2%+J;P_@R7a7tgLNNq%bnGgMltgaWc;|4QaCWB{MX( zpvYfc%XZ)NeHyNe<$ExWn+8eOzzZ8b3GAi{f|`?iSfmo+)f275Wa56S;wnLkWru=X zCw19F`%x}+@xAWP;!1NcvE*v=e7t6sMb!!GcSdo>Lx|&XQ9qgX6COS-ESk6I<5Q03 z(P&Zc^)85dxReznDI>-BH87v;`m?!|UZWwQ#@r@QpB? zt_+k`+|Nyk%=-LQ^BG#{$B!bLF@)qF&zHxZ1eC-Ws#x|?t-yCxccIvzhX#bYFGio6 zriqA&;ib%Z zFG@BUKNj^mXxkej|9#Y0#$+$!)9yZA(a!o?1`%$CA4N%0pjo=)K_-!Hs>m!B1>Mck%Jd!`zIJXmvfyM16HZ|2S%l zv`=GF&w`Sk-oIx+K9IWnu6l-^IN8Kl&}ZuW@$k4=PDrpPx=0-LeSM4IXScsD?=U}JyGB&iX6Tg$AP>|nh!%*3C! zn5{dmh-AO-RG_iyxrlsyntKGTF;g(ez`{%KCD|u*FwsGd)T4KeIaU$1y3}crG@qxKe{v0TT=u#?+e$nZ?%hZBe8d4$K&sj96DO4@kO5= zg(jDqN6<2xBzL`M1n-*wFS08Q^(x<9;w+7IP%zHMnPwgm9e3B?`j{;F9GW+!xlN(F z&`a}Tb(cYL7=elur4X}NqLPwr= zr3bLYje1m}oOk57)}EEg9O7zv$EU(|KbQTTtPzc99Uq>JKn#z?8?FLYB-SzmYgW&3 zqfb^ykJz3x%ZkNmkO?T!*i+Tr;tji*vSyswkUALskePb!P7tY(Rl}WaHk>_}u%w<^ z`g^U1b+iKKrl+by=NLCeGI$fsIv`7y9B&KMDAC$O*BuAqo-np6q>&^lztKTjG^#^9b14a;BCjlUC2`>B05tt zufzt`7e=o9eSy1or>@O)a?A z?k+ai*fkDi4B%>*#1ggh96C`SY|3n$J7By|A!%?(NsD(&XP$R27V+*{?Kp}E=ydbB z|NLf1xxK|~NC&66*fSz(BGP`s{>Em~$d|G@;%ZPSkhEJ_>)f8)kmGUH8a4?5xL@X&)o0YW)ckEMTS8 zLeMZBGcRf!v}W8x@<}fsqA`0Q#j_0N6FJB~B`zA7!&}7UL9<0lyeVUTl+D~YOL8j< z*XW55MbU8a$$lq&g7=HA$fA=#98XTqZjU(yKOeiu@AR%hhBOX7*b6v9EV43nB@J)B z_e?@9s*}Tc9^!?EV#x5-4jx*^y=!PYABT}d?B0R4LO*((Y@?}IuNgU3nizP$k**KKE?HGD|AwnL6xTy&>-{lo-WPi0)Q zqjN7G8E|`cF)(ME))vWgmr`M4bWkb1>bXw5W{j!-d+T|D*<0X%<$Tn12a$SMfkkV} zyLeYB4HSeNxu=+D??W@u-ePesTd~E;pwd>AEP0$<4+2)_a<&t2y}qk9%K+DL_UFOZ za87};-hMADF=Kjm`4E=c%$ctV+bWR7l~@}Rp3VH>lp(#AdV&IG`gn4x$lRN{{q3}t zeG{x;!o~-y$E_OAmCO>fMAs6>s;7*hbsDtqgv`8GRfT2_LeBCn5_;@wmq70VK5GGP z%c9H8pWk-N^z0k0kD<+kM^Jrb7O@rFzDa7>0HtV*c^qYO-*E;BH@n{1@ud3GQ(9SH zWaZsXwkb#@W>lxObuZCfCL7Yb1iG1fq8g(;)FY5Ebn7bB?IQY;;M^hjAt&f*5B|ef zV4mg2P&^Vp*ICy(uSk_@vQPef4-3wsl^+KL%T&_F9ckI|?L;^DBR{tCgA;$dm$dur zZN<*OQ`d7R6~D<>d+Yyp8nZy{ zz9j!`tlIY;%%gXu$Sk!?g8eH>El4qAR&mUG@oMkZ;VV{Oi_Au=Z+I zk`mk3P1cp`lzyX??rS$&hs?&FZQR&nOaVFgDd^TYzO8p$0>})EiJD&H(L%nT+N%Lx%XtOZF48oaR#%sO2_WPBU)%DPOr;2#S`DfxY%1yIIwDclpd}yLBY;(mG~h_7&>*(upY%s9`_P5&j+h3)DiwXf&5Xx z{~NGS(TEIEE%-S92=Ein$R14ZJ*P-Q*8}a*JFS>})oJ{cass;i80U59P0NVF+!Q)W zH;fqqB5>;sBlYUqW}*;ItgOY+ki&(Lw~DAAb|sTJC{FNn#k?0(ISU!`2TOIQZKJT` zwgfz~4l2Ieh(M~x*YBQ4W6{$xA+!3uamgz2bJIweI`8oTt?|Pa1n(lg`r`|QX82o}K^DO z=gs>JILr_1-BACXJ$5U;TA|bbBaLJ#AK$9NqsVY91r{d9Vj>=)J5nn=(}&a9Pa{l& zHD~HHTOeUX$+OE7Z=cv#Pt7b}PuyXxJMQCGW$e(@RZAUJ+eKX>vro1`^=Z`F4!||z zKC0vuCY_oRF5@OC6q;=JM}yDKH^gYc)7e+QL1##v&~+&^2*5#H?`LNc*tFR(Dmyu& ziqfAkadY>L_*6-1A?kS9;du@^rl!4)g7??UZ9*55_6LX_-MId3N9e?|cMF1e#1$7y zeI(hivr3-3gP!Ar{Dw)S%PZ_DJ2tB<@b32#oBvGpeZt)x&8LMWcwrNF@jUx#CG4{k z!8fK&pC|8QbW=HS1_h~rG36EC<)>l6sc{BMa;5cfHI#Wj7456-u7np8FzGP(Ny!<_ z;j{-ax+vk79=*Y)pDmiQ7zj#450>*uM=$z5^=;n#HIIu0?C6;zS3`PsBUjg$cD-D2 zAUZ!!$Bn|X{Ok>vc}};e38aVW3y;G}6!zCwU$L&1*HUZM6ft7qDzlg@LQU_mBj?0S zWP){tXSRDZ8t7PP3d}jLy+CSXEnh%M5OeC(A95Juq<&zs)U#XjZfBME)7bDrSF7Ll za$LXgo=Hr>)T5cAoApY~HMKP3$Oca$6a`oj9C*DfZ?p#Dacv$a#8yIO9HBXUJs~It zu1cgAApL|M%;_*MrSY2yf{$Z(G`OBgMMXGYAw?l_+i93Zm z*wW!890_GSl7^Htp}-gviK3NY2r3FWU|3XuKerT8>zKL846F87EmZ!?cmBAgUNB^V ztN!a{VBmG3?t5TTm?UMPnm(xgDl0O!#}#YSF~|oRl{*qUWP%YP z2?cu|p2sA#+o@#?dh|5?c%e^mPaIOcR<-T#iW=iWPX6`9R?y@| z>$vTT(?xf!YwwDX(Gv3iQIOkPiO)*YUtqE2pXHjw{IZkGZPvPsalw z`p?T6C9RK?>~#3zMU(2tZX{p#WQ1}o#O_#=m5DAwNmGRdl#wu{TWSufLCXVKEP~Q_ zB$B2**pM6_gs{Z5l=>wP52iQdweX=`@+71SRuMO*(Ks9!QLDBaO>}jNh(wS%_+zhL zgd7sxFxzFha8{Vg6Sj z8zmD)m`rVM&?QUF4)0Fk&zwhw^Z?SUzqS&>B{1?tjrDd6Ky^G%-BC}c1o<+@%^}tF z(QW3NnPRF%bXIY-0CTf_KmZP(iNdy-%OKz`6w;kXwmwNG zs-@Mk+*wE-fHLe)RXZNO8)R;aA~r$kNYm-X8GtpcL#R*>z8)$pK(R^_+bcClsqS+2 zvf;<0ZfQ!5jwM$WR*8oDbn(O#gd{bRH;tGb>brDd-wPtp?mz*U5Z_J!ia^V6$6_ig zMz2y1Dg#C!(WtN3=zI9!O*a%mj5t&{Jcn)1P%&CW#)U~?upk0DjFS=&qT7tjdID+z z?SW}nq4|&FhSr+g4*}C9Xr~1L?~2o0ckuDRRd7MQJNFpcDa8oyh$*FvJCRe0skJHk zu!W|BRMWl!s))e1&mxp$5wpmuq;e*Jk_P_xu_6D|;ySg(jO}mr8*^_QaVpA{Bs9OY z;=VbLjwD^1-7yELLCb9tTci5O(z9<8gUAmOdSrx&EtN{pSjTY#%@l;s5alFnDYu9? z49GOdM#Z5-kHw>@2*#y*RAlLkPu8Fhf1WB^Robl|zMs+V zveI&@*PJ;AHyJ7F;72PTwVE1 z;D}e#nm?PV+6<`Y~*n-!Lc>jdQ@cCCy;zdir&n__+pg87Xm~Cl8^9_ z+aV#dU_jVi#Eq(;JQ|y2@hl_|^2909zpo@1tc>v_ z5m8Ua10)KgP_Ezu$bs|26HLPAC)6Dn5n9%?!a~zhrATh0r%Z~e`dj}13|5ySQ?G8A zpsz}AP0xIlptQ=Q*S~X$8slHPY*k6rDK#|4)l9J!rr$gz3)Mppi*bOIs!$EO5!b^I ztpYmIgQh52;11ZSQg!G&d^~ZrSfhV@B`T4C98i4nDvg9I9yFxop zR6{ntuOmihMXXh!_BbzkWl86i^{p~4dTy-(y@kjqZUEyXWb|O($1!zSW_?gKIJ1np zB7D1~Xj;~&`ZU*K9%a(f{pbZ(bR-&e$ZE4s7C#UUD*B?%F%mS8YWiIIR;hKS&g$}8 zIYyBy#i`MSdmPKdlw^RA{wBG{gwhN#6{mj>46%#35C@JGYn5wU2z5>=clnG}*ifk- z9l2M%X@QVgy?5(eSh7DNFZ}IRYvb{Ji0RiMK25m!zJt>4Pcs#GiuCav@*#woDF8(q zf!uC#L9C{T7(^J4g^waV@U@iA%acS4bf`5QcEqMC$sZY&PT-zMax9gl1!V<+t5DXv zY;cXzRRR=br%I7l_umIJg)7B~MLN2dj#%A_(z~koWO{p)u{{zd5T`oQKArmIw9=da z(aN$BTGM}Q2}J5Bv%uSZrS0RAh)j}OYhO))r%X1$rpfkx54Ja_jv+$4QZ+cRqik0R z41rTBykDYTJNRo}lb;3PXt4_;&{+5aPcMES8kt zZ^so4h``_R@W4>HV%!nEFmWc4QAQS?6~M&5|JLA&ys9fh@~&1}6H7}gIj!E<+&ni& z;)JmM+xV&Q%4H%A*389H{X5C}mHWtoYkPhw%#AdGRzjk@RfTu?od)73h#=t&md{~g!-g+ zaYkAgN#!eSweSbI$jCNBmA!t{%$Erxk{F$bwgDC;oY=gQS*keQcMak&(^*dK0rVC& zCWLMDV$@TcbTP)DQ;Pks9q>tz3Z?+eD0wdQ!EC9i6_5q+-+lHtLJI!?R=*34s0}d# zxi+ID^+p}dK(AUhONEIkMXj>MuqJ?R4i*Iz60p$q2DlYe5yFSIO45h)hdP13js_}- zzZTe4R0`AEB$f2!v_9CSu83Fmdt*u#9~>xHKs~GDgzrQlDt} z;3~C%`JSf&8VlpMz7<$@-v~ostpGi7Rm2JpZwzUWYrjvU6e=xh4~IjMr9{R$8t-1d zI13m5*WloyjnwlU`(zstmb#&YD3(7`1YuLrg7*OBW*5mkMH?eoT0$=^ZkF=d-;uMF z5bCF>Vn1su0G)`YG01Olr*j3eT+J=Ci4LDC`mwEQz>!e2`Qs96er>VuM7Nkey4JI-I9bBZ@q6JAXAn zV;aVheWc&b1;i~MrsYx2>U=1}W42~t%NfKG)vScNzlK`Hz3E=Zz683I0QNXg+SHmZ z=WalC>$Pwc(yyX8awd!_3Xpd-{+Onj2ad=s#9Ouql_jZVzu|ikglpJ@8jDGCFlV^h811I zV@y)f9dMzpBd#i@QirG0g;y^0ug?KXQi`A9fFvoH>N;$4R;o=MKhLH%tAZY$IV)mU za9%w&@W7~Z7g9F_{y8Klv~5yrwkdF@9ftn^h6J=n#x~du$G$|}s@G2A?#Uw7l;3Z= z-wPEoho?$(7@@*40Pw?UR13HHK<(ghwGLR%%$?8A0#z0>)4y6^v@67f(M1Pr1rPtw z;}#{qMCu5x7m!mdWqC6dJ8|y0i$AU{;B1#jzKVe*eN#i}b_3tvE#|dL?O_w#EJf7} zy$Lj0`{ZP3TN+GstuQsz_7|4LYGLW6EJr)(qYvRUzLh_Ke)5o+*=;agxLo>!q}=4s21Rtu1pE4$v=UF?l-Dqi2{ z?{{mhLwxbG$@)4*WRcKyc=_zj{!Uf-u?dKn7=!$O!huK0iV}Kv{aK#H)Z6voQm+&! zV=}p@>BMbM3ZHxgvjGxr)omKx_!LPCM-?bkw^j@VO8)?o$0NhNrusP=+G6FT3g8b& zQlZ#>%XFnjM#puq^pDB|XAhX~+8Boz?Woc*+%Y19!>Rj2?PLx0XDXvlQPdt+ltwue zDhZ(5JP>3zst5t*p%kgs~J(a9Vv?f5wObZ#DQJu zTnuR(@@z+1n&AwJ-%*yQtvY*Rgejc!C5FehY;6i}C?t09!)s1g0+rghP`O)hI|Gp= zTPB1Ph$*KEZhst*Vy?9-?cs%xRE!eC!@~lFO}cj&vRXmk3L2)}aaE2#w+KO6D!caY zg)8bBo+qiurK)e!3KqJG_}8z?5U%1rfHAZ*MJf1wI8|dH2Az*Vh$^7*{8a7RC2ADf zGfZt(aXhQ?uXB+pURQ1Ku~=j7Hl`a@fm*ce2h&_i({vQyr)*Wld;Qp`ZAT;ejs&Vx zpglI<0@AEwrFP$Mpx`Bo|IyH3|nr56{P-Z2^>8*u`ZIYjUY zM8x%3fJG-aeqq&o%_NsCIkmX6g@_T4gpZiqSEgg*)58ei0>q14U?Y8PB>fkr%cHg8 zU6j3uku|J~_K#3dj@gmNE;_GI^O=%vt7Pv+@~z||9dlo^Gw6$N>LZDG8V|6b3Nilx zS21&Hgo($FRhIjigGm;)bUTZ;pGbmRJ4UGx%u9fO$!?$@1NL(-0Ld8C&m6nd(egrD z!OlVHkt23Oc-Dfaf7#1PNDIP9%mUFvRIN|ZwGRIPED2MR7ZIsxqpJYSfxaaq(u7m5 zd~J;_W+B&@9|bu8MGh4&QT(E|;d`n@DFRaj3{$w~+_$go1?!Z^?%G8Mu*oU(ltZ7T5|p7^p}M%Yl%8*lewt53ESSk*fWC}?%u`(jc8`T}X&0#@(7_}Uuy zkIM=h?Y=7SZscq|u~m!?5QR2C1$%g5w5(;@Yzb2UgTHUT5`{pO+Q02%XmLUIY5vwA zs*^+kC$T>~O0*Etpi{tOX?LgAgXqTAn+QRm752oHrxZMa9k;-$$cDee0Vt>c(&Mrl zpjsD&2o!esNgu1jF#sIgswkxzP1<@chR$MAvqDG2r*PZ+HT{k)ko8BGsd=o{wA*V* z9ZLyqCQ!EXEfvcu^_VSUd3&EtxZ{fz2_gulMUXO<;=j#L8fHi>WF~rc zpLKI=(?b6MQ{hBuPRRA&jeK&M%mZB5%W75Bn#LP=?QX5ex+ocDkL?lDi-Yp({J6jp zY#o`Ax<6ICw3fwm_tftuiU{K=2w=($DnYG2##4?29xfPyQz(vLZiSZL%Tj2?;JubT zN+bnPipL=*bl>b8upGR6hX?y4&>Sy$$ zfv#Z=(o^h;HqHLFBP@H^@i47(^P|g}Kbvp-zSa}oE}Y^Cui$vXw7>%*sy!+Yo*cP+ zZIj}cKA(?LL~oNN(R};meR5TgO}`0rDN8H0Hq%y{fUoem{{W0^`0<7^i5$fz6J5HE z>aW~%JieToDGDA(Y6_BjF7>7%X=tD&hXn#SMT-9jV;nmp6eQP9apz-8x}I zTo#q5$l{fZigyFHD!Eg~==yLW#e8t8#zV*A6$5dKt>8r|in)|~;-RHo{3(GYpSK^0xU3-JeDJhNmUYpl^s?aw-5ig(^7EeIo>6LY7jqYT9O%KA_S` z>ZDcNG=_nVd~!K52=q*2Y=OMBsOj(|(?M-c+Jo=OR$dK;cN;_C1woxU@H5k330(pqqoXagf1U+f~{#L`q zyAS{$kM>E75?lU@TN!O4Ef95z_$ZEK^zs;!Y$D&nDxupZ8rq;Ie#Vb4P=c z#6M-e+OP9v`yIyYC5(rz+o^gG;zcH^=tB;b8;=}Bfg3fdwC@GPa&cyhqlMq?cf)8X zp{&Oj*Rs?A3v5z6kBp?wwB;}l8Tc+tGW5@+XAEFl(FSd zM`{p9;fhg-Cqv`Y+XxD*9-@`P6>Aa8=*3p^+kW{gRlK=SuJzm>94g--wRWdm30xUP zD~hyDM_dZms4K?^L0qlx{?;gLF!0|Mw;Ju!2vxK->xovW{?;jI4lI58oK>?*cz9q! z&`$f|R@Fg9>qf2Y%1(?}88@lCqF0Ld#HVSm#?=KB*)6 zNj(py(jJ4C+2x0hH&^Oj30Eacn1Y7-+682yJc=mDM#V`V3;TZ75#+LudM4V^&IbfB zkkB{BLbWPDWnUkk?B!&Vn9x`Hyiii%mL4*(5;>zGULX+5LB!Pl&&B�lkq{t#37q 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 z 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 RFV%W;EAC(l_wI1={{R#U;^hDU literal 0 HcmV?d00001 diff --git a/episode23/postcard1.jpg b/episode23/postcard1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5b5d7f10d7b2412a550275f76bbce57115ba0192 GIT binary patch literal 60833 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 z�VytUB_0U*ltqRGXNJ4O^~D@26NOEhK#E4k$P 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

MU-Ym>$9&~I`V{mu3>G4NV=z^kxsFV+ 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 literal 0 HcmV?d00001 diff --git a/episode23/postcard3.jpg b/episode23/postcard3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f2877d39c13a8e340c0d56c21ecd82cd1f10e5f3 GIT binary patch literal 63487 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

Hxp3E!g4!o=-f*C!Ky^5?{RhjS)J< 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 literal 0 HcmV?d00001 diff --git a/episode23/postcard4.jpg b/episode23/postcard4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8f27343956e5c17762f997cfc389bc9ea15a4a7f GIT binary patch literal 65510 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 literal 0 HcmV?d00001 diff --git a/episode23/postcard5.jpg b/episode23/postcard5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..00b32aa623762830563b0609a2a854cca0c2bcae GIT binary patch literal 46842 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%0D$@Dh^yaR_;XG1NDdQe0F$DddA-~tig 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

_NVU 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 literal 0 HcmV?d00001 diff --git a/episode23/postcards.js b/episode23/postcards.js new file mode 100644 index 0000000..827465d --- /dev/null +++ b/episode23/postcards.js @@ -0,0 +1,61 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + fl = 300, + cards = [], + numCards = 7, + centerZ = 1000, + radius = 1000, + baseAngle = 0, + rotationSpeed = 0.01; + + for(var i = 0; i < numCards; i += 1) { + var card = { + y: 0, + angle: Math.PI * 2 / numCards * i, + img: document.createElement("img") + }; + card.img.src = "postcard" + i + ".jpg"; + card.x = Math.cos(card.angle + baseAngle) * radius; + card.z = centerZ + Math.sin(card.angle + baseAngle) * radius; + cards.push(card); + } + + context.translate(width / 2, height / 2); + context.font = "200px Arial"; + + document.body.addEventListener("mousemove", function(event) { + rotationSpeed = (event.clientX - width / 2) * 0.00005; + }); + + update(); + + function update() { + baseAngle += rotationSpeed; + cards.sort(zsort); + context.clearRect(-width / 2, -height / 2, width, height); + for(var i = 0; i < numCards; i += 1) { + var card = cards[i], + perspective = fl / (fl + card.z); + + context.save(); + context.scale(perspective, perspective); + context.translate(card.x, card.y); + + context.translate(-card.img.width / 2, -card.img.height / 2); + context.drawImage(card.img, 0, 0); + + context.restore(); + + card.x = Math.cos(card.angle + baseAngle) * radius; + card.z = centerZ + Math.sin(card.angle + baseAngle) * radius; + } + requestAnimationFrame(update); + } + + function zsort(cardA, cardB) { + return cardB.z - cardA.z; + } +}; \ No newline at end of file diff --git a/episode23/spiral.js b/episode23/spiral.js new file mode 100644 index 0000000..acd9ebe --- /dev/null +++ b/episode23/spiral.js @@ -0,0 +1,63 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + fl = 300, + cards = [], + numCards = 200, + centerZ = 2000, + radius = 1000, + baseAngle = 0, + rotationSpeed = 0.01; + + + for(var i = 0; i < numCards; i += 1) { + var card = { + angle: 0.2 * i, + y: 2000 - 4000 / numCards * i, + img: document.createElement("img") + }; + card.x = Math.cos(card.angle + baseAngle) * radius; + card.z = centerZ + Math.sin(card.angle + baseAngle) * radius; + cards.push(card); + } + + context.translate(width / 2, height / 2); + context.font = "200px Arial"; + + document.body.addEventListener("mousemove", function(event) { + rotationSpeed = (event.clientX - width / 2) * 0.00005; + ypos = (event.clientY - height / 2) * 2; + }); + + update(); + + function update() { + baseAngle += rotationSpeed; + cards.sort(zsort); + context.clearRect(-width / 2, -height / 2, width, height); + for(var i = 0; i < numCards; i += 1) { + var card = cards[i], + perspective = fl / (fl + card.z); + + context.save(); + context.scale(perspective, perspective); + context.translate(card.x, card.y); + + context.beginPath(); + context.arc(0, 0, 40, 0, Math.PI * 2, false); + context.fill(); + + context.restore(); + + card.x = Math.cos(card.angle + baseAngle) * radius; + card.z = centerZ + Math.sin(card.angle + baseAngle) * radius; + } + requestAnimationFrame(update); + } + + function zsort(cardA, cardB) { + return cardB.z - cardA.z; + } +}; \ No newline at end of file diff --git a/episode23/star.png b/episode23/star.png new file mode 100644 index 0000000000000000000000000000000000000000..892908b75d4440e9585354c1dabc657f5f140296 GIT binary patch literal 31761 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 literal 0 HcmV?d00001 diff --git a/episode23/stars.js b/episode23/stars.js new file mode 100644 index 0000000..0de703a --- /dev/null +++ b/episode23/stars.js @@ -0,0 +1,64 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + fl = 300, + cards = [], + numCards = 20, + centerZ = 1000, + ypos = 0, + radius = 1000, + baseAngle = 0, + rotationSpeed = 0.01, + star = document.createElement("img"); + + star.src = "star.png" + + for(var i = 0; i < numCards; i += 1) { + var card = { + angle: Math.PI * 2 / numCards * i, + img: document.createElement("img") + }; + card.x = Math.cos(card.angle + baseAngle) * radius; + card.z = centerZ + Math.sin(card.angle + baseAngle) * radius; + cards.push(card); + } + + context.translate(width / 2, height / 2); + context.font = "200px Arial"; + + document.body.addEventListener("mousemove", function(event) { + rotationSpeed = (event.clientX - width / 2) * 0.00005; + ypos = (event.clientY - height / 2) * 2; + }); + + update(); + + function update() { + baseAngle += rotationSpeed; + cards.sort(zsort); + context.clearRect(-width / 2, -height / 2, width, height); + for(var i = 0; i < numCards; i += 1) { + var card = cards[i], + perspective = fl / (fl + card.z); + + context.save(); + context.scale(perspective, perspective); + context.translate(card.x, ypos); + + context.translate(-card.img.width / 2, -card.img.height / 2); + context.drawImage(star, 0, 0); + + context.restore(); + + card.x = Math.cos(card.angle + baseAngle) * radius; + card.z = centerZ + Math.sin(card.angle + baseAngle) * radius; + } + requestAnimationFrame(update); + } + + function zsort(cardA, cardB) { + return cardB.z - cardA.z; + } +}; \ No newline at end of file diff --git a/episode23/stars.png b/episode23/stars.png new file mode 100644 index 0000000000000000000000000000000000000000..c906d9e94038d2e2cffd4525199030d61c37c582 GIT binary patch literal 30731 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 B>#G0& literal 0 HcmV?d00001 diff --git a/episode23/utils.js b/episode23/utils.js new file mode 100644 index 0000000..3c0f824 --- /dev/null +++ b/episode23/utils.js @@ -0,0 +1,123 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + }, + + multicurve: function(points, context) { + var p0, p1, midx, midy; + + context.moveTo(points[0].x, points[0].y); + + for(var i = 1; i < points.length - 2; i += 1) { + p0 = points[i]; + p1 = points[i + 1]; + midx = (p0.x + p1.x) / 2; + midy = (p0.y + p1.y) / 2; + context.quadraticCurveTo(p0.x, p0.y, midx, midy); + } + p0 = points[points.length - 2]; + p1 = points[points.length - 1]; + context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); + } + +} \ No newline at end of file From 3174fae74b4f38936a7dbc776ec91d8f51fb2786 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Sun, 11 May 2014 17:58:16 -0400 Subject: [PATCH 19/39] episode 24 and 25 code --- episode24/index.html | 24 ++++++++ episode24/particle.js | 138 ++++++++++++++++++++++++++++++++++++++++++ episode24/spiral.js | 63 +++++++++++++++++++ episode24/utils.js | 123 +++++++++++++++++++++++++++++++++++++ episode25/index.html | 20 ++++++ episode25/main.js | 95 +++++++++++++++++++++++++++++ 6 files changed, 463 insertions(+) create mode 100644 episode24/index.html create mode 100644 episode24/particle.js create mode 100644 episode24/spiral.js create mode 100644 episode24/utils.js create mode 100644 episode25/index.html create mode 100644 episode25/main.js diff --git a/episode24/index.html b/episode24/index.html new file mode 100644 index 0000000..e9da3d3 --- /dev/null +++ b/episode24/index.html @@ -0,0 +1,24 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/episode24/particle.js b/episode24/particle.js new file mode 100644 index 0000000..b6ef621 --- /dev/null +++ b/episode24/particle.js @@ -0,0 +1,138 @@ +var particle = { + x: 0, + y: 0, + vx: 0, + vy: 0, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + springs: null, + gravitations: null, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.x = x; + obj.y = y; + obj.vx = Math.cos(direction) * speed; + obj.vy = Math.sin(direction) * speed; + obj.gravity = grav || 0; + obj.springs = []; + obj.gravitations = []; + return obj; + }, + + addGravitation: function(p) { + this.removeGravitation(p); + this.gravitations.push(p); + }, + + removeGravitation: function(p) { + for(var i = 0; i < this.gravitations.length; i += 1) { + if(p === this.gravitations[i]) { + this.gravitations.splice(i, 1); + return; + } + } + }, + + addSpring: function(point, k, length) { + this.removeSpring(point); + this.springs.push({ + point: point, + k: k, + length: length || 0 + }); + }, + + removeSpring: function(point) { + for(var i = 0; i < this.springs.length; i += 1) { + if(point === this.springs[i].point) { + this.springs.splice(i, 1); + return; + } + } + }, + + getSpeed: function() { + return Math.sqrt(this.vx * this.vx + this.vy * this.vy); + }, + + setSpeed: function(speed) { + var heading = this.getHeading(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + getHeading: function() { + return Math.atan2(this.vy, this.vx); + }, + + setHeading: function(heading) { + var speed = this.getSpeed(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + accelerate: function(ax, ay) { + this.vx += ax; + this.vy += ay; + }, + + update: function() { + this.handleSprings(); + this.handleGravitations(); + this.vx *= this.friction; + this.vy *= this.friction; + this.vy += this.gravity; + this.x += this.vx; + this.y += this.vy; + }, + + handleGravitations: function() { + for(var i = 0; i < this.gravitations.length; i += 1) { + this.gravitateTo(this.gravitations[i]); + } + }, + + handleSprings: function() { + for(var i = 0; i < this.springs.length; i += 1) { + var spring = this.springs[i]; + this.springTo(spring.point, spring.k, spring.length); + } + }, + + angleTo: function(p2) { + return Math.atan2(p2.y - this.y, p2.x - this.x); + }, + + distanceTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y; + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y, + distSQ = dx * dx + dy * dy, + dist = Math.sqrt(distSQ), + force = p2.mass / distSQ, + ax = dx / dist * force, + ay = dy / dist * force; + + this.vx += ax; + this.vy += ay; + }, + + springTo: function(point, k, length) { + var dx = point.x - this.x, + dy = point.y - this.y, + distance = Math.sqrt(dx * dx + dy * dy), + springForce = (distance - length || 0) * k; + this.vx += dx / distance * springForce, + this.vy += dy / distance * springForce; + } +}; \ No newline at end of file diff --git a/episode24/spiral.js b/episode24/spiral.js new file mode 100644 index 0000000..cc64d83 --- /dev/null +++ b/episode24/spiral.js @@ -0,0 +1,63 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + fl = 300, + points = [], + numPoints = 200, + centerZ = 2000, + radius = 1000, + baseAngle = 0, + rotationSpeed = 0.01; + + + for(var i = 0; i < numPoints; i += 1) { + var point = { + angle: 0.2 * i, + y: 2000 - 4000 / numPoints * i + Math.random() * 500 + }; + point.x = Math.cos(point.angle + baseAngle) * radius; + point.z = centerZ + Math.sin(point.angle + baseAngle) * radius; + points.push(point); + } + + context.translate(width / 2, height / 2); + + document.body.addEventListener("mousemove", function(event) { + rotationSpeed = (event.clientX - width / 2) * 0.00005; + ypos = (event.clientY - height / 2) * 2; + }); + + update(); + + function update() { + baseAngle += rotationSpeed; + context.clearRect(-width / 2, -height / 2, width, height); + + context.beginPath(); + for(var i = 0; i < numPoints; i += 1) { + var point = points[i], + perspective = fl / (fl + point.z); + + context.save(); + context.scale(perspective, perspective); + context.translate(point.x, point.y); + + if(i == 0) { + context.moveTo(0, 0); + } + else { + context.lineTo(0, 0); + } + + context.restore(); + + point.x = Math.cos(point.angle + baseAngle) * radius; + point.z = centerZ + Math.sin(point.angle + baseAngle) * radius; + } + context.stroke(); + requestAnimationFrame(update); + } + +}; \ No newline at end of file diff --git a/episode24/utils.js b/episode24/utils.js new file mode 100644 index 0000000..3c0f824 --- /dev/null +++ b/episode24/utils.js @@ -0,0 +1,123 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + }, + + multicurve: function(points, context) { + var p0, p1, midx, midy; + + context.moveTo(points[0].x, points[0].y); + + for(var i = 1; i < points.length - 2; i += 1) { + p0 = points[i]; + p1 = points[i + 1]; + midx = (p0.x + p1.x) / 2; + midy = (p0.y + p1.y) / 2; + context.quadraticCurveTo(p0.x, p0.y, midx, midy); + } + p0 = points[points.length - 2]; + p1 = points[points.length - 1]; + context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); + } + +} \ No newline at end of file diff --git a/episode25/index.html b/episode25/index.html new file mode 100644 index 0000000..cee28ae --- /dev/null +++ b/episode25/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/episode25/main.js b/episode25/main.js new file mode 100644 index 0000000..d68c67b --- /dev/null +++ b/episode25/main.js @@ -0,0 +1,95 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight + fl = 300, + points = [], + needsUpdate = true; + + context.translate(width / 2, height / 2); + + points[0] = { x: -500, y: -500, z: 1000 }; + points[1] = { x: 500, y: -500, z: 1000 }; + points[2] = { x: 500, y: -500, z: 500 }; + points[3] = { x: -500, y: -500, z: 500 }; + points[0] = { x: -500, y: 500, z: 1000 }; + points[1] = { x: 500, y: 500, z: 1000 }; + points[2] = { x: 500, y: 500, z: 500 }; + points[3] = { x: -500, y: 500, z: 500 }; + + function project() { + for(var i = 0; i < points.length; i++) { + var p = points[i], + scale = fl / (fl + p.z); + + p.sx = p.x * scale; + p.sy = p.y * scale; + } + } + + function drawLine() { + var p = points[arguments[0]]; + context.moveTo(p.sx, p.sy); + + for(var i = 1; i < points.length; i++) { + p = points[arguments[i]]; + context.lineTo(p.sx, p.sy); + } + } + + function translateModel(x, y, z) { + for(var i = 0; i < points.length; i++) { + points[i].x += x; + points[i].y += y; + points[i].z += z; + } + needsUpdate = true; + } + + document.body.addEventListener("keydown", function(event) { + switch(event.keyCode) { + case 37: // left + translateModel(-20, 0, 0); + break; + case 39: // right + translateModel(20, 0, 0); + break; + case 38: // up + if(event.shiftKey) { + translateModel(0, 0, 20); + } + else { + translateModel(0, -20, 0); + } + case 40: // down + if(event.shiftKey) { + translateModel(0, 0, -20); + } + else { + translateModel(0, 20, 0); + } + } + }); + + update(); + + function update() { + if(needsUpdate) { + context.clearRect(-width / 2, -height / 2, width, height); + project(); + + context.beginPath(); + drawLine(0, 1, 2, 3, 0); + drawLine(4, 5, 6, 7, 4); + drawLine(0, 4); + drawLine(1, 5); + drawLine(2, 6); + drawLine(3, 7); + context.stroke(); + needsUpdate = false; + } + requestAnimationFrame(update); + } + +}; \ No newline at end of file From c1572bdb451846da5cd31b0d43da0ea903712726 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Sun, 11 May 2014 22:37:56 -0400 Subject: [PATCH 20/39] errors in episode 25 fixed --- episode25/main.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/episode25/main.js b/episode25/main.js index d68c67b..fc42656 100644 --- a/episode25/main.js +++ b/episode25/main.js @@ -13,10 +13,10 @@ window.onload = function() { points[1] = { x: 500, y: -500, z: 1000 }; points[2] = { x: 500, y: -500, z: 500 }; points[3] = { x: -500, y: -500, z: 500 }; - points[0] = { x: -500, y: 500, z: 1000 }; - points[1] = { x: 500, y: 500, z: 1000 }; - points[2] = { x: 500, y: 500, z: 500 }; - points[3] = { x: -500, y: 500, z: 500 }; + points[4] = { x: -500, y: 500, z: 1000 }; + points[5] = { x: 500, y: 500, z: 1000 }; + points[6] = { x: 500, y: 500, z: 500 }; + points[7] = { x: -500, y: 500, z: 500 }; function project() { for(var i = 0; i < points.length; i++) { @@ -32,7 +32,7 @@ window.onload = function() { var p = points[arguments[0]]; context.moveTo(p.sx, p.sy); - for(var i = 1; i < points.length; i++) { + for(var i = 1; i < arguments.length; i++) { p = points[arguments[i]]; context.lineTo(p.sx, p.sy); } @@ -62,6 +62,7 @@ window.onload = function() { else { translateModel(0, -20, 0); } + break; case 40: // down if(event.shiftKey) { translateModel(0, 0, -20); @@ -69,6 +70,7 @@ window.onload = function() { else { translateModel(0, 20, 0); } + break; } }); From c09482fff583139e26ad8d07cbc2e16c78e035de Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Mon, 26 May 2014 22:34:30 -0400 Subject: [PATCH 21/39] episode 26 --- episode26/2d.js | 33 +++++++++ episode26/index.html | 20 ++++++ episode26/main.js | 156 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 209 insertions(+) create mode 100644 episode26/2d.js create mode 100644 episode26/index.html create mode 100644 episode26/main.js diff --git a/episode26/2d.js b/episode26/2d.js new file mode 100644 index 0000000..4992c05 --- /dev/null +++ b/episode26/2d.js @@ -0,0 +1,33 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + point = { + x: 300, + y: 200 + }, + delta = 0.05; + + context.translate(width / 2, height / 2); + + update(); + + function update() { + context.clearRect(-width / 2, -height / 2, width, height); + + context.beginPath(); + context.arc(point.x, point.y, 20, 0, Math.PI * 2, false); + context.fill(); + + var cos = Math.cos(delta), + sin = Math.sin(delta), + x = point.x * cos - point.y * sin, + y = point.y * cos + point.x * sin; + + point.x = x; + point.y = y; + + requestAnimationFrame(update); + } +}; \ No newline at end of file diff --git a/episode26/index.html b/episode26/index.html new file mode 100644 index 0000000..719fb94 --- /dev/null +++ b/episode26/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/episode26/main.js b/episode26/main.js new file mode 100644 index 0000000..61da667 --- /dev/null +++ b/episode26/main.js @@ -0,0 +1,156 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight + fl = 300, + points = [], + needsUpdate = true, + centerZ = 1500; + + context.translate(width / 2, height / 2); + + points[0] = { x: -500, y: -500, z: 500 }; + points[1] = { x: 500, y: -500, z: 500 }; + points[2] = { x: 500, y: -500, z: -500 }; + points[3] = { x: -500, y: -500, z: -500 }; + points[4] = { x: -500, y: 500, z: 500 }; + points[5] = { x: 500, y: 500, z: 500 }; + points[6] = { x: 500, y: 500, z: -500 }; + points[7] = { x: -500, y: 500, z: -500 }; + + function project() { + for(var i = 0; i < points.length; i++) { + var p = points[i], + scale = fl / (fl + p.z + centerZ); + + p.sx = p.x * scale; + p.sy = p.y * scale; + } + } + + function drawLine() { + var p = points[arguments[0]]; + context.moveTo(p.sx, p.sy); + + for(var i = 1; i < arguments.length; i++) { + p = points[arguments[i]]; + context.lineTo(p.sx, p.sy); + } + } + + function translateModel(x, y, z) { + for(var i = 0; i < points.length; i++) { + points[i].x += x; + points[i].y += y; + points[i].z += z; + } + needsUpdate = true; + } + + function rotateX(angle) { + var cos = Math.cos(angle), + sin = Math.sin(angle); + + for(var i = 0; i < points.length; i++) { + var p = points[i], + y = p.y * cos - p.z * sin, + z = p.z * cos + p.y * sin; + p.y = y; + p.z = z; + } + needsUpdate = true; + } + + function rotateY(angle) { + var cos = Math.cos(angle), + sin = Math.sin(angle); + + for(var i = 0; i < points.length; i++) { + var p = points[i], + x = p.x * cos - p.z * sin, + z = p.z * cos + p.x * sin; + p.x = x; + p.z = z; + } + needsUpdate = true; + } + + function rotateZ(angle) { + var cos = Math.cos(angle), + sin = Math.sin(angle); + + for(var i = 0; i < points.length; i++) { + var p = points[i], + x = p.x * cos - p.y * sin, + y = p.y * cos + p.x * sin; + p.x = x; + p.y = y; + } + needsUpdate = true; + } + + document.body.addEventListener("keydown", function(event) { + switch(event.keyCode) { + case 37: // left + if(event.ctrlKey) { + rotateY(0.05); + } + else { + translateModel(-20, 0, 0); + } + break; + case 39: // right + if(event.ctrlKey) { + rotateY(-0.05); + } + else { + translateModel(20, 0, 0); + } + break; + case 38: // up + if(event.shiftKey) { + translateModel(0, 0, 20); + } + else if(event.ctrlKey) { + rotateX(0.05); + } + else { + translateModel(0, -20, 0); + } + break; + case 40: // down + if(event.shiftKey) { + translateModel(0, 0, -20); + } + else if(event.ctrlKey) { + rotateX(-0.05); + } + else { + translateModel(0, 20, 0); + } + break; + } + }); + + update(); + + function update() { + if(needsUpdate) { + context.clearRect(-width / 2, -height / 2, width, height); + project(); + + context.beginPath(); + drawLine(0, 1, 2, 3, 0); + drawLine(4, 5, 6, 7, 4); + drawLine(0, 4); + drawLine(1, 5); + drawLine(2, 6); + drawLine(3, 7); + context.stroke(); + needsUpdate = false; + } + requestAnimationFrame(update); + } + +}; \ No newline at end of file From f38edc30f0e1a2a49446f8d2a92e4ca3964ee3b6 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Mon, 29 Sep 2014 07:45:17 -0700 Subject: [PATCH 22/39] episode 27 --- episode27/index.html | 23 ++++++++++++++++++++++ episode27/main.js | 46 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 episode27/index.html create mode 100644 episode27/main.js diff --git a/episode27/index.html b/episode27/index.html new file mode 100644 index 0000000..5989d5a --- /dev/null +++ b/episode27/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/episode27/main.js b/episode27/main.js new file mode 100644 index 0000000..12399a3 --- /dev/null +++ b/episode27/main.js @@ -0,0 +1,46 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + + target = { + x: width, + y: Math.random() * height + }, + + position = { + x: 0, + y: Math.random() * height + }, + + ease = 0.1; + + update(); + + document.body.addEventListener("mousemove", function(event) { + target.x = event.clientX; + target.y = event.clientY; + }); + + function update() { + context.clearRect(0, 0, width, height); + + context.beginPath(); + context.arc(position.x, position.y, 10, 0, Math.PI * 2, false); + context.fill(); + + + var dx = target.x - position.x, + dy = target.y - position.y, + vx = dx * ease, + vy = dy * ease; + + position.x += vx; + position.y += vy; + + + requestAnimationFrame(update); + } + +}; \ No newline at end of file From 9e44f856b33f2d4da2dc9fd149eb36500f052990 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Sun, 5 Oct 2014 16:49:26 -0400 Subject: [PATCH 23/39] episode 28 --- episode28/click.js | 59 ++++++++++++++++++++ episode28/index.html | 24 +++++++++ episode28/main.js | 55 +++++++++++++++++++ episode28/steering.js | 38 +++++++++++++ episode28/string.js | 57 ++++++++++++++++++++ episode28/utils.js | 123 ++++++++++++++++++++++++++++++++++++++++++ episode28/wheel.png | Bin 0 -> 218849 bytes 7 files changed, 356 insertions(+) create mode 100644 episode28/click.js create mode 100644 episode28/index.html create mode 100644 episode28/main.js create mode 100644 episode28/steering.js create mode 100644 episode28/string.js create mode 100644 episode28/utils.js create mode 100644 episode28/wheel.png diff --git a/episode28/click.js b/episode28/click.js new file mode 100644 index 0000000..474b91a --- /dev/null +++ b/episode28/click.js @@ -0,0 +1,59 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + + target = { + x: width, + y: Math.random() * height + }, + + position = { + x: 0, + y: Math.random() * height + }, + + ease = 0.1, + easing = true; + + update(); + + document.body.addEventListener("click", function(event) { + target.x = event.clientX; + target.y = event.clientY; + if(!easing) { + easing = true; + update(); + } + }); + + function update() { + context.clearRect(0, 0, width, height); + + context.beginPath(); + context.arc(position.x, position.y, 10, 0, Math.PI * 2, false); + context.fill(); + + easing = easeTo(position, target, ease); + + if(easing) { + requestAnimationFrame(update); + } + } + + function easeTo(position, target, ease) { + var dx = target.x - position.x, + dy = target.y - position.y; + position.x += dx * ease; + position.y += dy * ease; + if(Math.abs(dx) < 0.1 && Math.abs(dy) < 0.1) { + position.x = target.x; + position.y = target.y; + console.log("stop"); + return false; + } + return true; + } + +}; \ No newline at end of file diff --git a/episode28/index.html b/episode28/index.html new file mode 100644 index 0000000..4f21121 --- /dev/null +++ b/episode28/index.html @@ -0,0 +1,24 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/episode28/main.js b/episode28/main.js new file mode 100644 index 0000000..b4eaa12 --- /dev/null +++ b/episode28/main.js @@ -0,0 +1,55 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + + target = { + x: width, + y: Math.random() * height + }, + + points = [], + numPoints = 100, + ease = 0.5; + + for(var i = 0; i < numPoints; i++) { + points.push({ + x: 0, + y: 0 + }); + } + + update(); + + document.body.addEventListener("mousemove", function(event) { + target.x = event.clientX; + target.y = event.clientY; + }); + + function update() { + context.clearRect(0, 0, width, height); + + var leader = { + x: target.x, + y: target.y + }; + + for(var i = 0; i < numPoints; i++) { + var point = points[i]; + point.x += (leader.x - point.x) * ease; + point.y += (leader.y - point.y) * ease; + + context.beginPath(); + context.arc(point.x, point.y, 10, 0, Math.PI * 2, false); + context.fill(); + + leader.x = point.x; + leader.y = point.y; + } + + + requestAnimationFrame(update); + } + +}; \ No newline at end of file diff --git a/episode28/steering.js b/episode28/steering.js new file mode 100644 index 0000000..a22ff37 --- /dev/null +++ b/episode28/steering.js @@ -0,0 +1,38 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + angle = 0, + targetAngle = 0, + ease = 0.05, + wheel; + + wheel = document.createElement("img"); + wheel.addEventListener("load", function() { + render(); + }); + wheel.src = "wheel.png"; + + + function render() { + context.clearRect(0, 0, width, height); + + angle += (targetAngle - angle) * ease; + + context.save(); + context.translate(width / 2, height / 2); + context.rotate(angle); + + context.drawImage(wheel, -wheel.width / 2, -wheel.height / 2); + + context.restore(); + requestAnimationFrame(render); + } + + document.body.addEventListener("mousemove", function(event) { + targetAngle = utils.map(event.clientX, 0, width, -Math.PI, Math.PI); + }); + + +}; \ No newline at end of file diff --git a/episode28/string.js b/episode28/string.js new file mode 100644 index 0000000..bce76bd --- /dev/null +++ b/episode28/string.js @@ -0,0 +1,57 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + + target = { + x: width, + y: Math.random() * height + }, + + points = [], + numPoints = 50, + ease = 0.25; + + for(var i = 0; i < numPoints; i++) { + points.push({ + x: 0, + y: 0 + }); + } + + update(); + + document.body.addEventListener("mousemove", function(event) { + target.x = event.clientX; + target.y = event.clientY; + }); + + function update() { + context.clearRect(0, 0, width, height); + + var leader = { + x: target.x, + y: target.y + }; + + context.beginPath(); + context.moveTo(leader.x, leader.y); + + for(var i = 0; i < numPoints; i++) { + var point = points[i]; + point.x += (leader.x - point.x) * ease; + point.y += (leader.y - point.y) * ease; + + context.lineTo(point.x, point.y); + + leader.x = point.x; + leader.y = point.y; + } + + context.stroke(); + + requestAnimationFrame(update); + } + +}; \ No newline at end of file diff --git a/episode28/utils.js b/episode28/utils.js new file mode 100644 index 0000000..3c0f824 --- /dev/null +++ b/episode28/utils.js @@ -0,0 +1,123 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + }, + + multicurve: function(points, context) { + var p0, p1, midx, midy; + + context.moveTo(points[0].x, points[0].y); + + for(var i = 1; i < points.length - 2; i += 1) { + p0 = points[i]; + p1 = points[i + 1]; + midx = (p0.x + p1.x) / 2; + midy = (p0.y + p1.y) / 2; + context.quadraticCurveTo(p0.x, p0.y, midx, midy); + } + p0 = points[points.length - 2]; + p1 = points[points.length - 1]; + context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); + } + +} \ No newline at end of file diff --git a/episode28/wheel.png b/episode28/wheel.png new file mode 100644 index 0000000000000000000000000000000000000000..0fed31d9355f17dd2efb857c5548c072909f677c GIT binary patch literal 218849 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�({_&6d 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�@})8=lxcwPk% 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 U=qAnmQ2+n{07*qoM6N<$f+k0(!~g&Q literal 0 HcmV?d00001 From b0633a6d0ca48660c6cfeafc9adac5925d5b59cf Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Mon, 3 Nov 2014 06:36:12 -0500 Subject: [PATCH 24/39] episode 29 and 30 --- episode29/index.html | 23 +++ episode29/main.js | 78 ++++++++++ episode29/penner_easing.as | 282 +++++++++++++++++++++++++++++++++++++ episode29/utils.js | 123 ++++++++++++++++ episode30/index.html | 23 +++ episode30/tweenBasic.js | 71 ++++++++++ episode30/tweenFull.js | 85 +++++++++++ episode30/tweenx.js | 69 +++++++++ 8 files changed, 754 insertions(+) create mode 100644 episode29/index.html create mode 100644 episode29/main.js create mode 100644 episode29/penner_easing.as create mode 100644 episode29/utils.js create mode 100644 episode30/index.html create mode 100644 episode30/tweenBasic.js create mode 100644 episode30/tweenFull.js create mode 100644 episode30/tweenx.js diff --git a/episode29/index.html b/episode29/index.html new file mode 100644 index 0000000..5989d5a --- /dev/null +++ b/episode29/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/episode29/main.js b/episode29/main.js new file mode 100644 index 0000000..36c55d0 --- /dev/null +++ b/episode29/main.js @@ -0,0 +1,78 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + start = { + x: 100, + y: 100 + }, + target = {}, + change = {}, + startTime, + duration = 1000; + + drawCircle(start.x, start.y); + + + document.body.addEventListener("click", function(event) { + target.x = event.clientX; + target.y = event.clientY; + change.x = target.x - start.x; + change.y = target.y - start.y; + startTime = new Date(); + update(); + }); + + function update() { + context.clearRect(0, 0, width, height); + + var time = new Date() - startTime; + if(time < duration) { + var x = easeInOutQuad(time, start.x, change.x, duration), + y = easeInOutQuad(time, start.y, change.y, duration); + drawCircle(x, y); + requestAnimationFrame(update); + } + else { + drawCircle(target.x, target.y); + start.x = target.x; + start.y = target.y; + } + + } + + // simple linear tweening - no easing + // t: current time, b: beginning value, c: change in value, d: duration + function linearTween(t, b, c, d) { + return c * t / d + b; + } + + ///////////// QUADRATIC EASING: t^2 /////////////////// + + // quadratic easing in - accelerating from zero velocity + // t: current time, b: beginning value, c: change in value, d: duration + // t and d can be in frames or seconds/milliseconds + function easeInQuad(t, b, c, d) { + return c*(t/=d)*t + b; + }; + + // quadratic easing out - decelerating to zero velocity + function easeOutQuad(t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + }; + + // quadratic easing in/out - acceleration until halfway, then deceleration + function easeInOutQuad(t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + }; + + + function drawCircle(x, y) { + context.beginPath(); + context.arc(x, y, 20, 0, Math.PI * 2, false); + context.fill(); + } + +}; \ No newline at end of file diff --git a/episode29/penner_easing.as b/episode29/penner_easing.as new file mode 100644 index 0000000..f96a2b1 --- /dev/null +++ b/episode29/penner_easing.as @@ -0,0 +1,282 @@ +/* + Easing Equations v1.5 + May 1, 2003 + (c) 2003 Robert Penner, all rights reserved. + This work is subject to the terms in http://www.robertpenner.com/easing_terms_of_use.html. + + These tweening functions provide different flavors of + math-based motion under a consistent API. + + Types of easing: + + Linear + Quadratic + Cubic + Quartic + Quintic + Sinusoidal + Exponential + Circular + Elastic + Back + Bounce + + Changes: + 1.5 - added bounce easing + 1.4 - added elastic and back easing + 1.3 - tweaked the exponential easing functions to make endpoints exact + 1.2 - inline optimizations (changing t and multiplying in one step)--thanks to Tatsuo Kato for the idea + + Discussed in Chapter 7 of + Robert Penner's Programming Macromedia Flash MX + (including graphs of the easing equations) + + http://www.robertpenner.com/profmx + http://www.amazon.com/exec/obidos/ASIN/0072223561/robertpennerc-20 +*/ + + +// simple linear tweening - no easing +// t: current time, b: beginning value, c: change in value, d: duration +Math.linearTween = function (t, b, c, d) { + return c*t/d + b; +}; + + + ///////////// QUADRATIC EASING: t^2 /////////////////// + +// quadratic easing in - accelerating from zero velocity +// t: current time, b: beginning value, c: change in value, d: duration +// t and d can be in frames or seconds/milliseconds +Math.easeInQuad = function (t, b, c, d) { + return c*(t/=d)*t + b; +}; + +// quadratic easing out - decelerating to zero velocity +Math.easeOutQuad = function (t, b, c, d) { + return -c *(t/=d)*(t-2) + b; +}; + +// quadratic easing in/out - acceleration until halfway, then deceleration +Math.easeInOutQuad = function (t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; +}; + + + ///////////// CUBIC EASING: t^3 /////////////////////// + +// cubic easing in - accelerating from zero velocity +// t: current time, b: beginning value, c: change in value, d: duration +// t and d can be frames or seconds/milliseconds +Math.easeInCubic = function (t, b, c, d) { + return c*(t/=d)*t*t + b; +}; + +// cubic easing out - decelerating to zero velocity +Math.easeOutCubic = function (t, b, c, d) { + return c*((t=t/d-1)*t*t + 1) + b; +}; + +// cubic easing in/out - acceleration until halfway, then deceleration +Math.easeInOutCubic = function (t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t + b; + return c/2*((t-=2)*t*t + 2) + b; +}; + + + ///////////// QUARTIC EASING: t^4 ///////////////////// + +// quartic easing in - accelerating from zero velocity +// t: current time, b: beginning value, c: change in value, d: duration +// t and d can be frames or seconds/milliseconds +Math.easeInQuart = function (t, b, c, d) { + return c*(t/=d)*t*t*t + b; +}; + +// quartic easing out - decelerating to zero velocity +Math.easeOutQuart = function (t, b, c, d) { + return -c * ((t=t/d-1)*t*t*t - 1) + b; +}; + +// quartic easing in/out - acceleration until halfway, then deceleration +Math.easeInOutQuart = function (t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t + b; + return -c/2 * ((t-=2)*t*t*t - 2) + b; +}; + + + ///////////// QUINTIC EASING: t^5 //////////////////// + +// quintic easing in - accelerating from zero velocity +// t: current time, b: beginning value, c: change in value, d: duration +// t and d can be frames or seconds/milliseconds +Math.easeInQuint = function (t, b, c, d) { + return c*(t/=d)*t*t*t*t + b; +}; + +// quintic easing out - decelerating to zero velocity +Math.easeOutQuint = function (t, b, c, d) { + return c*((t=t/d-1)*t*t*t*t + 1) + b; +}; + +// quintic easing in/out - acceleration until halfway, then deceleration +Math.easeInOutQuint = function (t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; + return c/2*((t-=2)*t*t*t*t + 2) + b; +}; + + + + ///////////// SINUSOIDAL EASING: sin(t) /////////////// + +// sinusoidal easing in - accelerating from zero velocity +// t: current time, b: beginning value, c: change in position, d: duration +Math.easeInSine = function (t, b, c, d) { + return -c * Math.cos(t/d * (Math.PI/2)) + c + b; +}; + +// sinusoidal easing out - decelerating to zero velocity +Math.easeOutSine = function (t, b, c, d) { + return c * Math.sin(t/d * (Math.PI/2)) + b; +}; + +// sinusoidal easing in/out - accelerating until halfway, then decelerating +Math.easeInOutSine = function (t, b, c, d) { + return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; +}; + + + ///////////// EXPONENTIAL EASING: 2^t ///////////////// + +// exponential easing in - accelerating from zero velocity +// t: current time, b: beginning value, c: change in position, d: duration +Math.easeInExpo = function (t, b, c, d) { + return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; +}; + +// exponential easing out - decelerating to zero velocity +Math.easeOutExpo = function (t, b, c, d) { + return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; +}; + +// exponential easing in/out - accelerating until halfway, then decelerating +Math.easeInOutExpo = function (t, b, c, d) { + if (t==0) return b; + if (t==d) return b+c; + if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; + return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; +}; + + + /////////// CIRCULAR EASING: sqrt(1-t^2) ////////////// + +// circular easing in - accelerating from zero velocity +// t: current time, b: beginning value, c: change in position, d: duration +Math.easeInCirc = function (t, b, c, d) { + return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; +}; + +// circular easing out - decelerating to zero velocity +Math.easeOutCirc = function (t, b, c, d) { + return c * Math.sqrt(1 - (t=t/d-1)*t) + b; +}; + +// circular easing in/out - acceleration until halfway, then deceleration +Math.easeInOutCirc = function (t, b, c, d) { + if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; + return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; +}; + + + /////////// ELASTIC EASING: exponentially decaying sine wave ////////////// + +// t: current time, b: beginning value, c: change in value, d: duration, a: amplitude (optional), p: period (optional) +// t and d can be in frames or seconds/milliseconds + +Math.easeInElastic = function (t, b, c, d, a, p) { + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; +}; + +Math.easeOutElastic = function (t, b, c, d, a, p) { + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; +}; + +Math.easeInOutElastic = function (t, b, c, d, a, p) { + if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; +}; + + + /////////// BACK EASING: overshooting cubic easing: (s+1)*t^3 - s*t^2 ////////////// + +// back easing in - backtracking slightly, then reversing direction and moving to target +// t: current time, b: beginning value, c: change in value, d: duration, s: overshoot amount (optional) +// t and d can be in frames or seconds/milliseconds +// s controls the amount of overshoot: higher s means greater overshoot +// s has a default value of 1.70158, which produces an overshoot of 10 percent +// s==0 produces cubic easing with no overshoot +Math.easeInBack = function (t, b, c, d, s) { + if (s == undefined) s = 1.70158; + return c*(t/=d)*t*((s+1)*t - s) + b; +}; + +// back easing out - moving towards target, overshooting it slightly, then reversing and coming back to target +Math.easeOutBack = function (t, b, c, d, s) { + if (s == undefined) s = 1.70158; + return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; +}; + +// back easing in/out - backtracking slightly, then reversing direction and moving to target, +// then overshooting target, reversing, and finally coming back to target +Math.easeInOutBack = function (t, b, c, d, s) { + if (s == undefined) s = 1.70158; + if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; + return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; +}; + + + /////////// BOUNCE EASING: exponentially decaying parabolic bounce ////////////// + +// bounce easing in +// t: current time, b: beginning value, c: change in position, d: duration +Math.easeInBounce = function (t, b, c, d) { + return c - Math.easeOutBounce (d-t, 0, c, d) + b; +}; + +// bounce easing out +Math.easeOutBounce = function (t, b, c, d) { + if ((t/=d) < (1/2.75)) { + return c*(7.5625*t*t) + b; + } else if (t < (2/2.75)) { + return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; + } else if (t < (2.5/2.75)) { + return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; + } else { + return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; + } +}; + +// bounce easing in/out +Math.easeInOutBounce = function (t, b, c, d) { + if (t < d/2) return Math.easeInBounce (t*2, 0, c, d) * .5 + b; + return Math.easeOutBounce (t*2-d, 0, c, d) * .5 + c*.5 + b; +}; + + +//trace (">> Penner easing equations loaded"); + + + + + + diff --git a/episode29/utils.js b/episode29/utils.js new file mode 100644 index 0000000..3c0f824 --- /dev/null +++ b/episode29/utils.js @@ -0,0 +1,123 @@ +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + }, + + multicurve: function(points, context) { + var p0, p1, midx, midy; + + context.moveTo(points[0].x, points[0].y); + + for(var i = 1; i < points.length - 2; i += 1) { + p0 = points[i]; + p1 = points[i + 1]; + midx = (p0.x + p1.x) / 2; + midy = (p0.y + p1.y) / 2; + context.quadraticCurveTo(p0.x, p0.y, midx, midy); + } + p0 = points[points.length - 2]; + p1 = points[points.length - 1]; + context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); + } + +} \ No newline at end of file diff --git a/episode30/index.html b/episode30/index.html new file mode 100644 index 0000000..b827fdb --- /dev/null +++ b/episode30/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/episode30/tweenBasic.js b/episode30/tweenBasic.js new file mode 100644 index 0000000..cdaa484 --- /dev/null +++ b/episode30/tweenBasic.js @@ -0,0 +1,71 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + ball = { + x: 100, + y: 100, + alpha: 1 + }; + + tween(ball, "alpha", 0, 1000, easeInOutQuad); + + function tween(obj, prop, target, duration, easingFunc) { + var start = obj[prop], + change = target - start, + startTime = new Date(); + + update(); + + function update() { + var time = new Date() - startTime; + if(time < duration) { + obj[prop] = easingFunc(time, start, change, duration); + requestAnimationFrame(update); + } + else { + time = duration; + obj[prop] = easingFunc(time, start, change, duration); + } + render(); + } + } + + + function render() { + context.clearRect(0, 0, width, height); + context.globalAlpha = ball.alpha; + context.beginPath(); + context.arc(ball.x, ball.y, 20, 0, Math.PI * 2, false); + context.fill(); + } + + + // simple linear tweening - no easing + // t: current time, b: beginning value, c: change in value, d: duration + function linearTween(t, b, c, d) { + return c * t / d + b; + } + + ///////////// QUADRATIC EASING: t^2 /////////////////// + + // quadratic easing in - accelerating from zero velocity + // t: current time, b: beginning value, c: change in value, d: duration + // t and d can be in frames or seconds/milliseconds + function easeInQuad(t, b, c, d) { + return c*(t/=d)*t + b; + }; + + // quadratic easing out - decelerating to zero velocity + function easeOutQuad(t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + }; + + // quadratic easing in/out - acceleration until halfway, then deceleration + function easeInOutQuad(t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + }; +}; \ No newline at end of file diff --git a/episode30/tweenFull.js b/episode30/tweenFull.js new file mode 100644 index 0000000..e7599f7 --- /dev/null +++ b/episode30/tweenFull.js @@ -0,0 +1,85 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + ball = { + x: 100, + y: 100, + alpha: 1 + }; + + tween(ball, {x: 900, y: 700, alpha: 0 }, 1000, easeInOutQuad, render, tweenBack); + + function tweenBack() { + tween(ball, {x: 100, y: 100, alpha: 1 }, 1000, easeInOutQuad, render, render); + } + + function tween(obj, props, duration, easingFunc, onProgress, onComplete) { + var starts = {}, + changes = {}, + startTime = new Date(); + + for(var prop in props) { + starts[prop] = obj[prop]; + changes[prop] = props[prop] - starts[prop]; + } + + update(); + + function update() { + var time = new Date() - startTime; + if(time < duration) { + for(var prop in props) { + obj[prop] = easingFunc(time, starts[prop], changes[prop], duration); + } + onProgress(); + requestAnimationFrame(update); + } + else { + time = duration; + for(var prop in props) { + obj[prop] = easingFunc(time, starts[prop], changes[prop], duration); + } + onComplete(); + } + } + } + + + function render() { + context.clearRect(0, 0, width, height); + context.globalAlpha = ball.alpha; + context.beginPath(); + context.arc(ball.x, ball.y, 20, 0, Math.PI * 2, false); + context.fill(); + } + + + // simple linear tweening - no easing + // t: current time, b: beginning value, c: change in value, d: duration + function linearTween(t, b, c, d) { + return c * t / d + b; + } + + ///////////// QUADRATIC EASING: t^2 /////////////////// + + // quadratic easing in - accelerating from zero velocity + // t: current time, b: beginning value, c: change in value, d: duration + // t and d can be in frames or seconds/milliseconds + function easeInQuad(t, b, c, d) { + return c*(t/=d)*t + b; + }; + + // quadratic easing out - decelerating to zero velocity + function easeOutQuad(t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + }; + + // quadratic easing in/out - acceleration until halfway, then deceleration + function easeInOutQuad(t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + }; +}; \ No newline at end of file diff --git a/episode30/tweenx.js b/episode30/tweenx.js new file mode 100644 index 0000000..b2c2642 --- /dev/null +++ b/episode30/tweenx.js @@ -0,0 +1,69 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + ball = { + x: 100, + y: 100 + }; + + tweenX(ball, 800, 1000, easeInOutQuad); + + function tweenX(obj, targetX, duration, easingFunc) { + var startX = obj.x, + changeX = targetX - startX, + startTime = new Date(); + + update(); + + function update() { + var time = new Date() - startTime; + if(time < duration) { + obj.x = easingFunc(time, startX, changeX, duration); + requestAnimationFrame(update); + } + else { + time = duration; + obj.x = easingFunc(time, startX, changeX, duration); + } + render(); + } + } + + + function render() { + context.clearRect(0, 0, width, height); + context.beginPath(); + context.arc(ball.x, ball.y, 20, 0, Math.PI * 2, false); + context.fill(); + } + + + // simple linear tweening - no easing + // t: current time, b: beginning value, c: change in value, d: duration + function linearTween(t, b, c, d) { + return c * t / d + b; + } + + ///////////// QUADRATIC EASING: t^2 /////////////////// + + // quadratic easing in - accelerating from zero velocity + // t: current time, b: beginning value, c: change in value, d: duration + // t and d can be in frames or seconds/milliseconds + function easeInQuad(t, b, c, d) { + return c*(t/=d)*t + b; + }; + + // quadratic easing out - decelerating to zero velocity + function easeOutQuad(t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + }; + + // quadratic easing in/out - acceleration until halfway, then deceleration + function easeInOutQuad(t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + }; +}; \ No newline at end of file From fade35735e56f7036467480b8aedd08eca6cdf56 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Thu, 27 Nov 2014 21:22:07 -0500 Subject: [PATCH 25/39] episode 32 --- episode32/index.html | 23 ++++++++ episode32/main.js | 55 +++++++++++++++++ episode32/main_interactive.js | 108 ++++++++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+) create mode 100644 episode32/index.html create mode 100644 episode32/main.js create mode 100644 episode32/main_interactive.js diff --git a/episode32/index.html b/episode32/index.html new file mode 100644 index 0000000..5989d5a --- /dev/null +++ b/episode32/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/episode32/main.js b/episode32/main.js new file mode 100644 index 0000000..fd14089 --- /dev/null +++ b/episode32/main.js @@ -0,0 +1,55 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var p0 = { + x: 100, + y: 100 + }, + p1 = { + x: 500, + y: 500 + }, + p2 = { + x: 600, + y: 50 + }, + p3 = { + x: 80, + y: 600 + }; + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.moveTo(p2.x, p2.y); + context.lineTo(p3.x, p3.y); + context.stroke(); + + var intersect = lineIntersect(p0, p1, p2, p3); + + context.beginPath(); + context.arc(intersect.x, intersect.y, 20, 0, Math.PI * 2, false); + context.stroke(); + + + + function lineIntersect(p0, p1, p2, p3) { + var A1 = p1.y - p0.y, + B1 = p0.x - p1.x, + C1 = A1 * p0.x + B1 * p0.y, + A2 = p3.y - p2.y, + B2 = p2.x - p3.x, + C2 = A2 * p2.x + B2 * p2.y, + denominator = A1 * B2 - A2 * B1; + + return { + x: (B2 * C1 - B1 * C2) / denominator, + y: (A1 * C2 - A2 * C1) / denominator + } + } + +}; \ No newline at end of file diff --git a/episode32/main_interactive.js b/episode32/main_interactive.js new file mode 100644 index 0000000..2f67db2 --- /dev/null +++ b/episode32/main_interactive.js @@ -0,0 +1,108 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var p0 = { + x: 100, + y: 100 + }, + p1 = { + x: 500, + y: 500 + }, + p2 = { + x: 600, + y: 50 + }, + p3 = { + x: 80, + y: 600 + }, + clickPoint; + + document.body.addEventListener("mousedown", onMouseDown); + + function onMouseDown(event) { + clickPoint = getClickPoint(event.clientX, event.clientY); + if(clickPoint) { + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + } + } + + function onMouseMove(event) { + clickPoint.x = event.clientX; + clickPoint.y = event.clientY; + render(); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + } + + function getClickPoint(x, y) { + var points = [p0, p1, p2, p3]; + for(var i = 0; i < points.length; i++) { + var p = points[i], + dx = p.x - x, + dy = p.y - y, + dist = Math.sqrt(dx * dx + dy * dy); + if(dist < 10) { + return p; + } + + } + } + + + render(); + + function render() { + context.clearRect(0, 0, width, height); + + drawPoint(p0); + drawPoint(p1); + drawPoint(p2); + drawPoint(p3); + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.moveTo(p2.x, p2.y); + context.lineTo(p3.x, p3.y); + context.stroke(); + + var intersect = lineIntersect(p0, p1, p2, p3); + + context.beginPath(); + context.arc(intersect.x, intersect.y, 20, 0, Math.PI * 2, false); + context.stroke(); + } + + function drawPoint(p) { + context.beginPath(); + context.arc(p.x, p.y, 10, 0, Math.PI * 2, false); + context.fill(); + } + + + function lineIntersect(p0, p1, p2, p3) { + var A1 = p1.y - p0.y, + B1 = p0.x - p1.x, + C1 = A1 * p0.x + B1 * p0.y, + A2 = p3.y - p2.y, + B2 = p2.x - p3.x, + C2 = A2 * p2.x + B2 * p2.y, + denominator = A1 * B2 - A2 * B1; + + return { + x: (B2 * C1 - B1 * C2) / denominator, + y: (A1 * C2 - A2 * C1) / denominator + } + } + +}; \ No newline at end of file From e258c0ccac45fc656294c3a7e446fd29f45c2007 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Mon, 1 Dec 2014 23:19:47 -0500 Subject: [PATCH 26/39] ep33 --- episode33/index.html | 23 ++++++ episode33/main_interactive.js | 145 ++++++++++++++++++++++++++++++++++ episode33/parallel.js | 59 ++++++++++++++ 3 files changed, 227 insertions(+) create mode 100644 episode33/index.html create mode 100644 episode33/main_interactive.js create mode 100644 episode33/parallel.js diff --git a/episode33/index.html b/episode33/index.html new file mode 100644 index 0000000..0c87fbf --- /dev/null +++ b/episode33/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/episode33/main_interactive.js b/episode33/main_interactive.js new file mode 100644 index 0000000..4017e74 --- /dev/null +++ b/episode33/main_interactive.js @@ -0,0 +1,145 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var p0 = { + x: 100, + y: 100 + }, + p1 = { + x: 500, + y: 500 + }, + p2 = { + x: 600, + y: 50 + }, + p3 = { + x: 80, + y: 600 + }, + clickPoint; + + document.body.addEventListener("mousedown", onMouseDown); + + function onMouseDown(event) { + clickPoint = getClickPoint(event.clientX, event.clientY); + if(clickPoint) { + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + } + } + + function onMouseMove(event) { + clickPoint.x = event.clientX; + clickPoint.y = event.clientY; + render(); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + } + + function getClickPoint(x, y) { + var points = [p0, p1, p2, p3]; + for(var i = 0; i < points.length; i++) { + var p = points[i], + dx = p.x - x, + dy = p.y - y, + dist = Math.sqrt(dx * dx + dy * dy); + if(dist < 10) { + return p; + } + + } + } + + + render(); + + function render() { + context.clearRect(0, 0, width, height); + + drawPoint(p0); + drawPoint(p1); + drawPoint(p2); + drawPoint(p3); + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.moveTo(p2.x, p2.y); + context.lineTo(p3.x, p3.y); + context.stroke(); + + var intersect = segmentIntersect(p0, p1, p2, p3); + if(intersect) { + context.beginPath(); + context.arc(intersect.x, intersect.y, 20, 0, Math.PI * 2, false); + context.stroke(); + } + } + + function drawPoint(p) { + context.beginPath(); + context.arc(p.x, p.y, 10, 0, Math.PI * 2, false); + context.fill(); + } + + + function lineIntersect(p0, p1, p2, p3) { + var A1 = p1.y - p0.y, + B1 = p0.x - p1.x, + C1 = A1 * p0.x + B1 * p0.y, + A2 = p3.y - p2.y, + B2 = p2.x - p3.x, + C2 = A2 * p2.x + B2 * p2.y, + denominator = A1 * B2 - A2 * B1; + + if(denominator == 0) { + return null; + } + + return { + x: (B2 * C1 - B1 * C2) / denominator, + y: (A1 * C2 - A2 * C1) / denominator + } + } + + + function segmentIntersect(p0, p1, p2, p3) { + var A1 = p1.y - p0.y, + B1 = p0.x - p1.x, + C1 = A1 * p0.x + B1 * p0.y, + A2 = p3.y - p2.y, + B2 = p2.x - p3.x, + C2 = A2 * p2.x + B2 * p2.y, + denominator = A1 * B2 - A2 * B1; + + if(denominator == 0) { + return null; + } + + var intersectX = (B2 * C1 - B1 * C2) / denominator, + intersectY = (A1 * C2 - A2 * C1) / denominator, + rx0 = (intersectX - p0.x) / (p1.x - p0.x), + ry0 = (intersectY - p0.y) / (p1.y - p0.y), + rx1 = (intersectX - p2.x) / (p3.x - p2.x), + ry1 = (intersectY - p2.y) / (p3.y - p2.y); + + if(((rx0 >= 0 && rx0 <= 1) || (ry0 >= 0 && ry0 <= 1)) && + ((rx1 >= 0 && rx1 <= 1) || (ry1 >= 0 && ry1 <= 1))) { + return { + x: intersectX, + y: intersectY + }; + } + else { + return null; + } + } +}; \ No newline at end of file diff --git a/episode33/parallel.js b/episode33/parallel.js new file mode 100644 index 0000000..7b95020 --- /dev/null +++ b/episode33/parallel.js @@ -0,0 +1,59 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var p0 = { + x: 100, + y: 100 + }, + p1 = { + x: 500, + y: 100 + }, + p2 = { + x: 100, + y: 200 + }, + p3 = { + x: 500, + y: 200 + }; + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.moveTo(p2.x, p2.y); + context.lineTo(p3.x, p3.y); + context.stroke(); + + var intersect = lineIntersect(p0, p1, p2, p3); + if(intersect) { + context.beginPath(); + context.arc(intersect.x, intersect.y, 20, 0, Math.PI * 2, false); + context.stroke(); + } + + + function lineIntersect(p0, p1, p2, p3) { + var A1 = p1.y - p0.y, + B1 = p0.x - p1.x, + C1 = A1 * p0.x + B1 * p0.y, + A2 = p3.y - p2.y, + B2 = p2.x - p3.x, + C2 = A2 * p2.x + B2 * p2.y, + denominator = A1 * B2 - A2 * B1; + + if(denominator == 0) { + return null; + } + + return { + x: (B2 * C1 - B1 * C2) / denominator, + y: (A1 * C2 - A2 * C1) / denominator + } + } + +}; \ No newline at end of file From 4ca00adfdafc0523f2373bf6e593c610d54bbd55 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Mon, 23 Feb 2015 06:20:58 -0500 Subject: [PATCH 27/39] episode 34 and 35 code --- episode34/index.html | 23 ++++++ episode34/particles.js | 108 +++++++++++++++++++++++++++ episode34/shapes.js | 149 ++++++++++++++++++++++++++++++++++++++ episode35/index.html | 23 ++++++ episode35/koch.js | 62 ++++++++++++++++ episode35/kochanimated.js | 78 ++++++++++++++++++++ episode35/sierpinski.js | 56 ++++++++++++++ episode35/twist.js | 71 ++++++++++++++++++ 8 files changed, 570 insertions(+) create mode 100644 episode34/index.html create mode 100644 episode34/particles.js create mode 100644 episode34/shapes.js create mode 100644 episode35/index.html create mode 100644 episode35/koch.js create mode 100644 episode35/kochanimated.js create mode 100644 episode35/sierpinski.js create mode 100644 episode35/twist.js diff --git a/episode34/index.html b/episode34/index.html new file mode 100644 index 0000000..a65ae57 --- /dev/null +++ b/episode34/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/episode34/particles.js b/episode34/particles.js new file mode 100644 index 0000000..6dba81e --- /dev/null +++ b/episode34/particles.js @@ -0,0 +1,108 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var particle = { + x: width / 2, + y: height / 2, + vx: Math.random() * 10 - 5, + vy: Math.random() * 10 - 5 + }, + + lines = []; + + for(var i = 0; i < 10; i++) { + lines[i] = { + p0: { + x: Math.random() * width, + y: Math.random() * height + }, + p1: { + x: Math.random() * width, + y: Math.random() * height + } + } + } + + update(); + + function update() { + context.clearRect(0, 0, width, height); + drawLines(); + + var p0 = { + x: particle.x, + y: particle.y + }; + particle.x += particle.vx; + particle.y += particle.vy; + context.fillRect(particle.x - 2, particle.y - 2, 4, 4); + + var p1 = { + x: particle.x, + y: particle.y + }; + + + for(var i = 0; i < lines.length; i++) { + var p2 = lines[i].p0, + p3 = lines[i].p1; + + var intersect = segmentIntersect(p0, p1, p2, p3); + if(intersect) { + context.beginPath(); + context.strokeStyle = "red"; + context.arc(intersect.x, intersect.y, 20, 0, Math.PI * 2, false); + context.stroke(); + return; + } + } + + + requestAnimationFrame(update); + } + + function drawLines() { + context.beginPath(); + for(var i = 0; i < lines.length; i++) { + context.moveTo(lines[i].p0.x, lines[i].p0.y); + context.lineTo(lines[i].p1.x, lines[i].p1.y); + } + context.stroke(); + } + + function segmentIntersect(p0, p1, p2, p3) { + var A1 = p1.y - p0.y, + B1 = p0.x - p1.x, + C1 = A1 * p0.x + B1 * p0.y, + A2 = p3.y - p2.y, + B2 = p2.x - p3.x, + C2 = A2 * p2.x + B2 * p2.y, + denominator = A1 * B2 - A2 * B1; + + if(denominator == 0) { + return null; + } + + var intersectX = (B2 * C1 - B1 * C2) / denominator, + intersectY = (A1 * C2 - A2 * C1) / denominator, + rx0 = (intersectX - p0.x) / (p1.x - p0.x), + ry0 = (intersectY - p0.y) / (p1.y - p0.y), + rx1 = (intersectX - p2.x) / (p3.x - p2.x), + ry1 = (intersectY - p2.y) / (p3.y - p2.y); + + if(((rx0 >= 0 && rx0 <= 1) || (ry0 >= 0 && ry0 <= 1)) && + ((rx1 >= 0 && rx1 <= 1) || (ry1 >= 0 && ry1 <= 1))) { + return { + x: intersectX, + y: intersectY + }; + } + else { + return null; + } + } +}; \ No newline at end of file diff --git a/episode34/shapes.js b/episode34/shapes.js new file mode 100644 index 0000000..3109bf4 --- /dev/null +++ b/episode34/shapes.js @@ -0,0 +1,149 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + + + var star0 = { + x: 200, + y: 200, + points: [ + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 } + ], + offset: [ + { x: 100, y: 0}, + { x: 40, y: 29}, + { x: 31, y: 95}, + { x: -15, y: 48}, + { x: -81, y: 59}, + { x: -50, y: 0}, + { x: -81, y: -59}, + { x: -15, y: -48}, + { x: 31, y: -95}, + { x: 40, y: -29} + ] + }; + var star1 = { + x: 600, + y: 500, + points: [ + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 } + ], + offset: [ + { x: 100, y: 0}, + { x: 40, y: 29}, + { x: 31, y: 95}, + { x: -15, y: 48}, + { x: -81, y: 59}, + { x: -50, y: 0}, + { x: -81, y: -59}, + { x: -15, y: -48}, + { x: 31, y: -95}, + { x: 40, y: -29} + ] + }; + + document.body.addEventListener("mousemove", function(event) { + context.clearRect(0, 0, width, height); + star0.x = event.clientX; + star0.y = event.clientY; + updateStar(star0); + updateStar(star1); + if(checkStarCollision(star0, star1)) { + context.fillStyle = "red"; + } + else { + context.fillStyle = "black"; + } + drawStar(star0); + drawStar(star1); + }); + + function checkStarCollision(starA, starB) { + for(var i = 0; i < starA.points.length; i++) { + var p0 = starA.points[i], + p1 = starA.points[(i + 1) % starA.points.length]; + + for(var j = 0; j < starB.points.length; j++) { + var p2 = starB.points[j], + p3 = starB.points[(j + 1) % starB.points.length]; + + if(segmentIntersect(p0, p1, p2, p3)) { + return true; + } + } + } + return false; + } + + + function updateStar(star) { + for(var i = 0; i < star.points.length; i++) { + star.points[i].x = star.x + star.offset[i].x; + star.points[i].y = star.y + star.offset[i].y; + } + } + + function drawStar(star) { + context.beginPath(); + context.moveTo(star.points[0].x, star.points[0].y); + for(var i = 1; i < star.points.length; i++) { + context.lineTo(star.points[i].x, star.points[i].y); + } + context.closePath(); + context.fill(); + } + + function segmentIntersect(p0, p1, p2, p3) { + var A1 = p1.y - p0.y, + B1 = p0.x - p1.x, + C1 = A1 * p0.x + B1 * p0.y, + A2 = p3.y - p2.y, + B2 = p2.x - p3.x, + C2 = A2 * p2.x + B2 * p2.y, + denominator = A1 * B2 - A2 * B1; + + if(denominator == 0) { + return null; + } + + var intersectX = (B2 * C1 - B1 * C2) / denominator, + intersectY = (A1 * C2 - A2 * C1) / denominator, + rx0 = (intersectX - p0.x) / (p1.x - p0.x), + ry0 = (intersectY - p0.y) / (p1.y - p0.y), + rx1 = (intersectX - p2.x) / (p3.x - p2.x), + ry1 = (intersectY - p2.y) / (p3.y - p2.y); + + if(((rx0 >= 0 && rx0 <= 1) || (ry0 >= 0 && ry0 <= 1)) && + ((rx1 >= 0 && rx1 <= 1) || (ry1 >= 0 && ry1 <= 1))) { + return { + x: intersectX, + y: intersectY + }; + } + else { + return null; + } + } +}; \ No newline at end of file diff --git a/episode35/index.html b/episode35/index.html new file mode 100644 index 0000000..6a8460a --- /dev/null +++ b/episode35/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/episode35/koch.js b/episode35/koch.js new file mode 100644 index 0000000..938491c --- /dev/null +++ b/episode35/koch.js @@ -0,0 +1,62 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var p0 = { + x: 0, + y: -321 + }, + p1 = { + x: 278, + y: 160 + }, + p2 = { + x: -278, + y: 160 + }; + context.translate(width / 2, height / 2); + + koch(p0, p1, 5); + koch(p1, p2, 5); + koch(p2, p0, 5); + + function koch(p0, p1, limit) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y, + dist = Math.sqrt(dx * dx + dy * dy), + unit = dist / 3, + angle = Math.atan2(dy, dx), + pA = { + x: p0.x + dx / 3, + y: p0.y + dy / 3 + }, + pC = { + x: p1.x - dx / 3, + y: p1.y - dy / 3 + }, + pB = { + x: pA.x + Math.cos(angle - Math.PI / 3) * unit, + y: pA.y + Math.sin(angle - Math.PI / 3) * unit + }; + + if(limit > 0) { + koch(p0, pA, limit - 1); + koch(pA, pB, limit - 1); + koch(pB, pC, limit - 1); + koch(pC, p1, limit - 1); + } + else { + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(pA.x, pA.y); + context.lineTo(pB.x, pB.y); + context.lineTo(pC.x, pC.y); + context.lineTo(p1.x, p1.y); + context.stroke(); + } + } + +}; \ No newline at end of file diff --git a/episode35/kochanimated.js b/episode35/kochanimated.js new file mode 100644 index 0000000..3dbe089 --- /dev/null +++ b/episode35/kochanimated.js @@ -0,0 +1,78 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + + + var p0 = { + x: 0, + y: -321 + }, + p1 = { + x: 278, + y: 160 + }, + p2 = { + x: -278, + y: 160 + }; + + var a = 0, + t; + + draw(); + + function draw() { + t = 1 / 3 + Math.sin(a += 0.02) * 1/6; + context.clearRect(0, 0, width, height); + context.save(); + context.translate(width / 2, height / 2); + koch(p0, p1, 5); + koch(p1, p2, 5); + koch(p2, p0, 5); + context.restore(); + requestAnimationFrame(draw); + } + + function koch(p0, p1, limit) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y, + dist = Math.sqrt(dx * dx + dy * dy), + unit = dist * t, + angle = Math.atan2(dy, dx), + pA = { + x: p0.x + dx * t, + y: p0.y + dy * t + }, + pC = { + x: p1.x - dx * t, + y: p1.y - dy * t + }, + pB = { + x: pA.x + Math.cos(angle - Math.PI * t) * unit, + y: pA.y + Math.sin(angle - Math.PI * t) * unit + }; + + + if(limit > 0) { + koch(p0, pA, limit - 1); + koch(pA, pB, limit - 1); + koch(pB, pC, limit - 1); + koch(pC, p1, limit - 1); + } + else { + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(pA.x, pA.y); + context.lineTo(pB.x, pB.y); + context.lineTo(pC.x, pC.y); + context.lineTo(p1.x, p1.y); + context.stroke(); + } + } + + +}; \ No newline at end of file diff --git a/episode35/sierpinski.js b/episode35/sierpinski.js new file mode 100644 index 0000000..5dabe8f --- /dev/null +++ b/episode35/sierpinski.js @@ -0,0 +1,56 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + context.translate(width / 2, height / 2); + var p0 = { + x: 0, + y: -321 + }, + p1 = { + x: 278, + y: 160 + }, + p2 = { + x: -278, + y: 160 + }; + + sierpinski(p0, p1, p2, 8); + + function sierpinski(p0, p1, p2, limit) { + if(limit > 0) { + var pA = { + x: (p0.x + p1.x) / 2, + y: (p0.y + p1.y) / 2 + }, + pB = { + x: (p1.x + p2.x) / 2, + y: (p1.y + p2.y) / 2 + }, + pC = { + x: (p2.x + p0.x) / 2, + y: (p2.y + p0.y) / 2 + }; + + sierpinski(p0, pA, pC, limit - 1); + sierpinski(pA, p1, pB, limit - 1); + sierpinski(pC, pB, p2, limit - 1); + } + else { + drawTriangle(p0, p1, p2); + } + } + + function drawTriangle(p0, p1, p2) { + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.lineTo(p2.x, p2.y); + context.fill(); + } + +}; \ No newline at end of file diff --git a/episode35/twist.js b/episode35/twist.js new file mode 100644 index 0000000..d2be611 --- /dev/null +++ b/episode35/twist.js @@ -0,0 +1,71 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + + + var p0 = { + x: 0, + y: -321 + }, + p1 = { + x: 278, + y: 160 + }, + p2 = { + x: -278, + y: 160 + }; + var a = 0, + b = 0, + r = 0, + tx, ty; + + draw(); + function draw() { + context.clearRect(0, 0, width, height); + context.save(); + context.translate(width / 2, height / 2); + context.rotate(r += 0.01); + tx = .5 + Math.sin(a += .045) * .25; + ty = .5 + Math.sin(b += .045) * .25; + sierpinski(p0, p1, p2, 7); + context.restore(); + requestAnimationFrame(draw); + } + + function sierpinski(p0, p1, p2, limit) { + if(limit > 0) { + var pA = { + x: p0.x + (p1.x - p0.x) * tx, + y: p0.y + (p1.y - p0.y) * ty + }, + pB = { + x: p1.x + (p2.x - p1.x) * tx, + y: p1.y + (p2.y - p1.y) * ty + }, + pC = { + x: p2.x + (p0.x - p2.x) * tx, + y: p2.y + (p0.y - p2.y) * ty + }; + sierpinski(p0, pA, pC, limit - 1); + sierpinski(pA, p1, pB, limit - 1); + sierpinski(pC, pB, p2, limit - 1); + } + else { + drawTriangle(p0, p1, p2); + } + } + + function drawTriangle(p0, p1, p2) { + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.lineTo(p2.x, p2.y); + context.fill(); + } + +}; \ No newline at end of file From f6b82113e12d7052f7f75a8583710749ac0faafb Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Sat, 28 Feb 2015 07:01:52 -0500 Subject: [PATCH 28/39] episode 36 files --- episode36/index.html | 23 +++++++++++++++ episode36/main.js | 70 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 episode36/index.html create mode 100644 episode36/main.js diff --git a/episode36/index.html b/episode36/index.html new file mode 100644 index 0000000..5989d5a --- /dev/null +++ b/episode36/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/episode36/main.js b/episode36/main.js new file mode 100644 index 0000000..dd2b98c --- /dev/null +++ b/episode36/main.js @@ -0,0 +1,70 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var points = [], + bounce = 0.9, + gravity = 0.5, + friction = 0.999; + + points.push({ + x: 100, + y: 100, + oldx: 95, + oldy: 95 + }); + + + + update(); + + function update() { + updatePoints(); + renderPoints(); + requestAnimationFrame(update); + } + + function updatePoints() { + for(var i = 0; i < points.length; i++) { + var p = points[i], + vx = (p.x - p.oldx) * friction; + vy = (p.y - p.oldy) * friction; + + p.oldx = p.x; + p.oldy = p.y; + p.x += vx; + p.y += vy; + p.y += gravity; + + if(p.x > width) { + p.x = width; + p.oldx = p.x + vx * bounce; + } + else if(p.x < 0) { + p.x = 0; + p.oldx = p.x + vx * bounce; + } + if(p.y > height) { + p.y = height; + p.oldy = p.y + vy * bounce; + } + else if(p.y < 0) { + p.y = 0; + p.oldy = p.y + vy * bounce; + } + } + } + + function renderPoints() { + context.clearRect(0, 0, width, height); + for(var i = 0; i < points.length; i++) { + var p = points[i]; + context.beginPath(); + context.arc(p.x, p.y, 5, 0, Math.PI * 2); + context.fill(); + } + } +}; \ No newline at end of file From d319f523e97bd9ea40d1a19dc6378f1f13f8e606 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Wed, 18 Mar 2015 08:20:04 -0400 Subject: [PATCH 29/39] episode 38. plus it looks like a lot of line endings got changed. --- README.md | 20 +- application1/index.html | 44 +-- application1/main.js | 100 +++--- application1/particle.js | 94 ++--- application1/utils.js | 32 +- application1/vector.js | 164 ++++----- application2/index.html | 44 +-- application2/main.js | 192 +++++----- application2/particle.js | 94 ++--- application2/utils.js | 32 +- application2/vector.js | 164 ++++----- application3/code.sublime-project | 14 +- application3/index.html | 44 +-- application3/main.js | 218 ++++++------ application3/main2.js | 226 ++++++------ application3/particle.js | 94 ++--- application3/utils.js | 32 +- application3/vector.js | 164 ++++----- application4/index.html | 44 +-- application4/main.js | 262 +++++++------- application4/particle.js | 116 +++--- application4/utils.js | 144 ++++---- application4/vector.js | 164 ++++----- episode1/index.html | 38 +- episode1/main.js | 24 +- episode10/animation_template.js | 32 +- episode10/main.js | 224 ++++++------ episode10/particle.js | 40 +-- episode10/ship1.js | 174 ++++----- episode10/ship2.js | 198 +++++------ episode10/vector.js | 164 ++++----- episode11/animation_template.js | 32 +- episode11/index.html | 42 +-- episode11/main.js | 66 ++-- episode11/orbit.js | 66 ++-- episode11/particle.js | 82 ++--- episode11/vector.js | 164 ++++----- episode12/bounce.js | 80 ++--- episode12/index.html | 42 +-- episode12/particle.js | 92 ++--- episode12/regen.js | 80 ++--- episode12/regen_extra.js | 82 ++--- episode12/removal.js | 100 +++--- episode12/vector.js | 164 ++++----- episode12/wrapping.js | 74 ++-- episode13/friction1.js | 64 ++-- episode13/friction2.js | 50 +-- episode13/index.html | 42 +-- episode13/particle.js | 96 ++--- episode13/ship2.js | 202 +++++------ episode13/vector.js | 164 ++++----- episode14/circle-circle.js | 84 ++--- episode14/circle-point.js | 58 +-- episode14/index.html | 44 +-- episode14/main.js | 16 +- episode14/particle.js | 96 ++--- episode14/rect-point.js | 46 +-- episode14/rect-rect.js | 70 ++-- episode14/utils.js | 112 +++--- episode14/vector.js | 164 ++++----- episode15/index.html | 44 +-- episode15/particle.js | 96 ++--- episode15/spring1.js | 98 +++--- episode15/utils.js | 112 +++--- episode15/vector.js | 164 ++++----- episode16/index.html | 44 +-- episode16/particle.js | 96 ++--- episode16/spring1.js | 102 +++--- episode16/spring2.js | 180 +++++----- episode16/utils.js | 144 ++++---- episode16/vector.js | 164 ++++----- episode17/index.html | 44 +-- episode17/orbit.js | 66 ++-- episode17/particle.js | 114 +++--- episode17/spring1.js | 116 +++--- episode17/utils.js | 144 ++++---- episode17/vector.js | 164 ++++----- episode18/index.html | 44 +-- episode18/main.js | 262 +++++++------- episode18/multigravity.js | 124 +++---- episode18/particle.js | 274 +++++++-------- episode18/spring1.js | 110 +++--- episode18/utils.js | 144 ++++---- episode18/vector.js | 164 ++++----- episode19/demo1.js | 146 ++++---- episode19/demo2.js | 190 +++++----- episode19/demo3.js | 210 +++++------ episode19/demo4.js | 248 ++++++------- episode19/demo5.js | 258 +++++++------- episode19/demo6.js | 358 +++++++++---------- episode19/index.html | 40 +-- episode19/main1.js | 104 +++--- episode19/main2.js | 86 ++--- episode19/main3.js | 96 ++--- episode19/utils.js | 210 +++++------ episode2/index.html | 34 +- episode2/trig01.js | 40 +-- episode20/index.html | 40 +-- episode20/main1.js | 90 ++--- episode20/main2.js | 70 ++-- episode20/main3.js | 64 ++-- episode20/utils.js | 244 ++++++------- episode21/index.html | 52 +-- episode21/main.js | 90 ++--- episode21/particle.js | 274 +++++++-------- episode21/utils.js | 244 ++++++------- episode22/index.html | 44 +-- episode22/main.js | 42 +-- episode22/main2.js | 118 +++---- episode22/particle.js | 274 +++++++-------- episode22/postcards.js | 94 ++--- episode22/stars.js | 38 +- episode22/utils.js | 244 ++++++------- episode23/final.js | 134 +++---- episode23/index.html | 46 +-- episode23/particle.js | 274 +++++++-------- episode23/postcards.js | 120 +++---- episode23/spiral.js | 124 +++---- episode23/stars.js | 126 +++---- episode23/utils.js | 244 ++++++------- episode24/index.html | 46 +-- episode24/particle.js | 274 +++++++-------- episode24/spiral.js | 124 +++---- episode24/utils.js | 244 ++++++------- episode25/index.html | 38 +- episode25/main.js | 192 +++++----- episode26/2d.js | 64 ++-- episode26/index.html | 38 +- episode26/main.js | 310 ++++++++-------- episode27/index.html | 44 +-- episode27/main.js | 90 ++--- episode28/click.js | 116 +++--- episode28/index.html | 46 +-- episode28/main.js | 108 +++--- episode28/steering.js | 74 ++-- episode28/string.js | 112 +++--- episode28/utils.js | 244 ++++++------- episode29/index.html | 44 +-- episode29/main.js | 154 ++++---- episode29/penner_easing.as | 564 +++++++++++++++--------------- episode29/utils.js | 244 ++++++------- episode3/index.html | 34 +- episode3/trig02.js | 58 +-- episode30/index.html | 44 +-- episode30/tweenBasic.js | 140 ++++---- episode30/tweenFull.js | 168 ++++----- episode30/tweenx.js | 136 +++---- episode32/index.html | 44 +-- episode32/main.js | 108 +++--- episode32/main_interactive.js | 214 ++++++------ episode33/index.html | 44 +-- episode33/main_interactive.js | 288 +++++++-------- episode33/parallel.js | 116 +++--- episode34/index.html | 44 +-- episode34/particles.js | 214 ++++++------ episode34/shapes.js | 296 ++++++++-------- episode35/index.html | 44 +-- episode35/koch.js | 122 +++---- episode35/kochanimated.js | 154 ++++---- episode35/sierpinski.js | 110 +++--- episode35/twist.js | 140 ++++---- episode36/index.html | 44 +-- episode36/main.js | 138 ++++---- episode38/cat.jpg | Bin 0 -> 46674 bytes episode38/image.js | 230 ++++++++++++ episode38/index.html | 23 ++ episode38/main.js | 227 ++++++++++++ episode38/ragdoll.js | 262 ++++++++++++++ episode4/bees.js | 104 +++--- episode4/circle.js | 48 +-- episode4/code.js | 46 +-- episode4/index.html | 34 +- episode5/arctangent.js | 86 ++--- episode5/index.html | 34 +- episode7/vector.js | 164 ++++----- episode8/index.html | 42 +-- episode8/main.js | 54 +-- episode8/particle.js | 32 +- episode8/vector.js | 164 ++++----- episode9/fireworks.js | 56 +-- episode9/index.html | 42 +-- episode9/main.js | 46 +-- episode9/particle.js | 46 +-- episode9/vector.js | 164 ++++----- mini1/index.html | 38 +- mini1/main.js | 82 ++--- mini10/circle.js | 54 +-- mini10/index.html | 42 +-- mini10/main.js | 36 +- mini10/main2.js | 54 +-- mini10/particle.js | 274 +++++++-------- mini10/utils.js | 210 +++++------ mini11/bezier.js | 178 +++++----- mini11/index.html | 40 +-- mini11/main.js | 88 ++--- mini11/utils.js | 210 +++++------ mini2/index.html | 38 +- mini2/main.js | 82 ++--- mini3/index.html | 38 +- mini3/main.js | 58 +-- mini4/index.html | 38 +- mini4/main.js | 60 ++-- mini6/index.html | 38 +- mini6/main.js | 58 +-- mini7/index.html | 40 +-- mini7/main.js | 40 +-- mini7/utils.js | 128 +++---- mini8/index.html | 40 +-- mini8/main.js | 70 ++-- mini8/test1.js | 12 +- mini8/test2.js | 12 +- mini8/utils.js | 146 ++++---- mini9/highres.js | 88 ++--- mini9/index.html | 40 +-- mini9/main.js | 68 ++-- mini9/main2.js | 74 ++-- mini9/main3.js | 26 +- mini9/utils.js | 162 ++++----- 218 files changed, 12586 insertions(+), 11844 deletions(-) create mode 100644 episode38/cat.jpg create mode 100644 episode38/image.js create mode 100644 episode38/index.html create mode 100644 episode38/main.js create mode 100644 episode38/ragdoll.js diff --git a/README.md b/README.md index 645b2ba..9c13536 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -CodingMath -========== - -This repo will house any applicable files from the Coding Math videos. - -Site: http://codingmath.com - -YouTube: http://www.youtube.com/user/codingmath - -Support: http://www.patreon.com/codingmath +CodingMath +========== + +This repo will house any applicable files from the Coding Math videos. + +Site: http://codingmath.com + +YouTube: http://www.youtube.com/user/codingmath + +Support: http://www.patreon.com/codingmath diff --git a/application1/index.html b/application1/index.html index e8000db..8b3dc92 100644 --- a/application1/index.html +++ b/application1/index.html @@ -1,23 +1,23 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/application1/main.js b/application1/main.js index b539abc..543d16e 100644 --- a/application1/main.js +++ b/application1/main.js @@ -1,51 +1,51 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - gun = { - x: 100, - y: height, - angle: -Math.PI / 4 - }; - - draw(); - - document.body.addEventListener("mousedown", onMouseDown); - - function onMouseDown(event) { - document.body.addEventListener("mousemove", onMouseMove); - document.body.addEventListener("mouseup", onMouseUp); - aimGun(event.clientX, event.clientY); - } - - function onMouseMove(event) { - aimGun(event.clientX, event.clientY); - } - - function onMouseUp(event) { - document.body.removeEventListener("mousemove", onMouseMove); - document.body.removeEventListener("mouseup", onMouseUp); - aimGun(event.clientX, event.clientY); - } - - function aimGun(mouseX, mouseY) { - gun.angle = utils.clamp(Math.atan2(mouseY - gun.y, mouseX - gun.x), -Math.PI / 2, -0.3); - draw(); - } - - function draw() { - context.clearRect(0, 0, width, height); - - context.beginPath(); - context.arc(gun.x, gun.y, 24, 0, Math.PI * 2, false); - context.fill(); - - context.save(); - context.translate(gun.x, gun.y); - context.rotate(gun.angle); - context.fillRect(0, -8, 40, 16); - context.restore(); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + gun = { + x: 100, + y: height, + angle: -Math.PI / 4 + }; + + draw(); + + document.body.addEventListener("mousedown", onMouseDown); + + function onMouseDown(event) { + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function onMouseMove(event) { + aimGun(event.clientX, event.clientY); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function aimGun(mouseX, mouseY) { + gun.angle = utils.clamp(Math.atan2(mouseY - gun.y, mouseX - gun.x), -Math.PI / 2, -0.3); + draw(); + } + + function draw() { + context.clearRect(0, 0, width, height); + + context.beginPath(); + context.arc(gun.x, gun.y, 24, 0, Math.PI * 2, false); + context.fill(); + + context.save(); + context.translate(gun.x, gun.y); + context.rotate(gun.angle); + context.fillRect(0, -8, 40, 16); + context.restore(); + } + }; \ No newline at end of file diff --git a/application1/particle.js b/application1/particle.js index 5580676..ca34379 100644 --- a/application1/particle.js +++ b/application1/particle.js @@ -1,48 +1,48 @@ -var particle = { - position: null, - velocity: null, - mass: 1, - radius: 0, - bounce: -1, - friction: 1, - - create: function(x, y, speed, direction, grav) { - var obj = Object.create(this); - obj.position = vector.create(x, y); - obj.velocity = vector.create(0, 0); - obj.velocity.setLength(speed); - obj.velocity.setAngle(direction); - obj.gravity = vector.create(0, grav || 0); - return obj; - }, - - accelerate: function(accel) { - this.velocity.addTo(accel); - }, - - update: function() { - this.velocity.multiplyBy(this.friction); - this.velocity.addTo(this.gravity); - this.position.addTo(this.velocity); - }, - - angleTo: function(p2) { - return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); - }, - - distanceTo: function(p2) { - var dx = p2.position.getX() - this.position.getX(), - dy = p2.position.getY() - this.position.getY(); - - return Math.sqrt(dx * dx + dy * dy); - }, - - gravitateTo: function(p2) { - var grav = vector.create(0, 0), - dist = this.distanceTo(p2); - - grav.setLength(p2.mass / (dist * dist)); - grav.setAngle(this.angleTo(p2)); - this.velocity.addTo(grav); - } +var particle = { + position: null, + velocity: null, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + obj.gravity = vector.create(0, grav || 0); + return obj; + }, + + accelerate: function(accel) { + this.velocity.addTo(accel); + }, + + update: function() { + this.velocity.multiplyBy(this.friction); + this.velocity.addTo(this.gravity); + this.position.addTo(this.velocity); + }, + + angleTo: function(p2) { + return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); + }, + + distanceTo: function(p2) { + var dx = p2.position.getX() - this.position.getX(), + dy = p2.position.getY() - this.position.getY(); + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var grav = vector.create(0, 0), + dist = this.distanceTo(p2); + + grav.setLength(p2.mass / (dist * dist)); + grav.setAngle(this.angleTo(p2)); + this.velocity.addTo(grav); + } }; \ No newline at end of file diff --git a/application1/utils.js b/application1/utils.js index 28df0b6..fc95532 100644 --- a/application1/utils.js +++ b/application1/utils.js @@ -1,17 +1,17 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return lerp(norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, min), max); - } +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return lerp(norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, min), max); + } } \ No newline at end of file diff --git a/application1/vector.js b/application1/vector.js index 609f6d5..4d66796 100644 --- a/application1/vector.js +++ b/application1/vector.js @@ -1,83 +1,83 @@ -var vector = { - _x: 1, - _y: 0, - - create: function(x, y) { - var obj = Object.create(this); - obj.setX(x); - obj.setY(y); - return obj; - }, - - setX: function(value) { - this._x = value; - }, - - getX: function() { - return this._x; - }, - - setY: function(value) { - this._y = value; - }, - - getY: function() { - return this._y; - }, - - setAngle: function(angle) { - var length = this.getLength(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getAngle: function() { - return Math.atan2(this._y, this._x); - }, - - setLength: function(length) { - var angle = this.getAngle(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getLength: function() { - return Math.sqrt(this._x * this._x + this._y * this._y); - }, - - add: function(v2) { - return vector.create(this._x + v2.getX(), this._y + v2.getY()); - }, - - subtract: function(v2) { - return vector.create(this._x - v2.getX(), this._y - v2.getY()); - }, - - multiply: function(val) { - return vector.create(this._x * val, this._y * val); - }, - - divide: function(val) { - return vector.create(this._x / val, this._y / val); - }, - - addTo: function(v2) { - this._x += v2.getX(); - this._y += v2.getY(); - }, - - subtractFrom: function(v2) { - this._x -= v2.getX(); - this._y -= v2.getY(); - }, - - multiplyBy: function(val) { - this._x *= val; - this._y *= val; - }, - - divideBy: function(val) { - this._x /= val; - this._y /= val; - } +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } }; \ No newline at end of file diff --git a/application2/index.html b/application2/index.html index e892cce..f55c3a4 100644 --- a/application2/index.html +++ b/application2/index.html @@ -1,23 +1,23 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/application2/main.js b/application2/main.js index a9db1d6..20879e0 100644 --- a/application2/main.js +++ b/application2/main.js @@ -1,97 +1,97 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - gun = { - x: 100, - y: height, - angle: -Math.PI / 4 - }, - cannonball = particle.create(gun.x, gun.y, 15, gun.angle, 0.2), - canShoot = true; - - cannonball.radius = 7; - - draw(); - - document.body.addEventListener("mousedown", onMouseDown); - - document.body.addEventListener("keyup", function(event) { - switch(event.keyCode) { - case 32: // space - if(canShoot) { - shoot(); - } - break; - - default: - break; - } - }); - - function shoot() { - cannonball.position.setX(gun.x + Math.cos(gun.angle) * 40); - cannonball.position.setY(gun.y + Math.sin(gun.angle) * 40); - cannonball.velocity.setLength(15); - cannonball.velocity.setAngle(gun.angle); - - canShoot = false; - update(); - } - - function update() { - cannonball.update(); - draw(); - - if(cannonball.position.getY() > height) { - canShoot = true; - } - else { - requestAnimationFrame(update); - } - } - - function onMouseDown(event) { - document.body.addEventListener("mousemove", onMouseMove); - document.body.addEventListener("mouseup", onMouseUp); - aimGun(event.clientX, event.clientY); - } - - function onMouseMove(event) { - aimGun(event.clientX, event.clientY); - } - - function onMouseUp(event) { - document.body.removeEventListener("mousemove", onMouseMove); - document.body.removeEventListener("mouseup", onMouseUp); - aimGun(event.clientX, event.clientY); - } - - function aimGun(mouseX, mouseY) { - gun.angle = utils.clamp(Math.atan2(mouseY - gun.y, mouseX - gun.x), -Math.PI / 2, -0.3); - draw(); - } - - function draw() { - context.clearRect(0, 0, width, height); - - context.beginPath(); - context.arc(gun.x, gun.y, 24, 0, Math.PI * 2, false); - context.fill(); - - context.save(); - context.translate(gun.x, gun.y); - context.rotate(gun.angle); - context.fillRect(0, -8, 40, 16); - context.restore(); - - context.beginPath(); - context.arc(cannonball.position.getX(), - cannonball.position.getY(), - cannonball.radius, - 0, Math.PI * 2, false); - context.fill(); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + gun = { + x: 100, + y: height, + angle: -Math.PI / 4 + }, + cannonball = particle.create(gun.x, gun.y, 15, gun.angle, 0.2), + canShoot = true; + + cannonball.radius = 7; + + draw(); + + document.body.addEventListener("mousedown", onMouseDown); + + document.body.addEventListener("keyup", function(event) { + switch(event.keyCode) { + case 32: // space + if(canShoot) { + shoot(); + } + break; + + default: + break; + } + }); + + function shoot() { + cannonball.position.setX(gun.x + Math.cos(gun.angle) * 40); + cannonball.position.setY(gun.y + Math.sin(gun.angle) * 40); + cannonball.velocity.setLength(15); + cannonball.velocity.setAngle(gun.angle); + + canShoot = false; + update(); + } + + function update() { + cannonball.update(); + draw(); + + if(cannonball.position.getY() > height) { + canShoot = true; + } + else { + requestAnimationFrame(update); + } + } + + function onMouseDown(event) { + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function onMouseMove(event) { + aimGun(event.clientX, event.clientY); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function aimGun(mouseX, mouseY) { + gun.angle = utils.clamp(Math.atan2(mouseY - gun.y, mouseX - gun.x), -Math.PI / 2, -0.3); + draw(); + } + + function draw() { + context.clearRect(0, 0, width, height); + + context.beginPath(); + context.arc(gun.x, gun.y, 24, 0, Math.PI * 2, false); + context.fill(); + + context.save(); + context.translate(gun.x, gun.y); + context.rotate(gun.angle); + context.fillRect(0, -8, 40, 16); + context.restore(); + + context.beginPath(); + context.arc(cannonball.position.getX(), + cannonball.position.getY(), + cannonball.radius, + 0, Math.PI * 2, false); + context.fill(); + } + }; \ No newline at end of file diff --git a/application2/particle.js b/application2/particle.js index 5580676..ca34379 100644 --- a/application2/particle.js +++ b/application2/particle.js @@ -1,48 +1,48 @@ -var particle = { - position: null, - velocity: null, - mass: 1, - radius: 0, - bounce: -1, - friction: 1, - - create: function(x, y, speed, direction, grav) { - var obj = Object.create(this); - obj.position = vector.create(x, y); - obj.velocity = vector.create(0, 0); - obj.velocity.setLength(speed); - obj.velocity.setAngle(direction); - obj.gravity = vector.create(0, grav || 0); - return obj; - }, - - accelerate: function(accel) { - this.velocity.addTo(accel); - }, - - update: function() { - this.velocity.multiplyBy(this.friction); - this.velocity.addTo(this.gravity); - this.position.addTo(this.velocity); - }, - - angleTo: function(p2) { - return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); - }, - - distanceTo: function(p2) { - var dx = p2.position.getX() - this.position.getX(), - dy = p2.position.getY() - this.position.getY(); - - return Math.sqrt(dx * dx + dy * dy); - }, - - gravitateTo: function(p2) { - var grav = vector.create(0, 0), - dist = this.distanceTo(p2); - - grav.setLength(p2.mass / (dist * dist)); - grav.setAngle(this.angleTo(p2)); - this.velocity.addTo(grav); - } +var particle = { + position: null, + velocity: null, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + obj.gravity = vector.create(0, grav || 0); + return obj; + }, + + accelerate: function(accel) { + this.velocity.addTo(accel); + }, + + update: function() { + this.velocity.multiplyBy(this.friction); + this.velocity.addTo(this.gravity); + this.position.addTo(this.velocity); + }, + + angleTo: function(p2) { + return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); + }, + + distanceTo: function(p2) { + var dx = p2.position.getX() - this.position.getX(), + dy = p2.position.getY() - this.position.getY(); + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var grav = vector.create(0, 0), + dist = this.distanceTo(p2); + + grav.setLength(p2.mass / (dist * dist)); + grav.setAngle(this.angleTo(p2)); + this.velocity.addTo(grav); + } }; \ No newline at end of file diff --git a/application2/utils.js b/application2/utils.js index a34cfec..0d6fd7b 100644 --- a/application2/utils.js +++ b/application2/utils.js @@ -1,17 +1,17 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, min), max); - } +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, min), max); + } } \ No newline at end of file diff --git a/application2/vector.js b/application2/vector.js index 609f6d5..4d66796 100644 --- a/application2/vector.js +++ b/application2/vector.js @@ -1,83 +1,83 @@ -var vector = { - _x: 1, - _y: 0, - - create: function(x, y) { - var obj = Object.create(this); - obj.setX(x); - obj.setY(y); - return obj; - }, - - setX: function(value) { - this._x = value; - }, - - getX: function() { - return this._x; - }, - - setY: function(value) { - this._y = value; - }, - - getY: function() { - return this._y; - }, - - setAngle: function(angle) { - var length = this.getLength(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getAngle: function() { - return Math.atan2(this._y, this._x); - }, - - setLength: function(length) { - var angle = this.getAngle(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getLength: function() { - return Math.sqrt(this._x * this._x + this._y * this._y); - }, - - add: function(v2) { - return vector.create(this._x + v2.getX(), this._y + v2.getY()); - }, - - subtract: function(v2) { - return vector.create(this._x - v2.getX(), this._y - v2.getY()); - }, - - multiply: function(val) { - return vector.create(this._x * val, this._y * val); - }, - - divide: function(val) { - return vector.create(this._x / val, this._y / val); - }, - - addTo: function(v2) { - this._x += v2.getX(); - this._y += v2.getY(); - }, - - subtractFrom: function(v2) { - this._x -= v2.getX(); - this._y -= v2.getY(); - }, - - multiplyBy: function(val) { - this._x *= val; - this._y *= val; - }, - - divideBy: function(val) { - this._x /= val; - this._y /= val; - } +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } }; \ No newline at end of file diff --git a/application3/code.sublime-project b/application3/code.sublime-project index 2862388..be2f241 100644 --- a/application3/code.sublime-project +++ b/application3/code.sublime-project @@ -1,8 +1,8 @@ -{ - "folders": - [ - { - "path": "." - } - ] +{ + "folders": + [ + { + "path": "." + } + ] } \ No newline at end of file diff --git a/application3/index.html b/application3/index.html index e8000db..8b3dc92 100644 --- a/application3/index.html +++ b/application3/index.html @@ -1,23 +1,23 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/application3/main.js b/application3/main.js index 6b8af4d..55d7893 100644 --- a/application3/main.js +++ b/application3/main.js @@ -1,110 +1,110 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - gun = { - x: 100, - y: height, - angle: -Math.PI / 4 - }, - cannonball = particle.create(gun.x, gun.y, 15, gun.angle, 0.2), - isShooting = false, - forceAngle = 0, - forceSpeed = 0.1, - rawForce = 0; - - cannonball.radius = 7; - - update (); - - document.body.addEventListener("mousedown", onMouseDown); - - document.body.addEventListener("keydown", function(event) { - switch(event.keyCode) { - case 32: // space - if(!isShooting) { - shoot(); - } - break; - - default: - break; - } - }); - - function shoot() { - cannonball.position.setX(gun.x + Math.cos(gun.angle) * 40); - cannonball.position.setY(gun.y + Math.sin(gun.angle) * 40); - cannonball.velocity.setLength(utils.map(rawForce, -1, 1, 2, 20)); - cannonball.velocity.setAngle(gun.angle); - - isShooting = true; - } - - function update() { - if(!isShooting) { - forceAngle += forceSpeed; - } - rawForce = Math.sin(forceAngle); - if(isShooting) { - cannonball.update(); - } - draw(); - - if(cannonball.position.getY() > height) { - isShooting = false; - } - requestAnimationFrame(update); - } - - function onMouseDown(event) { - document.body.addEventListener("mousemove", onMouseMove); - document.body.addEventListener("mouseup", onMouseUp); - aimGun(event.clientX, event.clientY); - } - - function onMouseMove(event) { - aimGun(event.clientX, event.clientY); - } - - function onMouseUp(event) { - document.body.removeEventListener("mousemove", onMouseMove); - document.body.removeEventListener("mouseup", onMouseUp); - aimGun(event.clientX, event.clientY); - } - - function aimGun(mouseX, mouseY) { - gun.angle = utils.clamp(Math.atan2(mouseY - gun.y, mouseX - gun.x), -Math.PI / 2, -0.3); - } - - function draw() { - context.clearRect(0, 0, width, height); - - context.fillStyle = "#ccc"; - context.fillRect(10, height - 10, 20, -100); - - context.fillStyle = "#666"; - context.fillRect(10, height - 10, 20, utils.map(rawForce, -1, 1, 0, -100)); - - context.fillStyle = "#000"; - - context.beginPath(); - context.arc(gun.x, gun.y, 24, 0, Math.PI * 2, false); - context.fill(); - - context.save(); - context.translate(gun.x, gun.y); - context.rotate(gun.angle); - context.fillRect(0, -8, 40, 16); - context.restore(); - - context.beginPath(); - context.arc(cannonball.position.getX(), - cannonball.position.getY(), - cannonball.radius, - 0, Math.PI * 2, false); - context.fill(); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + gun = { + x: 100, + y: height, + angle: -Math.PI / 4 + }, + cannonball = particle.create(gun.x, gun.y, 15, gun.angle, 0.2), + isShooting = false, + forceAngle = 0, + forceSpeed = 0.1, + rawForce = 0; + + cannonball.radius = 7; + + update (); + + document.body.addEventListener("mousedown", onMouseDown); + + document.body.addEventListener("keydown", function(event) { + switch(event.keyCode) { + case 32: // space + if(!isShooting) { + shoot(); + } + break; + + default: + break; + } + }); + + function shoot() { + cannonball.position.setX(gun.x + Math.cos(gun.angle) * 40); + cannonball.position.setY(gun.y + Math.sin(gun.angle) * 40); + cannonball.velocity.setLength(utils.map(rawForce, -1, 1, 2, 20)); + cannonball.velocity.setAngle(gun.angle); + + isShooting = true; + } + + function update() { + if(!isShooting) { + forceAngle += forceSpeed; + } + rawForce = Math.sin(forceAngle); + if(isShooting) { + cannonball.update(); + } + draw(); + + if(cannonball.position.getY() > height) { + isShooting = false; + } + requestAnimationFrame(update); + } + + function onMouseDown(event) { + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function onMouseMove(event) { + aimGun(event.clientX, event.clientY); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function aimGun(mouseX, mouseY) { + gun.angle = utils.clamp(Math.atan2(mouseY - gun.y, mouseX - gun.x), -Math.PI / 2, -0.3); + } + + function draw() { + context.clearRect(0, 0, width, height); + + context.fillStyle = "#ccc"; + context.fillRect(10, height - 10, 20, -100); + + context.fillStyle = "#666"; + context.fillRect(10, height - 10, 20, utils.map(rawForce, -1, 1, 0, -100)); + + context.fillStyle = "#000"; + + context.beginPath(); + context.arc(gun.x, gun.y, 24, 0, Math.PI * 2, false); + context.fill(); + + context.save(); + context.translate(gun.x, gun.y); + context.rotate(gun.angle); + context.fillRect(0, -8, 40, 16); + context.restore(); + + context.beginPath(); + context.arc(cannonball.position.getX(), + cannonball.position.getY(), + cannonball.radius, + 0, Math.PI * 2, false); + context.fill(); + } + }; \ No newline at end of file diff --git a/application3/main2.js b/application3/main2.js index 5bb68ed..21a291f 100644 --- a/application3/main2.js +++ b/application3/main2.js @@ -1,114 +1,114 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - gun = { - x: 100, - y: height, - angle: -Math.PI / 4 - }, - cannonball = particle.create(gun.x, gun.y, 15, gun.angle, 0.2), - isShooting = false, - forceAngle = 0, - forceSpeed = 0.1, - rawForce = 0; - - cannonball.radius = 7; - - update(); - - document.body.addEventListener("mousedown", onMouseDown); - - document.body.addEventListener("keydown", function(event) { - switch(event.keyCode) { - case 32: // space - if(!isShooting) { - shoot(); - } - break; - - default: - break; - } - }); - - function shoot() { - cannonball.position.setX(gun.x + Math.cos(gun.angle) * 40); - cannonball.position.setY(gun.y + Math.sin(gun.angle) * 40); - cannonball.velocity.setLength(utils.map(rawForce, -1, 1, 2, 20)); - cannonball.velocity.setAngle(gun.angle); - - isShooting = true; - } - - function update() { - if(isShooting) { - cannonball.update(); - } - else { - forceAngle += forceSpeed; - rawForce = Math.sin(forceAngle); - } - draw(); - - if(cannonball.position.getY() > height) { - isShooting = false; - } - requestAnimationFrame(update); - } - - function onMouseDown(event) { - document.body.addEventListener("mousemove", onMouseMove); - document.body.addEventListener("mouseup", onMouseUp); - aimGun(event.clientX, event.clientY); - } - - function onMouseMove(event) { - aimGun(event.clientX, event.clientY); - } - - function onMouseUp(event) { - document.body.removeEventListener("mousemove", onMouseMove); - document.body.removeEventListener("mouseup", onMouseUp); - aimGun(event.clientX, event.clientY); - } - - function aimGun(mouseX, mouseY) { - gun.angle = utils.clamp(Math.atan2(mouseY - gun.y, mouseX - gun.x), -Math.PI / 2, -0.3); - draw(); - } - - function draw() { - context.clearRect(0, 0, width, height); - - context.fillStyle = "#ccc"; - context.beginPath(); - context.rect(10, height - 10, 20, -100); - context.fill(); - - context.fillStyle = "#666"; - context.beginPath(); - context.rect(10, height - 10, 20, utils.map(rawForce, -1, 1, 0, -100)); - context.fill(); - - context.fillStyle = "#000"; - context.beginPath(); - context.arc(gun.x, gun.y, 24, 0, Math.PI * 2, false); - context.fill(); - - context.save(); - context.translate(gun.x, gun.y); - context.rotate(gun.angle); - context.fillRect(0, -8, 40, 16); - context.restore(); - - context.beginPath(); - context.arc(cannonball.position.getX(), - cannonball.position.getY(), - cannonball.radius, - 0, Math.PI * 2, false); - context.fill(); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + gun = { + x: 100, + y: height, + angle: -Math.PI / 4 + }, + cannonball = particle.create(gun.x, gun.y, 15, gun.angle, 0.2), + isShooting = false, + forceAngle = 0, + forceSpeed = 0.1, + rawForce = 0; + + cannonball.radius = 7; + + update(); + + document.body.addEventListener("mousedown", onMouseDown); + + document.body.addEventListener("keydown", function(event) { + switch(event.keyCode) { + case 32: // space + if(!isShooting) { + shoot(); + } + break; + + default: + break; + } + }); + + function shoot() { + cannonball.position.setX(gun.x + Math.cos(gun.angle) * 40); + cannonball.position.setY(gun.y + Math.sin(gun.angle) * 40); + cannonball.velocity.setLength(utils.map(rawForce, -1, 1, 2, 20)); + cannonball.velocity.setAngle(gun.angle); + + isShooting = true; + } + + function update() { + if(isShooting) { + cannonball.update(); + } + else { + forceAngle += forceSpeed; + rawForce = Math.sin(forceAngle); + } + draw(); + + if(cannonball.position.getY() > height) { + isShooting = false; + } + requestAnimationFrame(update); + } + + function onMouseDown(event) { + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function onMouseMove(event) { + aimGun(event.clientX, event.clientY); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function aimGun(mouseX, mouseY) { + gun.angle = utils.clamp(Math.atan2(mouseY - gun.y, mouseX - gun.x), -Math.PI / 2, -0.3); + draw(); + } + + function draw() { + context.clearRect(0, 0, width, height); + + context.fillStyle = "#ccc"; + context.beginPath(); + context.rect(10, height - 10, 20, -100); + context.fill(); + + context.fillStyle = "#666"; + context.beginPath(); + context.rect(10, height - 10, 20, utils.map(rawForce, -1, 1, 0, -100)); + context.fill(); + + context.fillStyle = "#000"; + context.beginPath(); + context.arc(gun.x, gun.y, 24, 0, Math.PI * 2, false); + context.fill(); + + context.save(); + context.translate(gun.x, gun.y); + context.rotate(gun.angle); + context.fillRect(0, -8, 40, 16); + context.restore(); + + context.beginPath(); + context.arc(cannonball.position.getX(), + cannonball.position.getY(), + cannonball.radius, + 0, Math.PI * 2, false); + context.fill(); + } + }; \ No newline at end of file diff --git a/application3/particle.js b/application3/particle.js index 5580676..ca34379 100644 --- a/application3/particle.js +++ b/application3/particle.js @@ -1,48 +1,48 @@ -var particle = { - position: null, - velocity: null, - mass: 1, - radius: 0, - bounce: -1, - friction: 1, - - create: function(x, y, speed, direction, grav) { - var obj = Object.create(this); - obj.position = vector.create(x, y); - obj.velocity = vector.create(0, 0); - obj.velocity.setLength(speed); - obj.velocity.setAngle(direction); - obj.gravity = vector.create(0, grav || 0); - return obj; - }, - - accelerate: function(accel) { - this.velocity.addTo(accel); - }, - - update: function() { - this.velocity.multiplyBy(this.friction); - this.velocity.addTo(this.gravity); - this.position.addTo(this.velocity); - }, - - angleTo: function(p2) { - return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); - }, - - distanceTo: function(p2) { - var dx = p2.position.getX() - this.position.getX(), - dy = p2.position.getY() - this.position.getY(); - - return Math.sqrt(dx * dx + dy * dy); - }, - - gravitateTo: function(p2) { - var grav = vector.create(0, 0), - dist = this.distanceTo(p2); - - grav.setLength(p2.mass / (dist * dist)); - grav.setAngle(this.angleTo(p2)); - this.velocity.addTo(grav); - } +var particle = { + position: null, + velocity: null, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + obj.gravity = vector.create(0, grav || 0); + return obj; + }, + + accelerate: function(accel) { + this.velocity.addTo(accel); + }, + + update: function() { + this.velocity.multiplyBy(this.friction); + this.velocity.addTo(this.gravity); + this.position.addTo(this.velocity); + }, + + angleTo: function(p2) { + return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); + }, + + distanceTo: function(p2) { + var dx = p2.position.getX() - this.position.getX(), + dy = p2.position.getY() - this.position.getY(); + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var grav = vector.create(0, 0), + dist = this.distanceTo(p2); + + grav.setLength(p2.mass / (dist * dist)); + grav.setAngle(this.angleTo(p2)); + this.velocity.addTo(grav); + } }; \ No newline at end of file diff --git a/application3/utils.js b/application3/utils.js index a34cfec..0d6fd7b 100644 --- a/application3/utils.js +++ b/application3/utils.js @@ -1,17 +1,17 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, min), max); - } +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, min), max); + } } \ No newline at end of file diff --git a/application3/vector.js b/application3/vector.js index 609f6d5..4d66796 100644 --- a/application3/vector.js +++ b/application3/vector.js @@ -1,83 +1,83 @@ -var vector = { - _x: 1, - _y: 0, - - create: function(x, y) { - var obj = Object.create(this); - obj.setX(x); - obj.setY(y); - return obj; - }, - - setX: function(value) { - this._x = value; - }, - - getX: function() { - return this._x; - }, - - setY: function(value) { - this._y = value; - }, - - getY: function() { - return this._y; - }, - - setAngle: function(angle) { - var length = this.getLength(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getAngle: function() { - return Math.atan2(this._y, this._x); - }, - - setLength: function(length) { - var angle = this.getAngle(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getLength: function() { - return Math.sqrt(this._x * this._x + this._y * this._y); - }, - - add: function(v2) { - return vector.create(this._x + v2.getX(), this._y + v2.getY()); - }, - - subtract: function(v2) { - return vector.create(this._x - v2.getX(), this._y - v2.getY()); - }, - - multiply: function(val) { - return vector.create(this._x * val, this._y * val); - }, - - divide: function(val) { - return vector.create(this._x / val, this._y / val); - }, - - addTo: function(v2) { - this._x += v2.getX(); - this._y += v2.getY(); - }, - - subtractFrom: function(v2) { - this._x -= v2.getX(); - this._y -= v2.getY(); - }, - - multiplyBy: function(val) { - this._x *= val; - this._y *= val; - }, - - divideBy: function(val) { - this._x /= val; - this._y /= val; - } +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } }; \ No newline at end of file diff --git a/application4/index.html b/application4/index.html index e8000db..8b3dc92 100644 --- a/application4/index.html +++ b/application4/index.html @@ -1,23 +1,23 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/application4/main.js b/application4/main.js index bfcad3d..dd0c680 100644 --- a/application4/main.js +++ b/application4/main.js @@ -1,132 +1,132 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - gun = { - x: 100, - y: height, - angle: -Math.PI / 4 - }, - cannonball = particle.create(gun.x, gun.y, 15, gun.angle, 0.2), - isShooting = false, - forceAngle = 0, - forceSpeed = 0.1, - rawForce = 0, - target = {}; - - cannonball.radius = 7; - - setTarget(); - update (); - - function setTarget() { - target.x = utils.randomRange(200, width); - target.y = height; - target.radius = utils.randomRange(10, 40); - } - - document.body.addEventListener("mousedown", onMouseDown); - - document.body.addEventListener("keydown", function(event) { - switch(event.keyCode) { - case 32: // space - if(!isShooting) { - shoot(); - } - break; - - default: - break; - } - }); - - function shoot() { - var force = utils.map(rawForce, -1, 1, 2, 20); - cannonball.x = gun.x + Math.cos(gun.angle) * 40; - cannonball.y = gun.y + Math.sin(gun.angle) * 40; - cannonball.vx = Math.cos(gun.angle) * force; - cannonball.vy = Math.sin(gun.angle) * force; - - isShooting = true; - } - - function update() { - if(!isShooting) { - forceAngle += forceSpeed; - } - rawForce = Math.sin(forceAngle); - if(isShooting) { - cannonball.update(); - checkTarget(); - } - draw(); - - if(cannonball.y > height) { - isShooting = false; - } - requestAnimationFrame(update); - } - - function checkTarget() { - if(utils.circleCollision(target, cannonball)) { - // create amazing collision reaction!!! - setTarget(); - } - } - - function onMouseDown(event) { - document.body.addEventListener("mousemove", onMouseMove); - document.body.addEventListener("mouseup", onMouseUp); - aimGun(event.clientX, event.clientY); - } - - function onMouseMove(event) { - aimGun(event.clientX, event.clientY); - } - - function onMouseUp(event) { - document.body.removeEventListener("mousemove", onMouseMove); - document.body.removeEventListener("mouseup", onMouseUp); - aimGun(event.clientX, event.clientY); - } - - function aimGun(mouseX, mouseY) { - gun.angle = utils.clamp(Math.atan2(mouseY - gun.y, mouseX - gun.x), -Math.PI / 2, -0.3); - } - - function draw() { - context.clearRect(0, 0, width, height); - - context.fillStyle = "#ccc"; - context.fillRect(10, height - 10, 20, -100); - - context.fillStyle = "#666"; - context.fillRect(10, height - 10, 20, utils.map(rawForce, -1, 1, 0, -100)); - - context.fillStyle = "#000"; - - context.beginPath(); - context.arc(gun.x, gun.y, 24, 0, Math.PI * 2, false); - context.fill(); - - context.save(); - context.translate(gun.x, gun.y); - context.rotate(gun.angle); - context.fillRect(0, -8, 40, 16); - context.restore(); - - context.beginPath(); - context.arc(cannonball.x, - cannonball.y, - cannonball.radius, - 0, Math.PI * 2, false); - context.fill(); - - context.fillStyle = "red"; - context.beginPath(); - context.arc(target.x, target.y, target.radius, 0, Math.PI * 2, false); - context.fill(); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + gun = { + x: 100, + y: height, + angle: -Math.PI / 4 + }, + cannonball = particle.create(gun.x, gun.y, 15, gun.angle, 0.2), + isShooting = false, + forceAngle = 0, + forceSpeed = 0.1, + rawForce = 0, + target = {}; + + cannonball.radius = 7; + + setTarget(); + update (); + + function setTarget() { + target.x = utils.randomRange(200, width); + target.y = height; + target.radius = utils.randomRange(10, 40); + } + + document.body.addEventListener("mousedown", onMouseDown); + + document.body.addEventListener("keydown", function(event) { + switch(event.keyCode) { + case 32: // space + if(!isShooting) { + shoot(); + } + break; + + default: + break; + } + }); + + function shoot() { + var force = utils.map(rawForce, -1, 1, 2, 20); + cannonball.x = gun.x + Math.cos(gun.angle) * 40; + cannonball.y = gun.y + Math.sin(gun.angle) * 40; + cannonball.vx = Math.cos(gun.angle) * force; + cannonball.vy = Math.sin(gun.angle) * force; + + isShooting = true; + } + + function update() { + if(!isShooting) { + forceAngle += forceSpeed; + } + rawForce = Math.sin(forceAngle); + if(isShooting) { + cannonball.update(); + checkTarget(); + } + draw(); + + if(cannonball.y > height) { + isShooting = false; + } + requestAnimationFrame(update); + } + + function checkTarget() { + if(utils.circleCollision(target, cannonball)) { + // create amazing collision reaction!!! + setTarget(); + } + } + + function onMouseDown(event) { + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function onMouseMove(event) { + aimGun(event.clientX, event.clientY); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function aimGun(mouseX, mouseY) { + gun.angle = utils.clamp(Math.atan2(mouseY - gun.y, mouseX - gun.x), -Math.PI / 2, -0.3); + } + + function draw() { + context.clearRect(0, 0, width, height); + + context.fillStyle = "#ccc"; + context.fillRect(10, height - 10, 20, -100); + + context.fillStyle = "#666"; + context.fillRect(10, height - 10, 20, utils.map(rawForce, -1, 1, 0, -100)); + + context.fillStyle = "#000"; + + context.beginPath(); + context.arc(gun.x, gun.y, 24, 0, Math.PI * 2, false); + context.fill(); + + context.save(); + context.translate(gun.x, gun.y); + context.rotate(gun.angle); + context.fillRect(0, -8, 40, 16); + context.restore(); + + context.beginPath(); + context.arc(cannonball.x, + cannonball.y, + cannonball.radius, + 0, Math.PI * 2, false); + context.fill(); + + context.fillStyle = "red"; + context.beginPath(); + context.arc(target.x, target.y, target.radius, 0, Math.PI * 2, false); + context.fill(); + } + }; \ No newline at end of file diff --git a/application4/particle.js b/application4/particle.js index 7e15dc5..03706a6 100644 --- a/application4/particle.js +++ b/application4/particle.js @@ -1,59 +1,59 @@ -var particle = { - x: 0, - y: 0, - vx: 0, - vy: 0, - mass: 1, - radius: 0, - bounce: -1, - friction: 1, - gravity: 0, - - create: function(x, y, speed, direction, grav) { - console.log("x: ", x); - var obj = Object.create(this); - this.x = x; - this.y = y; - this.vx = Math.cos(direction) * speed; - this.vy = Math.sin(direction) * speed; - obj.gravity = grav || 0; - return obj; - }, - - accelerate: function(ax, ay) { - this.vx += ax; - this.vy += ay; - }, - - update: function() { - this.vx *= this.friction; - this.vy *= this.friction; - this.vy += this.gravity; - this.x += this.vx; - this.y += this.vy; - }, - - angleTo: function(p2) { - return Math.atan2(p2.y - this.y, p2.x - this.x); - }, - - distanceTo: function(p2) { - var dx = p2.x - this.x, - dy = p2.y - this.y; - - return Math.sqrt(dx * dx + dy * dy); - }, - - gravitateTo: function(p2) { - var dx = this.x - p2.x, - dy = this.y - p2.y, - distSQ = dx * dx + dy * dy, - distance = Math.sqrt(distSQ), - force = p2.mass / distSQ, - ax = dx / distance * force, - ay = dy / distance * force; - - this.vx += ax; - this.vy += ay; - } +var particle = { + x: 0, + y: 0, + vx: 0, + vy: 0, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + + create: function(x, y, speed, direction, grav) { + console.log("x: ", x); + var obj = Object.create(this); + this.x = x; + this.y = y; + this.vx = Math.cos(direction) * speed; + this.vy = Math.sin(direction) * speed; + obj.gravity = grav || 0; + return obj; + }, + + accelerate: function(ax, ay) { + this.vx += ax; + this.vy += ay; + }, + + update: function() { + this.vx *= this.friction; + this.vy *= this.friction; + this.vy += this.gravity; + this.x += this.vx; + this.y += this.vy; + }, + + angleTo: function(p2) { + return Math.atan2(p2.y - this.y, p2.x - this.x); + }, + + distanceTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y; + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var dx = this.x - p2.x, + dy = this.y - p2.y, + distSQ = dx * dx + dy * dy, + distance = Math.sqrt(distSQ), + force = p2.mass / distSQ, + ax = dx / distance * force, + ay = dy / distance * force; + + this.vx += ax; + this.vy += ay; + } }; \ No newline at end of file diff --git a/application4/utils.js b/application4/utils.js index 37ae5ef..9728633 100644 --- a/application4/utils.js +++ b/application4/utils.js @@ -1,73 +1,73 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - }, - - degreesToRads: function(degrees) { - return degrees / 180 * Math.PI; - }, - - radsToDegrees: function(radians) { - return radians * 180 / Math.PI; - }, - - randomRange: function(min, max) { - return min + Math.random() * (max - min); - }, - - randomInt: function(min, max) { - return Math.floor(min + Math.random() * (max - min + 1)); - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + } + } \ No newline at end of file diff --git a/application4/vector.js b/application4/vector.js index 609f6d5..4d66796 100644 --- a/application4/vector.js +++ b/application4/vector.js @@ -1,83 +1,83 @@ -var vector = { - _x: 1, - _y: 0, - - create: function(x, y) { - var obj = Object.create(this); - obj.setX(x); - obj.setY(y); - return obj; - }, - - setX: function(value) { - this._x = value; - }, - - getX: function() { - return this._x; - }, - - setY: function(value) { - this._y = value; - }, - - getY: function() { - return this._y; - }, - - setAngle: function(angle) { - var length = this.getLength(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getAngle: function() { - return Math.atan2(this._y, this._x); - }, - - setLength: function(length) { - var angle = this.getAngle(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getLength: function() { - return Math.sqrt(this._x * this._x + this._y * this._y); - }, - - add: function(v2) { - return vector.create(this._x + v2.getX(), this._y + v2.getY()); - }, - - subtract: function(v2) { - return vector.create(this._x - v2.getX(), this._y - v2.getY()); - }, - - multiply: function(val) { - return vector.create(this._x * val, this._y * val); - }, - - divide: function(val) { - return vector.create(this._x / val, this._y / val); - }, - - addTo: function(v2) { - this._x += v2.getX(); - this._y += v2.getY(); - }, - - subtractFrom: function(v2) { - this._x -= v2.getX(); - this._y -= v2.getY(); - }, - - multiplyBy: function(val) { - this._x *= val; - this._y *= val; - }, - - divideBy: function(val) { - this._x /= val; - this._y /= val; - } +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } }; \ No newline at end of file diff --git a/episode1/index.html b/episode1/index.html index 719fb94..dfde07f 100644 --- a/episode1/index.html +++ b/episode1/index.html @@ -1,20 +1,20 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/episode1/main.js b/episode1/main.js index 5e6c4da..98a2a2e 100644 --- a/episode1/main.js +++ b/episode1/main.js @@ -1,13 +1,13 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - for(var i = 0; i < 100; i += 1) { - context.beginPath(); - context.moveTo(Math.random() * width, Math.random() * height); - context.lineTo(Math.random() * width, Math.random() * height); - context.stroke(); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + for(var i = 0; i < 100; i += 1) { + context.beginPath(); + context.moveTo(Math.random() * width, Math.random() * height); + context.lineTo(Math.random() * width, Math.random() * height); + context.stroke(); + } }; \ No newline at end of file diff --git a/episode10/animation_template.js b/episode10/animation_template.js index e557225..916d3d5 100644 --- a/episode10/animation_template.js +++ b/episode10/animation_template.js @@ -1,17 +1,17 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - update(); - - - function update() { - context.clearRect(0, 0, width, height); - - // animation goes here - - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + update(); + + + function update() { + context.clearRect(0, 0, width, height); + + // animation goes here + + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/episode10/main.js b/episode10/main.js index 25d329d..f465dfd 100644 --- a/episode10/main.js +++ b/episode10/main.js @@ -1,113 +1,113 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - ship = particle.create(width / 2, height / 2, 0, 0), - thrust = vector.create(0, 0), - angle = 0, - turningLeft = false, - turningRight = false, - thrusting = false; - - update(); - - - document.body.addEventListener("keydown", function(event) { - // console.log(event.keyCode); - switch(event.keyCode) { - case 38: // up - thrusting = true; - break; - - case 37: // left - turningLeft = true; - break; - - case 39: // right - turningRight = true; - break; - - default: - break; - - } - }); - - document.body.addEventListener("keyup", function(event) { - // console.log(event.keyCode); - switch(event.keyCode) { - case 38: // up - thrusting = false; - break; - - case 37: // left - turningLeft = false; - break; - - case 39: // right - turningRight = false; - break; - - default: - break; - - } - }); - - function update() { - context.clearRect(0, 0, width, height); - - if(turningLeft) { - angle -= 0.05; - } - if(turningRight) { - angle += 0.05; - } - - thrust.setAngle(angle); - - if(thrusting) { - thrust.setLength(0.1); - } - else { - thrust.setLength(0); - } - - // animation goes here - ship.accelerate(thrust); - ship.update(); - - context.save(); - context.translate(ship.position.getX(), ship.position.getY()); - context.rotate(angle); - - context.beginPath(); - context.moveTo(10, 0); - context.lineTo(-10, -7); - context.lineTo(-10, 7); - context.lineTo(10, 0); - if(thrusting) { - context.moveTo(-10, 0); - context.lineTo(-18, 0); - } - context.stroke(); - - context.restore(); - - if(ship.position.getX() > width) { - ship.position.setX(0); - } - if(ship.position.getX() < 0) { - ship.position.setX(width); - } - if(ship.position.getY() > height) { - ship.position.setY(0); - } - if(ship.position.getY() < 0) { - ship.position.setY(height); - } - - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + ship = particle.create(width / 2, height / 2, 0, 0), + thrust = vector.create(0, 0), + angle = 0, + turningLeft = false, + turningRight = false, + thrusting = false; + + update(); + + + document.body.addEventListener("keydown", function(event) { + // console.log(event.keyCode); + switch(event.keyCode) { + case 38: // up + thrusting = true; + break; + + case 37: // left + turningLeft = true; + break; + + case 39: // right + turningRight = true; + break; + + default: + break; + + } + }); + + document.body.addEventListener("keyup", function(event) { + // console.log(event.keyCode); + switch(event.keyCode) { + case 38: // up + thrusting = false; + break; + + case 37: // left + turningLeft = false; + break; + + case 39: // right + turningRight = false; + break; + + default: + break; + + } + }); + + function update() { + context.clearRect(0, 0, width, height); + + if(turningLeft) { + angle -= 0.05; + } + if(turningRight) { + angle += 0.05; + } + + thrust.setAngle(angle); + + if(thrusting) { + thrust.setLength(0.1); + } + else { + thrust.setLength(0); + } + + // animation goes here + ship.accelerate(thrust); + ship.update(); + + context.save(); + context.translate(ship.position.getX(), ship.position.getY()); + context.rotate(angle); + + context.beginPath(); + context.moveTo(10, 0); + context.lineTo(-10, -7); + context.lineTo(-10, 7); + context.lineTo(10, 0); + if(thrusting) { + context.moveTo(-10, 0); + context.lineTo(-18, 0); + } + context.stroke(); + + context.restore(); + + if(ship.position.getX() > width) { + ship.position.setX(0); + } + if(ship.position.getX() < 0) { + ship.position.setX(width); + } + if(ship.position.getY() > height) { + ship.position.setY(0); + } + if(ship.position.getY() < 0) { + ship.position.setY(height); + } + + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/episode10/particle.js b/episode10/particle.js index ea5eb1e..8d9d391 100644 --- a/episode10/particle.js +++ b/episode10/particle.js @@ -1,21 +1,21 @@ -var particle = { - position: null, - velocity: null, - - create: function(x, y, speed, direction) { - var obj = Object.create(this); - obj.position = vector.create(x, y); - obj.velocity = vector.create(0, 0); - obj.velocity.setLength(speed); - obj.velocity.setAngle(direction); - return obj; - }, - - accelerate: function(accel) { - this.velocity.addTo(accel); - }, - - update: function() { - this.position.addTo(this.velocity); - } +var particle = { + position: null, + velocity: null, + + create: function(x, y, speed, direction) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + return obj; + }, + + accelerate: function(accel) { + this.velocity.addTo(accel); + }, + + update: function() { + this.position.addTo(this.velocity); + } }; \ No newline at end of file diff --git a/episode10/ship1.js b/episode10/ship1.js index 74c765c..0470e1e 100644 --- a/episode10/ship1.js +++ b/episode10/ship1.js @@ -1,88 +1,88 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - ship = particle.create(width / 2, height / 2, 0, 0), - thrust = vector.create(0, 0); - - update(); - - - document.body.addEventListener("keydown", function(event) { - // console.log(event.keyCode); - switch(event.keyCode) { - case 38: // up - thrust.setY(-0.1); - break; - - case 40: // down - thrust.setY(0.1); - break; - - case 37: // left - thrust.setX(-0.1); - break; - - case 39: // right - thrust.setX(0.1); - break; - - default: - break; - - } - }); - - document.body.addEventListener("keyup", function(event) { - // console.log(event.keyCode); - switch(event.keyCode) { - case 38: // up - thrust.setY(0); - break; - - case 40: // down - thrust.setY(0); - break; - - case 37: // left - thrust.setX(0); - break; - - case 39: // right - thrust.setX(0); - break; - - default: - break; - - } - }); - - function update() { - context.clearRect(0, 0, width, height); - - // animation goes here - ship.accelerate(thrust); - ship.update(); - - context.beginPath(); - context.arc(ship.position.getX(), ship.position.getY(), 10, 0, Math.PI * 2, false); - context.fill(); - - if(ship.position.getX() > width) { - ship.position.setX(0); - } - if(ship.position.getX() < 0) { - ship.position.setX(width); - } - if(ship.position.getY() > height) { - ship.position.setY(0); - } - if(ship.position.getY() < 0) { - ship.position.setY(height); - } - - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + ship = particle.create(width / 2, height / 2, 0, 0), + thrust = vector.create(0, 0); + + update(); + + + document.body.addEventListener("keydown", function(event) { + // console.log(event.keyCode); + switch(event.keyCode) { + case 38: // up + thrust.setY(-0.1); + break; + + case 40: // down + thrust.setY(0.1); + break; + + case 37: // left + thrust.setX(-0.1); + break; + + case 39: // right + thrust.setX(0.1); + break; + + default: + break; + + } + }); + + document.body.addEventListener("keyup", function(event) { + // console.log(event.keyCode); + switch(event.keyCode) { + case 38: // up + thrust.setY(0); + break; + + case 40: // down + thrust.setY(0); + break; + + case 37: // left + thrust.setX(0); + break; + + case 39: // right + thrust.setX(0); + break; + + default: + break; + + } + }); + + function update() { + context.clearRect(0, 0, width, height); + + // animation goes here + ship.accelerate(thrust); + ship.update(); + + context.beginPath(); + context.arc(ship.position.getX(), ship.position.getY(), 10, 0, Math.PI * 2, false); + context.fill(); + + if(ship.position.getX() > width) { + ship.position.setX(0); + } + if(ship.position.getX() < 0) { + ship.position.setX(width); + } + if(ship.position.getY() > height) { + ship.position.setY(0); + } + if(ship.position.getY() < 0) { + ship.position.setY(height); + } + + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/episode10/ship2.js b/episode10/ship2.js index ea137b9..90cb4d3 100644 --- a/episode10/ship2.js +++ b/episode10/ship2.js @@ -1,100 +1,100 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight - ship = particle.create(width / 2, height / 2, 0, 0), - thrust = vector.create(0, 0), - angle = 0, - turningLeft = false, - turningRight = false, - thrusting = false; - - document.body.addEventListener("keydown", function(event) { - // console.log(event.keyCode); - switch(event.keyCode) { - case 38: // up - thrusting = true; - break; - case 37: // left - turningLeft = true; - break; - case 39: // right - turningRight = true; - default: - break - } - }); - - document.body.addEventListener("keyup", function(event) { - // console.log(event.keyCode); - switch(event.keyCode) { - case 38: // up - thrusting = false; - break; - case 37: // left - turningLeft = false; - break; - case 39: // right - turningRight = false; - default: - break - } - }); - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - if(turningRight) { - angle += .05; - } - if(turningLeft) { - angle -= .05; - } - - if(thrusting) { - thrust.setLength(.1); - } - else { - thrust.setLength(0); - } - thrust.setAngle(angle); - - ship.accelerate(thrust); - ship.update(); - - if(ship.position.getX() > width) { - ship.position.setX(0); - } - if(ship.position.getX() < 0) { - ship.position.setX(width); - } - if(ship.position.getY() > height) { - ship.position.setY(0); - } - if(ship.position.getY() < 0) { - ship.position.setY(height); - } - - context.save(); - - context.translate(ship.position.getX(), ship.position.getY()); - context.rotate(angle); - context.beginPath(); - context.moveTo(10, 0); - context.lineTo(-10, -7); - context.lineTo(-10, 7 ); - context.lineTo(10, 0); - if(thrusting) { - context.moveTo(-10, 0); - context.lineTo(-18, 0); - } - context.stroke(); - - context.restore(); - - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight + ship = particle.create(width / 2, height / 2, 0, 0), + thrust = vector.create(0, 0), + angle = 0, + turningLeft = false, + turningRight = false, + thrusting = false; + + document.body.addEventListener("keydown", function(event) { + // console.log(event.keyCode); + switch(event.keyCode) { + case 38: // up + thrusting = true; + break; + case 37: // left + turningLeft = true; + break; + case 39: // right + turningRight = true; + default: + break + } + }); + + document.body.addEventListener("keyup", function(event) { + // console.log(event.keyCode); + switch(event.keyCode) { + case 38: // up + thrusting = false; + break; + case 37: // left + turningLeft = false; + break; + case 39: // right + turningRight = false; + default: + break + } + }); + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + if(turningRight) { + angle += .05; + } + if(turningLeft) { + angle -= .05; + } + + if(thrusting) { + thrust.setLength(.1); + } + else { + thrust.setLength(0); + } + thrust.setAngle(angle); + + ship.accelerate(thrust); + ship.update(); + + if(ship.position.getX() > width) { + ship.position.setX(0); + } + if(ship.position.getX() < 0) { + ship.position.setX(width); + } + if(ship.position.getY() > height) { + ship.position.setY(0); + } + if(ship.position.getY() < 0) { + ship.position.setY(height); + } + + context.save(); + + context.translate(ship.position.getX(), ship.position.getY()); + context.rotate(angle); + context.beginPath(); + context.moveTo(10, 0); + context.lineTo(-10, -7); + context.lineTo(-10, 7 ); + context.lineTo(10, 0); + if(thrusting) { + context.moveTo(-10, 0); + context.lineTo(-18, 0); + } + context.stroke(); + + context.restore(); + + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/episode10/vector.js b/episode10/vector.js index 609f6d5..4d66796 100644 --- a/episode10/vector.js +++ b/episode10/vector.js @@ -1,83 +1,83 @@ -var vector = { - _x: 1, - _y: 0, - - create: function(x, y) { - var obj = Object.create(this); - obj.setX(x); - obj.setY(y); - return obj; - }, - - setX: function(value) { - this._x = value; - }, - - getX: function() { - return this._x; - }, - - setY: function(value) { - this._y = value; - }, - - getY: function() { - return this._y; - }, - - setAngle: function(angle) { - var length = this.getLength(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getAngle: function() { - return Math.atan2(this._y, this._x); - }, - - setLength: function(length) { - var angle = this.getAngle(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getLength: function() { - return Math.sqrt(this._x * this._x + this._y * this._y); - }, - - add: function(v2) { - return vector.create(this._x + v2.getX(), this._y + v2.getY()); - }, - - subtract: function(v2) { - return vector.create(this._x - v2.getX(), this._y - v2.getY()); - }, - - multiply: function(val) { - return vector.create(this._x * val, this._y * val); - }, - - divide: function(val) { - return vector.create(this._x / val, this._y / val); - }, - - addTo: function(v2) { - this._x += v2.getX(); - this._y += v2.getY(); - }, - - subtractFrom: function(v2) { - this._x -= v2.getX(); - this._y -= v2.getY(); - }, - - multiplyBy: function(val) { - this._x *= val; - this._y *= val; - }, - - divideBy: function(val) { - this._x /= val; - this._y /= val; - } +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } }; \ No newline at end of file diff --git a/episode11/animation_template.js b/episode11/animation_template.js index e557225..916d3d5 100644 --- a/episode11/animation_template.js +++ b/episode11/animation_template.js @@ -1,17 +1,17 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - update(); - - - function update() { - context.clearRect(0, 0, width, height); - - // animation goes here - - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + update(); + + + function update() { + context.clearRect(0, 0, width, height); + + // animation goes here + + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/episode11/index.html b/episode11/index.html index f6702d7..532a094 100644 --- a/episode11/index.html +++ b/episode11/index.html @@ -1,22 +1,22 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/episode11/main.js b/episode11/main.js index 213c791..b1a6483 100644 --- a/episode11/main.js +++ b/episode11/main.js @@ -1,34 +1,34 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - sun = particle.create(width / 2, height / 2, 0, 0), - planet = particle.create(width / 2 + 200, height / 2, 10, -Math.PI / 2); - - sun.mass = 100000; - - update(); - - - function update() { - context.clearRect(0, 0, width, height); - - planet.gravitateTo(sun); - planet.update(); - - context.beginPath(); - context.fillStyle = "#ffff00"; - context.arc(sun.position.getX(), sun.position.getY(), 20, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.fillStyle = "#0000ff"; - context.arc(planet.position.getX(), planet.position.getY(), 5, 0, Math.PI * 2, false); - context.fill(); - - // animation goes here - - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + sun = particle.create(width / 2, height / 2, 0, 0), + planet = particle.create(width / 2 + 200, height / 2, 10, -Math.PI / 2); + + sun.mass = 100000; + + update(); + + + function update() { + context.clearRect(0, 0, width, height); + + planet.gravitateTo(sun); + planet.update(); + + context.beginPath(); + context.fillStyle = "#ffff00"; + context.arc(sun.position.getX(), sun.position.getY(), 20, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.fillStyle = "#0000ff"; + context.arc(planet.position.getX(), planet.position.getY(), 5, 0, Math.PI * 2, false); + context.fill(); + + // animation goes here + + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/episode11/orbit.js b/episode11/orbit.js index 3a0b3b8..d4fa70f 100644 --- a/episode11/orbit.js +++ b/episode11/orbit.js @@ -1,34 +1,34 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - sun = particle.create(width / 2, height / 2, 0, 0); - planet = particle.create(width / 2 + 200, height / 2, 10, -Math.PI / 2); - - sun.mass = 20000; - - update(); - - - function update() { - context.clearRect(0, 0, width, height); - - // animation goes here - - planet.gravitateTo(sun); - planet.update(); - - context.beginPath(); - context.fillStyle = "#ffff00"; - context.arc(sun.position.getX(), sun.position.getY(), 20, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.fillStyle = "#0000ff"; - context.arc(planet.position.getX(), planet.position.getY(), 4, 0, Math.PI * 2, false); - context.fill(); - - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + sun = particle.create(width / 2, height / 2, 0, 0); + planet = particle.create(width / 2 + 200, height / 2, 10, -Math.PI / 2); + + sun.mass = 20000; + + update(); + + + function update() { + context.clearRect(0, 0, width, height); + + // animation goes here + + planet.gravitateTo(sun); + planet.update(); + + context.beginPath(); + context.fillStyle = "#ffff00"; + context.arc(sun.position.getX(), sun.position.getY(), 20, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.fillStyle = "#0000ff"; + context.arc(planet.position.getX(), planet.position.getY(), 4, 0, Math.PI * 2, false); + context.fill(); + + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/episode11/particle.js b/episode11/particle.js index 5959aeb..af3e0a2 100644 --- a/episode11/particle.js +++ b/episode11/particle.js @@ -1,42 +1,42 @@ -var particle = { - position: null, - velocity: null, - mass: 1, - - create: function(x, y, speed, direction) { - var obj = Object.create(this); - obj.position = vector.create(x, y); - obj.velocity = vector.create(0, 0); - obj.velocity.setLength(speed); - obj.velocity.setAngle(direction); - return obj; - }, - - accelerate: function(accel) { - this.velocity.addTo(accel); - }, - - update: function() { - this.position.addTo(this.velocity); - }, - - angleTo: function(p2) { - return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); - }, - - distanceTo: function(p2) { - var dx = p2.position.getX() - this.position.getX(), - dy = p2.position.getY() - this.position.getY(); - - return Math.sqrt(dx * dx + dy * dy); - }, - - gravitateTo: function(p2) { - var grav = vector.create(0, 0), - dist = this.distanceTo(p2); - - grav.setLength(p2.mass / (dist * dist)); - grav.setAngle(this.angleTo(p2)); - this.velocity.addTo(grav); - } +var particle = { + position: null, + velocity: null, + mass: 1, + + create: function(x, y, speed, direction) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + return obj; + }, + + accelerate: function(accel) { + this.velocity.addTo(accel); + }, + + update: function() { + this.position.addTo(this.velocity); + }, + + angleTo: function(p2) { + return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); + }, + + distanceTo: function(p2) { + var dx = p2.position.getX() - this.position.getX(), + dy = p2.position.getY() - this.position.getY(); + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var grav = vector.create(0, 0), + dist = this.distanceTo(p2); + + grav.setLength(p2.mass / (dist * dist)); + grav.setAngle(this.angleTo(p2)); + this.velocity.addTo(grav); + } }; \ No newline at end of file diff --git a/episode11/vector.js b/episode11/vector.js index 609f6d5..4d66796 100644 --- a/episode11/vector.js +++ b/episode11/vector.js @@ -1,83 +1,83 @@ -var vector = { - _x: 1, - _y: 0, - - create: function(x, y) { - var obj = Object.create(this); - obj.setX(x); - obj.setY(y); - return obj; - }, - - setX: function(value) { - this._x = value; - }, - - getX: function() { - return this._x; - }, - - setY: function(value) { - this._y = value; - }, - - getY: function() { - return this._y; - }, - - setAngle: function(angle) { - var length = this.getLength(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getAngle: function() { - return Math.atan2(this._y, this._x); - }, - - setLength: function(length) { - var angle = this.getAngle(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getLength: function() { - return Math.sqrt(this._x * this._x + this._y * this._y); - }, - - add: function(v2) { - return vector.create(this._x + v2.getX(), this._y + v2.getY()); - }, - - subtract: function(v2) { - return vector.create(this._x - v2.getX(), this._y - v2.getY()); - }, - - multiply: function(val) { - return vector.create(this._x * val, this._y * val); - }, - - divide: function(val) { - return vector.create(this._x / val, this._y / val); - }, - - addTo: function(v2) { - this._x += v2.getX(); - this._y += v2.getY(); - }, - - subtractFrom: function(v2) { - this._x -= v2.getX(); - this._y -= v2.getY(); - }, - - multiplyBy: function(val) { - this._x *= val; - this._y *= val; - }, - - divideBy: function(val) { - this._x /= val; - this._y /= val; - } +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } }; \ No newline at end of file diff --git a/episode12/bounce.js b/episode12/bounce.js index 8151aeb..dc376ce 100644 --- a/episode12/bounce.js +++ b/episode12/bounce.js @@ -1,41 +1,41 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - p = particle.create(width / 2, height / 2, 5, Math.random() * Math.PI * 2, 0.1); - - p.radius = 40; - p.bounce = -0.9; - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - p.update(); - - context.beginPath(); - context.arc(p.position.getX(), p.position.getY(), p.radius, 0, Math.PI * 2, false); - context.fill(); - - if(p.position.getX() + p.radius > width) { - p.position.setX(width - p.radius); - p.velocity.setX(p.velocity.getX() * p.bounce); - } - if(p.position.getX() - p.radius < 0) { - p.position.setX(p.radius); - p.velocity.setX(p.velocity.getX() * p.bounce); - } - if(p.position.getY() + p.radius > height) { - p.position.setY(height - p.radius); - p.velocity.setY(p.velocity.getY() * p.bounce); - } - if(p.position.getY() - p.radius < 0) { - p.position.setY(p.radius); - p.velocity.setY(p.velocity.getY() * p.bounce); - } - - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p = particle.create(width / 2, height / 2, 5, Math.random() * Math.PI * 2, 0.1); + + p.radius = 40; + p.bounce = -0.9; + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + p.update(); + + context.beginPath(); + context.arc(p.position.getX(), p.position.getY(), p.radius, 0, Math.PI * 2, false); + context.fill(); + + if(p.position.getX() + p.radius > width) { + p.position.setX(width - p.radius); + p.velocity.setX(p.velocity.getX() * p.bounce); + } + if(p.position.getX() - p.radius < 0) { + p.position.setX(p.radius); + p.velocity.setX(p.velocity.getX() * p.bounce); + } + if(p.position.getY() + p.radius > height) { + p.position.setY(height - p.radius); + p.velocity.setY(p.velocity.getY() * p.bounce); + } + if(p.position.getY() - p.radius < 0) { + p.position.setY(p.radius); + p.velocity.setY(p.velocity.getY() * p.bounce); + } + + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/episode12/index.html b/episode12/index.html index 4618452..b7716e8 100644 --- a/episode12/index.html +++ b/episode12/index.html @@ -1,22 +1,22 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/episode12/particle.js b/episode12/particle.js index 4139869..fe49a65 100644 --- a/episode12/particle.js +++ b/episode12/particle.js @@ -1,47 +1,47 @@ -var particle = { - position: null, - velocity: null, - mass: 1, - radius: 0, - bounce: -1, - gravity: 0, - - create: function(x, y, speed, direction, grav) { - var obj = Object.create(this); - obj.position = vector.create(x, y); - obj.velocity = vector.create(0, 0); - obj.velocity.setLength(speed); - obj.velocity.setAngle(direction); - obj.gravity = vector.create(0, grav || 0); - return obj; - }, - - accelerate: function(accel) { - this.velocity.addTo(accel); - }, - - update: function() { - this.velocity.addTo(this.gravity); - this.position.addTo(this.velocity); - }, - - angleTo: function(p2) { - return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); - }, - - distanceTo: function(p2) { - var dx = p2.position.getX() - this.position.getX(), - dy = p2.position.getY() - this.position.getY(); - - return Math.sqrt(dx * dx + dy * dy); - }, - - gravitateTo: function(p2) { - var grav = vector.create(0, 0), - dist = this.distanceTo(p2); - - grav.setLength(p2.mass / (dist * dist)); - grav.setAngle(this.angleTo(p2)); - this.velocity.addTo(grav); - } +var particle = { + position: null, + velocity: null, + mass: 1, + radius: 0, + bounce: -1, + gravity: 0, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + obj.gravity = vector.create(0, grav || 0); + return obj; + }, + + accelerate: function(accel) { + this.velocity.addTo(accel); + }, + + update: function() { + this.velocity.addTo(this.gravity); + this.position.addTo(this.velocity); + }, + + angleTo: function(p2) { + return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); + }, + + distanceTo: function(p2) { + var dx = p2.position.getX() - this.position.getX(), + dy = p2.position.getY() - this.position.getY(); + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var grav = vector.create(0, 0), + dist = this.distanceTo(p2); + + grav.setLength(p2.mass / (dist * dist)); + grav.setAngle(this.angleTo(p2)); + this.velocity.addTo(grav); + } }; \ No newline at end of file diff --git a/episode12/regen.js b/episode12/regen.js index 1951134..c6fb0ad 100644 --- a/episode12/regen.js +++ b/episode12/regen.js @@ -1,41 +1,41 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - particles = []; - - for(var i = 0; i < 100; i += 1) { - var p = particle.create(width / 2, height, Math.random() * 8 + 5, -Math.PI / 2 + (Math.random() * .2 - .1), 0.1); - p.radius = Math.random() * 10 + 2; - particles.push(p); - } - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - - for(var i = 0; i < 100; i += 1) { - var p = particles[i]; - - p.update(); - - context.beginPath(); - context.arc(p.position.getX(), p.position.getY(), p.radius, 0, Math.PI * 2, false); - context.fill(); - - if(p.position.getY() - p.radius > height) { - p.position.setX(width / 2); - p.position.setY(height); - p.velocity.setLength(Math.random() * 8 + 5); - p.velocity.setAngle(-Math.PI / 2 + (Math.random() * .2 - .1)); - } - - } - - requestAnimationFrame(update); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + particles = []; + + for(var i = 0; i < 100; i += 1) { + var p = particle.create(width / 2, height, Math.random() * 8 + 5, -Math.PI / 2 + (Math.random() * .2 - .1), 0.1); + p.radius = Math.random() * 10 + 2; + particles.push(p); + } + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + + for(var i = 0; i < 100; i += 1) { + var p = particles[i]; + + p.update(); + + context.beginPath(); + context.arc(p.position.getX(), p.position.getY(), p.radius, 0, Math.PI * 2, false); + context.fill(); + + if(p.position.getY() - p.radius > height) { + p.position.setX(width / 2); + p.position.setY(height); + p.velocity.setLength(Math.random() * 8 + 5); + p.velocity.setAngle(-Math.PI / 2 + (Math.random() * .2 - .1)); + } + + } + + requestAnimationFrame(update); + } + }; \ No newline at end of file diff --git a/episode12/regen_extra.js b/episode12/regen_extra.js index d2a5b1c..3737ff9 100644 --- a/episode12/regen_extra.js +++ b/episode12/regen_extra.js @@ -1,42 +1,42 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - particles = []; - - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - // if we have less than 100 particles, create one and add it to the array - // once we have 100, this will be skipped. - if(particles.length < 100) { - var p = particle.create(width / 2, height, 5 + Math.random() * 8, -Math.PI / 2 + (Math.random() * .2 - .1), 0.1); - p.radius = Math.random() * 10 + 2; - particles.push(p); - } - - for(var i = 0; i < particles.length; i += 1) { - var p = particles[i]; - - p.update(); - - context.beginPath(); - context.arc(p.position.getX(), p.position.getY(), p.radius, 0, Math.PI * 2, false); - context.fill(); - - if(p.position.getY() - p.radius > height) { - p.position.setX(width / 2); - p.position.setY(height); - p.velocity.setLength(5 + Math.random() * 8); - p.velocity.setAngle(-Math.PI / 2 + (Math.random() * .2 - .1)); - } - } - - requestAnimationFrame(update); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + particles = []; + + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + // if we have less than 100 particles, create one and add it to the array + // once we have 100, this will be skipped. + if(particles.length < 100) { + var p = particle.create(width / 2, height, 5 + Math.random() * 8, -Math.PI / 2 + (Math.random() * .2 - .1), 0.1); + p.radius = Math.random() * 10 + 2; + particles.push(p); + } + + for(var i = 0; i < particles.length; i += 1) { + var p = particles[i]; + + p.update(); + + context.beginPath(); + context.arc(p.position.getX(), p.position.getY(), p.radius, 0, Math.PI * 2, false); + context.fill(); + + if(p.position.getY() - p.radius > height) { + p.position.setX(width / 2); + p.position.setY(height); + p.velocity.setLength(5 + Math.random() * 8); + p.velocity.setAngle(-Math.PI / 2 + (Math.random() * .2 - .1)); + } + } + + requestAnimationFrame(update); + } + }; \ No newline at end of file diff --git a/episode12/removal.js b/episode12/removal.js index a02bf65..3ff77e8 100644 --- a/episode12/removal.js +++ b/episode12/removal.js @@ -1,51 +1,51 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - particles = []; - - for(var i = 0; i < 100; i += 1) { - var p = particle.create(width / 2, height / 2, Math.random() * 5 + 2, Math.random() * Math.PI * 2); - p.radius = 10; - particles.push(p); - } - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - console.log(particles.length); - - - for(var i = 0; i < particles.length; i += 1) { - var p = particles[i]; - - p.update(); - - context.beginPath(); - context.arc(p.position.getX(), p.position.getY(), p.radius, 0, Math.PI * 2, false); - context.fill(); - - } - - removeDeadParticles(); - - requestAnimationFrame(update); - } - - - function removeDeadParticles() { - for(var i = particles.length - 1; i >= 0; i -= 1) { - var p = particles[i]; - if(p.position.getX() - p.radius > width || - p.position.getX() + p.radius < 0 || - p.position.getY() - p.radius > height || - p.position.getY() + p.radius < 0) { - - particles.splice(i, 1); - } - } - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + particles = []; + + for(var i = 0; i < 100; i += 1) { + var p = particle.create(width / 2, height / 2, Math.random() * 5 + 2, Math.random() * Math.PI * 2); + p.radius = 10; + particles.push(p); + } + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + console.log(particles.length); + + + for(var i = 0; i < particles.length; i += 1) { + var p = particles[i]; + + p.update(); + + context.beginPath(); + context.arc(p.position.getX(), p.position.getY(), p.radius, 0, Math.PI * 2, false); + context.fill(); + + } + + removeDeadParticles(); + + requestAnimationFrame(update); + } + + + function removeDeadParticles() { + for(var i = particles.length - 1; i >= 0; i -= 1) { + var p = particles[i]; + if(p.position.getX() - p.radius > width || + p.position.getX() + p.radius < 0 || + p.position.getY() - p.radius > height || + p.position.getY() + p.radius < 0) { + + particles.splice(i, 1); + } + } + } }; \ No newline at end of file diff --git a/episode12/vector.js b/episode12/vector.js index 609f6d5..4d66796 100644 --- a/episode12/vector.js +++ b/episode12/vector.js @@ -1,83 +1,83 @@ -var vector = { - _x: 1, - _y: 0, - - create: function(x, y) { - var obj = Object.create(this); - obj.setX(x); - obj.setY(y); - return obj; - }, - - setX: function(value) { - this._x = value; - }, - - getX: function() { - return this._x; - }, - - setY: function(value) { - this._y = value; - }, - - getY: function() { - return this._y; - }, - - setAngle: function(angle) { - var length = this.getLength(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getAngle: function() { - return Math.atan2(this._y, this._x); - }, - - setLength: function(length) { - var angle = this.getAngle(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getLength: function() { - return Math.sqrt(this._x * this._x + this._y * this._y); - }, - - add: function(v2) { - return vector.create(this._x + v2.getX(), this._y + v2.getY()); - }, - - subtract: function(v2) { - return vector.create(this._x - v2.getX(), this._y - v2.getY()); - }, - - multiply: function(val) { - return vector.create(this._x * val, this._y * val); - }, - - divide: function(val) { - return vector.create(this._x / val, this._y / val); - }, - - addTo: function(v2) { - this._x += v2.getX(); - this._y += v2.getY(); - }, - - subtractFrom: function(v2) { - this._x -= v2.getX(); - this._y -= v2.getY(); - }, - - multiplyBy: function(val) { - this._x *= val; - this._y *= val; - }, - - divideBy: function(val) { - this._x /= val; - this._y /= val; - } +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } }; \ No newline at end of file diff --git a/episode12/wrapping.js b/episode12/wrapping.js index a5706b0..f698acd 100644 --- a/episode12/wrapping.js +++ b/episode12/wrapping.js @@ -1,38 +1,38 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - p = particle.create(width / 2, height / 2, 3, Math.random() * Math.PI * 2); - - p.radius = 50; - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - - p.update(); - - context.beginPath(); - context.arc(p.position.getX(), p.position.getY(), p.radius, 0, Math.PI * 2, false); - context.fill(); - - if(p.position.getX() - p.radius > width) { - p.position.setX(-p.radius); - } - if(p.position.getX() + p.radius < 0) { - p.position.setX(width + p.radius); - } - if(p.position.getY() - p.radius > height) { - p.position.setY(-p.radius); - } - if(p.position.getY() + p.radius < 0) { - p.position.setY(height + p.radius); - } - - - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p = particle.create(width / 2, height / 2, 3, Math.random() * Math.PI * 2); + + p.radius = 50; + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + + p.update(); + + context.beginPath(); + context.arc(p.position.getX(), p.position.getY(), p.radius, 0, Math.PI * 2, false); + context.fill(); + + if(p.position.getX() - p.radius > width) { + p.position.setX(-p.radius); + } + if(p.position.getX() + p.radius < 0) { + p.position.setX(width + p.radius); + } + if(p.position.getY() - p.radius > height) { + p.position.setY(-p.radius); + } + if(p.position.getY() + p.radius < 0) { + p.position.setY(height + p.radius); + } + + + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/episode13/friction1.js b/episode13/friction1.js index 8b719e7..a10a61b 100644 --- a/episode13/friction1.js +++ b/episode13/friction1.js @@ -1,33 +1,33 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - p = particle.create(width / 2, height / 2, 10, Math.random() * Math.PI * 2), - friction = vector.create(0.15, 0); - - p.radius = 10; - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - friction.setAngle(p.velocity.getAngle()); - - if(p.velocity.getLength() > friction.getLength()) { - p.velocity.subtractFrom(friction); - } - else { - p.velocity.setLength(0); - } - - p.update(); - - context.beginPath(); - context.arc(p.position.getX(), p.position.getY(), p.radius, 0, Math.PI * 2, false); - context.fill(); - - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p = particle.create(width / 2, height / 2, 10, Math.random() * Math.PI * 2), + friction = vector.create(0.15, 0); + + p.radius = 10; + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + friction.setAngle(p.velocity.getAngle()); + + if(p.velocity.getLength() > friction.getLength()) { + p.velocity.subtractFrom(friction); + } + else { + p.velocity.setLength(0); + } + + p.update(); + + context.beginPath(); + context.arc(p.position.getX(), p.position.getY(), p.radius, 0, Math.PI * 2, false); + context.fill(); + + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/episode13/friction2.js b/episode13/friction2.js index e5b5e40..46ec238 100644 --- a/episode13/friction2.js +++ b/episode13/friction2.js @@ -1,26 +1,26 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - p = particle.create(width / 2, height / 2, 10, Math.random() * Math.PI * 2), - friction = 0.97; - - p.radius = 10; - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - p.velocity.multiplyBy(friction); - p.update(); - - context.beginPath(); - context.arc(p.position.getX(), p.position.getY(), p.radius, 0, Math.PI * 2, false); - context.fill(); - - requestAnimationFrame(update); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p = particle.create(width / 2, height / 2, 10, Math.random() * Math.PI * 2), + friction = 0.97; + + p.radius = 10; + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + p.velocity.multiplyBy(friction); + p.update(); + + context.beginPath(); + context.arc(p.position.getX(), p.position.getY(), p.radius, 0, Math.PI * 2, false); + context.fill(); + + requestAnimationFrame(update); + } + }; \ No newline at end of file diff --git a/episode13/index.html b/episode13/index.html index 9ad4a10..1ac566f 100644 --- a/episode13/index.html +++ b/episode13/index.html @@ -1,22 +1,22 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/episode13/particle.js b/episode13/particle.js index 2269cf9..53e94c1 100644 --- a/episode13/particle.js +++ b/episode13/particle.js @@ -1,49 +1,49 @@ -var particle = { - position: null, - velocity: null, - mass: 1, - radius: 0, - bounce: -1, - friction: 1, - gravity: 0, - - create: function(x, y, speed, direction, grav) { - var obj = Object.create(this); - obj.position = vector.create(x, y); - obj.velocity = vector.create(0, 0); - obj.velocity.setLength(speed); - obj.velocity.setAngle(direction); - obj.gravity = vector.create(0, grav || 0); - return obj; - }, - - accelerate: function(accel) { - this.velocity.addTo(accel); - }, - - update: function() { - this.velocity.multiplyBy(this.friction); - this.velocity.addTo(this.gravity); - this.position.addTo(this.velocity); - }, - - angleTo: function(p2) { - return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); - }, - - distanceTo: function(p2) { - var dx = p2.position.getX() - this.position.getX(), - dy = p2.position.getY() - this.position.getY(); - - return Math.sqrt(dx * dx + dy * dy); - }, - - gravitateTo: function(p2) { - var grav = vector.create(0, 0), - dist = this.distanceTo(p2); - - grav.setLength(p2.mass / (dist * dist)); - grav.setAngle(this.angleTo(p2)); - this.velocity.addTo(grav); - } +var particle = { + position: null, + velocity: null, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + obj.gravity = vector.create(0, grav || 0); + return obj; + }, + + accelerate: function(accel) { + this.velocity.addTo(accel); + }, + + update: function() { + this.velocity.multiplyBy(this.friction); + this.velocity.addTo(this.gravity); + this.position.addTo(this.velocity); + }, + + angleTo: function(p2) { + return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); + }, + + distanceTo: function(p2) { + var dx = p2.position.getX() - this.position.getX(), + dy = p2.position.getY() - this.position.getY(); + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var grav = vector.create(0, 0), + dist = this.distanceTo(p2); + + grav.setLength(p2.mass / (dist * dist)); + grav.setAngle(this.angleTo(p2)); + this.velocity.addTo(grav); + } }; \ No newline at end of file diff --git a/episode13/ship2.js b/episode13/ship2.js index a93b849..26de8f0 100644 --- a/episode13/ship2.js +++ b/episode13/ship2.js @@ -1,102 +1,102 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight - ship = particle.create(width / 2, height / 2, 0, 0), - thrust = vector.create(0, 0), - angle = 0, - turningLeft = false, - turningRight = false, - thrusting = false; - - ship.friction = 0.99; - - document.body.addEventListener("keydown", function(event) { - // console.log(event.keyCode); - switch(event.keyCode) { - case 38: // up - thrusting = true; - break; - case 37: // left - turningLeft = true; - break; - case 39: // right - turningRight = true; - default: - break - } - }); - - document.body.addEventListener("keyup", function(event) { - // console.log(event.keyCode); - switch(event.keyCode) { - case 38: // up - thrusting = false; - break; - case 37: // left - turningLeft = false; - break; - case 39: // right - turningRight = false; - default: - break - } - }); - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - if(turningRight) { - angle += .05; - } - if(turningLeft) { - angle -= .05; - } - - if(thrusting) { - thrust.setLength(.1); - } - else { - thrust.setLength(0); - } - thrust.setAngle(angle); - - ship.accelerate(thrust); - ship.update(); - - if(ship.position.getX() > width) { - ship.position.setX(0); - } - if(ship.position.getX() < 0) { - ship.position.setX(width); - } - if(ship.position.getY() > height) { - ship.position.setY(0); - } - if(ship.position.getY() < 0) { - ship.position.setY(height); - } - - context.save(); - - context.translate(ship.position.getX(), ship.position.getY()); - context.rotate(angle); - context.beginPath(); - context.moveTo(10, 0); - context.lineTo(-10, -7); - context.lineTo(-10, 7 ); - context.lineTo(10, 0); - if(thrusting) { - context.moveTo(-10, 0); - context.lineTo(-18, 0); - } - context.stroke(); - - context.restore(); - - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight + ship = particle.create(width / 2, height / 2, 0, 0), + thrust = vector.create(0, 0), + angle = 0, + turningLeft = false, + turningRight = false, + thrusting = false; + + ship.friction = 0.99; + + document.body.addEventListener("keydown", function(event) { + // console.log(event.keyCode); + switch(event.keyCode) { + case 38: // up + thrusting = true; + break; + case 37: // left + turningLeft = true; + break; + case 39: // right + turningRight = true; + default: + break + } + }); + + document.body.addEventListener("keyup", function(event) { + // console.log(event.keyCode); + switch(event.keyCode) { + case 38: // up + thrusting = false; + break; + case 37: // left + turningLeft = false; + break; + case 39: // right + turningRight = false; + default: + break + } + }); + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + if(turningRight) { + angle += .05; + } + if(turningLeft) { + angle -= .05; + } + + if(thrusting) { + thrust.setLength(.1); + } + else { + thrust.setLength(0); + } + thrust.setAngle(angle); + + ship.accelerate(thrust); + ship.update(); + + if(ship.position.getX() > width) { + ship.position.setX(0); + } + if(ship.position.getX() < 0) { + ship.position.setX(width); + } + if(ship.position.getY() > height) { + ship.position.setY(0); + } + if(ship.position.getY() < 0) { + ship.position.setY(height); + } + + context.save(); + + context.translate(ship.position.getX(), ship.position.getY()); + context.rotate(angle); + context.beginPath(); + context.moveTo(10, 0); + context.lineTo(-10, -7); + context.lineTo(-10, 7 ); + context.lineTo(10, 0); + if(thrusting) { + context.moveTo(-10, 0); + context.lineTo(-18, 0); + } + context.stroke(); + + context.restore(); + + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/episode13/vector.js b/episode13/vector.js index 609f6d5..4d66796 100644 --- a/episode13/vector.js +++ b/episode13/vector.js @@ -1,83 +1,83 @@ -var vector = { - _x: 1, - _y: 0, - - create: function(x, y) { - var obj = Object.create(this); - obj.setX(x); - obj.setY(y); - return obj; - }, - - setX: function(value) { - this._x = value; - }, - - getX: function() { - return this._x; - }, - - setY: function(value) { - this._y = value; - }, - - getY: function() { - return this._y; - }, - - setAngle: function(angle) { - var length = this.getLength(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getAngle: function() { - return Math.atan2(this._y, this._x); - }, - - setLength: function(length) { - var angle = this.getAngle(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getLength: function() { - return Math.sqrt(this._x * this._x + this._y * this._y); - }, - - add: function(v2) { - return vector.create(this._x + v2.getX(), this._y + v2.getY()); - }, - - subtract: function(v2) { - return vector.create(this._x - v2.getX(), this._y - v2.getY()); - }, - - multiply: function(val) { - return vector.create(this._x * val, this._y * val); - }, - - divide: function(val) { - return vector.create(this._x / val, this._y / val); - }, - - addTo: function(v2) { - this._x += v2.getX(); - this._y += v2.getY(); - }, - - subtractFrom: function(v2) { - this._x -= v2.getX(); - this._y -= v2.getY(); - }, - - multiplyBy: function(val) { - this._x *= val; - this._y *= val; - }, - - divideBy: function(val) { - this._x /= val; - this._y /= val; - } +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } }; \ No newline at end of file diff --git a/episode14/circle-circle.js b/episode14/circle-circle.js index 6338230..258490d 100644 --- a/episode14/circle-circle.js +++ b/episode14/circle-circle.js @@ -1,43 +1,43 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - circle0 = { - x: Math.random() * width, - y: Math.random() * height, - radius: 50 + Math.random() * 100 - }, - - circle1 = { - x: Math.random() * width, - y: Math.random() * height, - radius: 50 + Math.random() * 100 - }; - - document.body.addEventListener("mousemove", function(event) { - circle1.x = event.clientX; - circle1.y = event.clientY; - - if(utils.circleCollision(circle0, circle1)) { - context.fillStyle = "#f66"; - } - else { - context.fillStyle = "#999"; - } - - context.clearRect(0, 0, width, height); - context.beginPath(); - context.arc(circle0.x, circle0.y, circle0.radius, - 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(circle1.x, circle1.y, circle1.radius, - 0, Math.PI * 2, false); - context.fill(); - - }) - - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + circle0 = { + x: Math.random() * width, + y: Math.random() * height, + radius: 50 + Math.random() * 100 + }, + + circle1 = { + x: Math.random() * width, + y: Math.random() * height, + radius: 50 + Math.random() * 100 + }; + + document.body.addEventListener("mousemove", function(event) { + circle1.x = event.clientX; + circle1.y = event.clientY; + + if(utils.circleCollision(circle0, circle1)) { + context.fillStyle = "#f66"; + } + else { + context.fillStyle = "#999"; + } + + context.clearRect(0, 0, width, height); + context.beginPath(); + context.arc(circle0.x, circle0.y, circle0.radius, + 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(circle1.x, circle1.y, circle1.radius, + 0, Math.PI * 2, false); + context.fill(); + + }) + + }; \ No newline at end of file diff --git a/episode14/circle-point.js b/episode14/circle-point.js index 4e09e9f..03e31b8 100644 --- a/episode14/circle-point.js +++ b/episode14/circle-point.js @@ -1,30 +1,30 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - circle = { - x: Math.random() * width, - y: Math.random() * height, - radius: 50 + Math.random() * 100 - }; - - document.body.addEventListener("mousemove", function(event) { - - if(utils.circlePointCollision(event.clientX, event.clientY, circle)) { - context.fillStyle = "#f66"; - } - else { - context.fillStyle = "#999"; - } - - context.clearRect(0, 0, width, height); - context.beginPath(); - context.arc(circle.x, circle.y, circle.radius, - 0, Math.PI * 2, false); - context.fill(); - - }) - - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + circle = { + x: Math.random() * width, + y: Math.random() * height, + radius: 50 + Math.random() * 100 + }; + + document.body.addEventListener("mousemove", function(event) { + + if(utils.circlePointCollision(event.clientX, event.clientY, circle)) { + context.fillStyle = "#f66"; + } + else { + context.fillStyle = "#999"; + } + + context.clearRect(0, 0, width, height); + context.beginPath(); + context.arc(circle.x, circle.y, circle.radius, + 0, Math.PI * 2, false); + context.fill(); + + }) + + }; \ No newline at end of file diff --git a/episode14/index.html b/episode14/index.html index b9547fa..df145f8 100644 --- a/episode14/index.html +++ b/episode14/index.html @@ -1,23 +1,23 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/episode14/main.js b/episode14/main.js index 44dc5bd..61deb1f 100644 --- a/episode14/main.js +++ b/episode14/main.js @@ -1,9 +1,9 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + + }; \ No newline at end of file diff --git a/episode14/particle.js b/episode14/particle.js index 2269cf9..53e94c1 100644 --- a/episode14/particle.js +++ b/episode14/particle.js @@ -1,49 +1,49 @@ -var particle = { - position: null, - velocity: null, - mass: 1, - radius: 0, - bounce: -1, - friction: 1, - gravity: 0, - - create: function(x, y, speed, direction, grav) { - var obj = Object.create(this); - obj.position = vector.create(x, y); - obj.velocity = vector.create(0, 0); - obj.velocity.setLength(speed); - obj.velocity.setAngle(direction); - obj.gravity = vector.create(0, grav || 0); - return obj; - }, - - accelerate: function(accel) { - this.velocity.addTo(accel); - }, - - update: function() { - this.velocity.multiplyBy(this.friction); - this.velocity.addTo(this.gravity); - this.position.addTo(this.velocity); - }, - - angleTo: function(p2) { - return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); - }, - - distanceTo: function(p2) { - var dx = p2.position.getX() - this.position.getX(), - dy = p2.position.getY() - this.position.getY(); - - return Math.sqrt(dx * dx + dy * dy); - }, - - gravitateTo: function(p2) { - var grav = vector.create(0, 0), - dist = this.distanceTo(p2); - - grav.setLength(p2.mass / (dist * dist)); - grav.setAngle(this.angleTo(p2)); - this.velocity.addTo(grav); - } +var particle = { + position: null, + velocity: null, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + obj.gravity = vector.create(0, grav || 0); + return obj; + }, + + accelerate: function(accel) { + this.velocity.addTo(accel); + }, + + update: function() { + this.velocity.multiplyBy(this.friction); + this.velocity.addTo(this.gravity); + this.position.addTo(this.velocity); + }, + + angleTo: function(p2) { + return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); + }, + + distanceTo: function(p2) { + var dx = p2.position.getX() - this.position.getX(), + dy = p2.position.getY() - this.position.getY(); + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var grav = vector.create(0, 0), + dist = this.distanceTo(p2); + + grav.setLength(p2.mass / (dist * dist)); + grav.setAngle(this.angleTo(p2)); + this.velocity.addTo(grav); + } }; \ No newline at end of file diff --git a/episode14/rect-point.js b/episode14/rect-point.js index 6aba12b..8e34b5b 100644 --- a/episode14/rect-point.js +++ b/episode14/rect-point.js @@ -1,24 +1,24 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - rect = { - x: 300, - y: 200, - width: -200, - height: -100 - }; - - document.body.addEventListener("mousemove", function(event) { - - context.clearRect(0, 0, width, height); - if(utils.pointInRect(event.clientX, event.clientY, rect)) { - context.fillStyle = "#ff6666"; - } - else { - context.fillStyle = "#999999"; - } - context.fillRect(rect.x, rect.y, rect.width, rect.height); - }) +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + rect = { + x: 300, + y: 200, + width: -200, + height: -100 + }; + + document.body.addEventListener("mousemove", function(event) { + + context.clearRect(0, 0, width, height); + if(utils.pointInRect(event.clientX, event.clientY, rect)) { + context.fillStyle = "#ff6666"; + } + else { + context.fillStyle = "#999999"; + } + context.fillRect(rect.x, rect.y, rect.width, rect.height); + }) }; \ No newline at end of file diff --git a/episode14/rect-rect.js b/episode14/rect-rect.js index 1da4d0d..9dfc79a 100644 --- a/episode14/rect-rect.js +++ b/episode14/rect-rect.js @@ -1,36 +1,36 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - rect0 = { - x: 200, - y: 200, - width: -200, - height: -100 - }, - rect1 = { - x: 0, - y: 0, - width: -100, - height: -200 - }; - - document.body.addEventListener("mousemove", function(event) { - rect1.x = event.clientX - 50; - rect1.y = event.clientY - 100; - - context.clearRect(0, 0, width, height); - if(utils.rectIntersect(rect0, rect1)) { - context.fillStyle = "#ff6666"; - } - else { - context.fillStyle = "#999999"; - } - context.fillRect(rect0.x, rect0.y, rect0.width, rect0.height); - context.fillRect(rect1.x, rect1.y, rect1.width, rect1.height); - }) - - - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + rect0 = { + x: 200, + y: 200, + width: -200, + height: -100 + }, + rect1 = { + x: 0, + y: 0, + width: -100, + height: -200 + }; + + document.body.addEventListener("mousemove", function(event) { + rect1.x = event.clientX - 50; + rect1.y = event.clientY - 100; + + context.clearRect(0, 0, width, height); + if(utils.rectIntersect(rect0, rect1)) { + context.fillStyle = "#ff6666"; + } + else { + context.fillStyle = "#999999"; + } + context.fillRect(rect0.x, rect0.y, rect0.width, rect0.height); + context.fillRect(rect1.x, rect1.y, rect1.width, rect1.height); + }) + + + }; \ No newline at end of file diff --git a/episode14/utils.js b/episode14/utils.js index bd5b5e6..5eecdc3 100644 --- a/episode14/utils.js +++ b/episode14/utils.js @@ -1,57 +1,57 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + } + } \ No newline at end of file diff --git a/episode14/vector.js b/episode14/vector.js index 609f6d5..4d66796 100644 --- a/episode14/vector.js +++ b/episode14/vector.js @@ -1,83 +1,83 @@ -var vector = { - _x: 1, - _y: 0, - - create: function(x, y) { - var obj = Object.create(this); - obj.setX(x); - obj.setY(y); - return obj; - }, - - setX: function(value) { - this._x = value; - }, - - getX: function() { - return this._x; - }, - - setY: function(value) { - this._y = value; - }, - - getY: function() { - return this._y; - }, - - setAngle: function(angle) { - var length = this.getLength(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getAngle: function() { - return Math.atan2(this._y, this._x); - }, - - setLength: function(length) { - var angle = this.getAngle(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getLength: function() { - return Math.sqrt(this._x * this._x + this._y * this._y); - }, - - add: function(v2) { - return vector.create(this._x + v2.getX(), this._y + v2.getY()); - }, - - subtract: function(v2) { - return vector.create(this._x - v2.getX(), this._y - v2.getY()); - }, - - multiply: function(val) { - return vector.create(this._x * val, this._y * val); - }, - - divide: function(val) { - return vector.create(this._x / val, this._y / val); - }, - - addTo: function(v2) { - this._x += v2.getX(); - this._y += v2.getY(); - }, - - subtractFrom: function(v2) { - this._x -= v2.getX(); - this._y -= v2.getY(); - }, - - multiplyBy: function(val) { - this._x *= val; - this._y *= val; - }, - - divideBy: function(val) { - this._x /= val; - this._y /= val; - } +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } }; \ No newline at end of file diff --git a/episode15/index.html b/episode15/index.html index 26a2d0a..f0073e4 100644 --- a/episode15/index.html +++ b/episode15/index.html @@ -1,23 +1,23 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/episode15/particle.js b/episode15/particle.js index 2269cf9..53e94c1 100644 --- a/episode15/particle.js +++ b/episode15/particle.js @@ -1,49 +1,49 @@ -var particle = { - position: null, - velocity: null, - mass: 1, - radius: 0, - bounce: -1, - friction: 1, - gravity: 0, - - create: function(x, y, speed, direction, grav) { - var obj = Object.create(this); - obj.position = vector.create(x, y); - obj.velocity = vector.create(0, 0); - obj.velocity.setLength(speed); - obj.velocity.setAngle(direction); - obj.gravity = vector.create(0, grav || 0); - return obj; - }, - - accelerate: function(accel) { - this.velocity.addTo(accel); - }, - - update: function() { - this.velocity.multiplyBy(this.friction); - this.velocity.addTo(this.gravity); - this.position.addTo(this.velocity); - }, - - angleTo: function(p2) { - return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); - }, - - distanceTo: function(p2) { - var dx = p2.position.getX() - this.position.getX(), - dy = p2.position.getY() - this.position.getY(); - - return Math.sqrt(dx * dx + dy * dy); - }, - - gravitateTo: function(p2) { - var grav = vector.create(0, 0), - dist = this.distanceTo(p2); - - grav.setLength(p2.mass / (dist * dist)); - grav.setAngle(this.angleTo(p2)); - this.velocity.addTo(grav); - } +var particle = { + position: null, + velocity: null, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + obj.gravity = vector.create(0, grav || 0); + return obj; + }, + + accelerate: function(accel) { + this.velocity.addTo(accel); + }, + + update: function() { + this.velocity.multiplyBy(this.friction); + this.velocity.addTo(this.gravity); + this.position.addTo(this.velocity); + }, + + angleTo: function(p2) { + return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); + }, + + distanceTo: function(p2) { + var dx = p2.position.getX() - this.position.getX(), + dy = p2.position.getY() - this.position.getY(); + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var grav = vector.create(0, 0), + dist = this.distanceTo(p2); + + grav.setLength(p2.mass / (dist * dist)); + grav.setAngle(this.angleTo(p2)); + this.velocity.addTo(grav); + } }; \ No newline at end of file diff --git a/episode15/spring1.js b/episode15/spring1.js index d480dc9..b73b478 100644 --- a/episode15/spring1.js +++ b/episode15/spring1.js @@ -1,50 +1,50 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - springPoint = vector.create(width / 2, height / 2), - weight = particle.create(Math.random() * width, Math.random() * height, - 50, Math.random() * Math.PI * 2), - k = 0.01 + Math.random() * .5; - - weight.radius = 20; - weight.friction = 0.5 + Math.random() * .5; - - document.body.addEventListener("mousemove", function(event) { - springPoint.setX(event.clientX); - springPoint.setY(event.clientY); - }); - - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - var distance = springPoint.subtract(weight.position), - springForce = distance.multiply(k); - - weight.velocity.addTo(springForce); - - weight.update(); - - context.beginPath(); - context.arc(weight.position.getX(), weight.position.getY(), weight.radius, - 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(springPoint.getX(), springPoint.getY(), 4, - 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.moveTo(weight.position.getX(), weight.position.getY()); - context.lineTo(springPoint.getX(), springPoint.getY()); - context.stroke(); - - requestAnimationFrame(update); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + springPoint = vector.create(width / 2, height / 2), + weight = particle.create(Math.random() * width, Math.random() * height, + 50, Math.random() * Math.PI * 2), + k = 0.01 + Math.random() * .5; + + weight.radius = 20; + weight.friction = 0.5 + Math.random() * .5; + + document.body.addEventListener("mousemove", function(event) { + springPoint.setX(event.clientX); + springPoint.setY(event.clientY); + }); + + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + var distance = springPoint.subtract(weight.position), + springForce = distance.multiply(k); + + weight.velocity.addTo(springForce); + + weight.update(); + + context.beginPath(); + context.arc(weight.position.getX(), weight.position.getY(), weight.radius, + 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(springPoint.getX(), springPoint.getY(), 4, + 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.moveTo(weight.position.getX(), weight.position.getY()); + context.lineTo(springPoint.getX(), springPoint.getY()); + context.stroke(); + + requestAnimationFrame(update); + } + }; \ No newline at end of file diff --git a/episode15/utils.js b/episode15/utils.js index bd5b5e6..5eecdc3 100644 --- a/episode15/utils.js +++ b/episode15/utils.js @@ -1,57 +1,57 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + } + } \ No newline at end of file diff --git a/episode15/vector.js b/episode15/vector.js index 609f6d5..4d66796 100644 --- a/episode15/vector.js +++ b/episode15/vector.js @@ -1,83 +1,83 @@ -var vector = { - _x: 1, - _y: 0, - - create: function(x, y) { - var obj = Object.create(this); - obj.setX(x); - obj.setY(y); - return obj; - }, - - setX: function(value) { - this._x = value; - }, - - getX: function() { - return this._x; - }, - - setY: function(value) { - this._y = value; - }, - - getY: function() { - return this._y; - }, - - setAngle: function(angle) { - var length = this.getLength(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getAngle: function() { - return Math.atan2(this._y, this._x); - }, - - setLength: function(length) { - var angle = this.getAngle(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getLength: function() { - return Math.sqrt(this._x * this._x + this._y * this._y); - }, - - add: function(v2) { - return vector.create(this._x + v2.getX(), this._y + v2.getY()); - }, - - subtract: function(v2) { - return vector.create(this._x - v2.getX(), this._y - v2.getY()); - }, - - multiply: function(val) { - return vector.create(this._x * val, this._y * val); - }, - - divide: function(val) { - return vector.create(this._x / val, this._y / val); - }, - - addTo: function(v2) { - this._x += v2.getX(); - this._y += v2.getY(); - }, - - subtractFrom: function(v2) { - this._x -= v2.getX(); - this._y -= v2.getY(); - }, - - multiplyBy: function(val) { - this._x *= val; - this._y *= val; - }, - - divideBy: function(val) { - this._x /= val; - this._y /= val; - } +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } }; \ No newline at end of file diff --git a/episode16/index.html b/episode16/index.html index 9721461..0aa0e0f 100644 --- a/episode16/index.html +++ b/episode16/index.html @@ -1,23 +1,23 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/episode16/particle.js b/episode16/particle.js index 2269cf9..53e94c1 100644 --- a/episode16/particle.js +++ b/episode16/particle.js @@ -1,49 +1,49 @@ -var particle = { - position: null, - velocity: null, - mass: 1, - radius: 0, - bounce: -1, - friction: 1, - gravity: 0, - - create: function(x, y, speed, direction, grav) { - var obj = Object.create(this); - obj.position = vector.create(x, y); - obj.velocity = vector.create(0, 0); - obj.velocity.setLength(speed); - obj.velocity.setAngle(direction); - obj.gravity = vector.create(0, grav || 0); - return obj; - }, - - accelerate: function(accel) { - this.velocity.addTo(accel); - }, - - update: function() { - this.velocity.multiplyBy(this.friction); - this.velocity.addTo(this.gravity); - this.position.addTo(this.velocity); - }, - - angleTo: function(p2) { - return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); - }, - - distanceTo: function(p2) { - var dx = p2.position.getX() - this.position.getX(), - dy = p2.position.getY() - this.position.getY(); - - return Math.sqrt(dx * dx + dy * dy); - }, - - gravitateTo: function(p2) { - var grav = vector.create(0, 0), - dist = this.distanceTo(p2); - - grav.setLength(p2.mass / (dist * dist)); - grav.setAngle(this.angleTo(p2)); - this.velocity.addTo(grav); - } +var particle = { + position: null, + velocity: null, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + obj.gravity = vector.create(0, grav || 0); + return obj; + }, + + accelerate: function(accel) { + this.velocity.addTo(accel); + }, + + update: function() { + this.velocity.multiplyBy(this.friction); + this.velocity.addTo(this.gravity); + this.position.addTo(this.velocity); + }, + + angleTo: function(p2) { + return Math.atan2(p2.position.getY() - this.position.getY(), p2.position.getX() - this.position.getX()); + }, + + distanceTo: function(p2) { + var dx = p2.position.getX() - this.position.getX(), + dy = p2.position.getY() - this.position.getY(); + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var grav = vector.create(0, 0), + dist = this.distanceTo(p2); + + grav.setLength(p2.mass / (dist * dist)); + grav.setAngle(this.angleTo(p2)); + this.velocity.addTo(grav); + } }; \ No newline at end of file diff --git a/episode16/spring1.js b/episode16/spring1.js index 036e6dd..6f58036 100644 --- a/episode16/spring1.js +++ b/episode16/spring1.js @@ -1,52 +1,52 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - springPoint = vector.create(width / 2, height / 2), - weight = particle.create(Math.random() * width, Math.random() * height, - 50, Math.random() * Math.PI * 2, 0.5), - k = 0.1, - springLength = 100; - - weight.radius = 20; - weight.friction = 0.95; - - document.body.addEventListener("mousemove", function(event) { - springPoint.setX(event.clientX); - springPoint.setY(event.clientY); - }); - - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - var distance = springPoint.subtract(weight.position); - distance.setLength(distance.getLength() - springLength); - var springForce = distance.multiply(k); - - weight.velocity.addTo(springForce); - - weight.update(); - - context.beginPath(); - context.arc(weight.position.getX(), weight.position.getY(), weight.radius, - 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(springPoint.getX(), springPoint.getY(), 4, - 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.moveTo(weight.position.getX(), weight.position.getY()); - context.lineTo(springPoint.getX(), springPoint.getY()); - context.stroke(); - - requestAnimationFrame(update); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + springPoint = vector.create(width / 2, height / 2), + weight = particle.create(Math.random() * width, Math.random() * height, + 50, Math.random() * Math.PI * 2, 0.5), + k = 0.1, + springLength = 100; + + weight.radius = 20; + weight.friction = 0.95; + + document.body.addEventListener("mousemove", function(event) { + springPoint.setX(event.clientX); + springPoint.setY(event.clientY); + }); + + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + var distance = springPoint.subtract(weight.position); + distance.setLength(distance.getLength() - springLength); + var springForce = distance.multiply(k); + + weight.velocity.addTo(springForce); + + weight.update(); + + context.beginPath(); + context.arc(weight.position.getX(), weight.position.getY(), weight.radius, + 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(springPoint.getX(), springPoint.getY(), 4, + 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.moveTo(weight.position.getX(), weight.position.getY()); + context.lineTo(springPoint.getX(), springPoint.getY()); + context.stroke(); + + requestAnimationFrame(update); + } + }; \ No newline at end of file diff --git a/episode16/spring2.js b/episode16/spring2.js index addc051..5077219 100644 --- a/episode16/spring2.js +++ b/episode16/spring2.js @@ -1,91 +1,91 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - particleA = particle.create(utils.randomRange(0, width), - utils.randomRange(0, height), - utils.randomRange(0, 50), - utils.randomRange(0, Math.PI * 2), - 0.2), - particleB = particle.create(utils.randomRange(0, width), - utils.randomRange(0, height), - utils.randomRange(0, 50), - utils.randomRange(0, Math.PI * 2), - 0.2), - particleC = particle.create(utils.randomRange(0, width), - utils.randomRange(0, height), - utils.randomRange(0, 50), - utils.randomRange(0, Math.PI * 2), - 0.2), - k = 0.01, - separation = 200; - - particleA.friction = 0.9; - particleA.radius = 20; - - particleB.friction = 0.9; - particleB.radius = 20; - - particleC.friction = 0.9; - particleC.radius = 20; - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - spring(particleA, particleB, separation); - spring(particleB, particleC, separation); - spring(particleC, particleA, separation); - - checkEdges(particleA); - checkEdges(particleB); - checkEdges(particleC); - - particleA.update(); - particleB.update(); - particleC.update(); - - context.beginPath(); - context.arc(particleA.position.getX(), particleA.position.getY(), - particleA.radius, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(particleB.position.getX(), particleB.position.getY(), - particleB.radius, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(particleC.position.getX(), particleC.position.getY(), - particleC.radius, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.moveTo(particleA.position.getX(), particleA.position.getY()); - context.lineTo(particleB.position.getX(), particleB.position.getY()); - context.lineTo(particleC.position.getX(), particleC.position.getY()); - context.lineTo(particleA.position.getX(), particleA.position.getY()); - context.stroke(); - - requestAnimationFrame(update); - } - - function spring(p0, p1, separation) { - var distance = p0.position.subtract(p1.position); - distance.setLength(distance.getLength() - separation); - - var springForce = distance.multiply(k); - - p1.velocity.addTo(springForce); - p0.velocity.subtractFrom(springForce); - } - - function checkEdges(p) { - if(p.position.getY() + p.radius > height) { - p.position.setY(height - p.radius); - p.velocity.setY(p.velocity.getY() * -0.95); - } - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + particleA = particle.create(utils.randomRange(0, width), + utils.randomRange(0, height), + utils.randomRange(0, 50), + utils.randomRange(0, Math.PI * 2), + 0.2), + particleB = particle.create(utils.randomRange(0, width), + utils.randomRange(0, height), + utils.randomRange(0, 50), + utils.randomRange(0, Math.PI * 2), + 0.2), + particleC = particle.create(utils.randomRange(0, width), + utils.randomRange(0, height), + utils.randomRange(0, 50), + utils.randomRange(0, Math.PI * 2), + 0.2), + k = 0.01, + separation = 200; + + particleA.friction = 0.9; + particleA.radius = 20; + + particleB.friction = 0.9; + particleB.radius = 20; + + particleC.friction = 0.9; + particleC.radius = 20; + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + spring(particleA, particleB, separation); + spring(particleB, particleC, separation); + spring(particleC, particleA, separation); + + checkEdges(particleA); + checkEdges(particleB); + checkEdges(particleC); + + particleA.update(); + particleB.update(); + particleC.update(); + + context.beginPath(); + context.arc(particleA.position.getX(), particleA.position.getY(), + particleA.radius, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(particleB.position.getX(), particleB.position.getY(), + particleB.radius, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(particleC.position.getX(), particleC.position.getY(), + particleC.radius, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.moveTo(particleA.position.getX(), particleA.position.getY()); + context.lineTo(particleB.position.getX(), particleB.position.getY()); + context.lineTo(particleC.position.getX(), particleC.position.getY()); + context.lineTo(particleA.position.getX(), particleA.position.getY()); + context.stroke(); + + requestAnimationFrame(update); + } + + function spring(p0, p1, separation) { + var distance = p0.position.subtract(p1.position); + distance.setLength(distance.getLength() - separation); + + var springForce = distance.multiply(k); + + p1.velocity.addTo(springForce); + p0.velocity.subtractFrom(springForce); + } + + function checkEdges(p) { + if(p.position.getY() + p.radius > height) { + p.position.setY(height - p.radius); + p.velocity.setY(p.velocity.getY() * -0.95); + } + } }; \ No newline at end of file diff --git a/episode16/utils.js b/episode16/utils.js index 37ae5ef..9728633 100644 --- a/episode16/utils.js +++ b/episode16/utils.js @@ -1,73 +1,73 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - }, - - degreesToRads: function(degrees) { - return degrees / 180 * Math.PI; - }, - - radsToDegrees: function(radians) { - return radians * 180 / Math.PI; - }, - - randomRange: function(min, max) { - return min + Math.random() * (max - min); - }, - - randomInt: function(min, max) { - return Math.floor(min + Math.random() * (max - min + 1)); - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + } + } \ No newline at end of file diff --git a/episode16/vector.js b/episode16/vector.js index 609f6d5..4d66796 100644 --- a/episode16/vector.js +++ b/episode16/vector.js @@ -1,83 +1,83 @@ -var vector = { - _x: 1, - _y: 0, - - create: function(x, y) { - var obj = Object.create(this); - obj.setX(x); - obj.setY(y); - return obj; - }, - - setX: function(value) { - this._x = value; - }, - - getX: function() { - return this._x; - }, - - setY: function(value) { - this._y = value; - }, - - getY: function() { - return this._y; - }, - - setAngle: function(angle) { - var length = this.getLength(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getAngle: function() { - return Math.atan2(this._y, this._x); - }, - - setLength: function(length) { - var angle = this.getAngle(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getLength: function() { - return Math.sqrt(this._x * this._x + this._y * this._y); - }, - - add: function(v2) { - return vector.create(this._x + v2.getX(), this._y + v2.getY()); - }, - - subtract: function(v2) { - return vector.create(this._x - v2.getX(), this._y - v2.getY()); - }, - - multiply: function(val) { - return vector.create(this._x * val, this._y * val); - }, - - divide: function(val) { - return vector.create(this._x / val, this._y / val); - }, - - addTo: function(v2) { - this._x += v2.getX(); - this._y += v2.getY(); - }, - - subtractFrom: function(v2) { - this._x -= v2.getX(); - this._y -= v2.getY(); - }, - - multiplyBy: function(val) { - this._x *= val; - this._y *= val; - }, - - divideBy: function(val) { - this._x /= val; - this._y /= val; - } +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } }; \ No newline at end of file diff --git a/episode17/index.html b/episode17/index.html index 26a2d0a..f0073e4 100644 --- a/episode17/index.html +++ b/episode17/index.html @@ -1,23 +1,23 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/episode17/orbit.js b/episode17/orbit.js index 0121e8a..eec5651 100644 --- a/episode17/orbit.js +++ b/episode17/orbit.js @@ -1,34 +1,34 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - sun = particle.create(width / 2, height / 2, 0, 0); - planet = particle.create(width / 2 + 200, height / 2, 10, -Math.PI / 2); - - sun.mass = 20000; - - update(); - - - function update() { - context.clearRect(0, 0, width, height); - - // animation goes here - - planet.gravitateTo(sun); - planet.update(); - - context.beginPath(); - context.fillStyle = "#ffff00"; - context.arc(sun.x, sun.y, 20, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.fillStyle = "#0000ff"; - context.arc(planet.x, planet.y, 4, 0, Math.PI * 2, false); - context.fill(); - - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + sun = particle.create(width / 2, height / 2, 0, 0); + planet = particle.create(width / 2 + 200, height / 2, 10, -Math.PI / 2); + + sun.mass = 20000; + + update(); + + + function update() { + context.clearRect(0, 0, width, height); + + // animation goes here + + planet.gravitateTo(sun); + planet.update(); + + context.beginPath(); + context.fillStyle = "#ffff00"; + context.arc(sun.x, sun.y, 20, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.fillStyle = "#0000ff"; + context.arc(planet.x, planet.y, 4, 0, Math.PI * 2, false); + context.fill(); + + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/episode17/particle.js b/episode17/particle.js index 76ad889..5265c6a 100644 --- a/episode17/particle.js +++ b/episode17/particle.js @@ -1,58 +1,58 @@ -var particle = { - x: 0, - y: 0, - vx: 0, - vy: 0, - mass: 1, - radius: 0, - bounce: -1, - friction: 1, - gravity: 0, - - create: function(x, y, speed, direction, grav) { - var obj = Object.create(this); - obj.x = x; - obj.y = y; - obj.vx = Math.cos(direction) * speed; - obj.vy = Math.sin(direction) * speed; - obj.gravity = grav || 0; - return obj; - }, - - accelerate: function(ax, ay) { - this.vx += ax; - this.vy += ay; - }, - - update: function() { - this.vx *= this.friction; - this.vy *= this.friction; - this.vy += this.gravity; - this.x += this.vx; - this.y += this.vy; - }, - - angleTo: function(p2) { - return Math.atan2(p2.y - this.y, p2.x - this.x); - }, - - distanceTo: function(p2) { - var dx = p2.x - this.x, - dy = p2.y - this.y; - - return Math.sqrt(dx * dx + dy * dy); - }, - - gravitateTo: function(p2) { - var dx = p2.x - this.x, - dy = p2.y - this.y, - distSQ = dx * dx + dy * dy, - dist = Math.sqrt(distSQ), - force = p2.mass / distSQ, - ax = dx / dist * force, - ay = dy / dist * force; - - this.vx += ax; - this.vy += ay; - } +var particle = { + x: 0, + y: 0, + vx: 0, + vy: 0, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.x = x; + obj.y = y; + obj.vx = Math.cos(direction) * speed; + obj.vy = Math.sin(direction) * speed; + obj.gravity = grav || 0; + return obj; + }, + + accelerate: function(ax, ay) { + this.vx += ax; + this.vy += ay; + }, + + update: function() { + this.vx *= this.friction; + this.vy *= this.friction; + this.vy += this.gravity; + this.x += this.vx; + this.y += this.vy; + }, + + angleTo: function(p2) { + return Math.atan2(p2.y - this.y, p2.x - this.x); + }, + + distanceTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y; + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y, + distSQ = dx * dx + dy * dy, + dist = Math.sqrt(distSQ), + force = p2.mass / distSQ, + ax = dx / dist * force, + ay = dy / dist * force; + + this.vx += ax; + this.vy += ay; + } }; \ No newline at end of file diff --git a/episode17/spring1.js b/episode17/spring1.js index 896a012..82d1f32 100644 --- a/episode17/spring1.js +++ b/episode17/spring1.js @@ -1,59 +1,59 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - springPoint = { - x: width / 2, - y: height / 2 - }, - weight = particle.create(Math.random() * width, Math.random() * height, - 50, Math.random() * Math.PI * 2, 0.5), - k = 0.1, - springLength = 100; - - weight.radius = 20; - weight.friction = 0.95; - - document.body.addEventListener("mousemove", function(event) { - springPoint.x = event.clientX ; - springPoint.y = event.clientY; - }); - - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - var dx = springPoint.x - weight.x, - dy = springPoint.y - weight.y, - distance = Math.sqrt(dx * dx + dy * dy), - springForce = (distance - springLength) * k, - ax = dx / distance * springForce, - ay = dy / distance * springForce; - - weight.vx += ax; - weight.vy += ay; - - weight.update(); - - context.beginPath(); - context.arc(weight.x, weight.y, weight.radius, - 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(springPoint.x, springPoint.y, 4, - 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.moveTo(weight.x, weight.y); - context.lineTo(springPoint.x, springPoint.y); - context.stroke(); - - requestAnimationFrame(update); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + springPoint = { + x: width / 2, + y: height / 2 + }, + weight = particle.create(Math.random() * width, Math.random() * height, + 50, Math.random() * Math.PI * 2, 0.5), + k = 0.1, + springLength = 100; + + weight.radius = 20; + weight.friction = 0.95; + + document.body.addEventListener("mousemove", function(event) { + springPoint.x = event.clientX ; + springPoint.y = event.clientY; + }); + + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + var dx = springPoint.x - weight.x, + dy = springPoint.y - weight.y, + distance = Math.sqrt(dx * dx + dy * dy), + springForce = (distance - springLength) * k, + ax = dx / distance * springForce, + ay = dy / distance * springForce; + + weight.vx += ax; + weight.vy += ay; + + weight.update(); + + context.beginPath(); + context.arc(weight.x, weight.y, weight.radius, + 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(springPoint.x, springPoint.y, 4, + 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.moveTo(weight.x, weight.y); + context.lineTo(springPoint.x, springPoint.y); + context.stroke(); + + requestAnimationFrame(update); + } + }; \ No newline at end of file diff --git a/episode17/utils.js b/episode17/utils.js index 37ae5ef..9728633 100644 --- a/episode17/utils.js +++ b/episode17/utils.js @@ -1,73 +1,73 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - }, - - degreesToRads: function(degrees) { - return degrees / 180 * Math.PI; - }, - - radsToDegrees: function(radians) { - return radians * 180 / Math.PI; - }, - - randomRange: function(min, max) { - return min + Math.random() * (max - min); - }, - - randomInt: function(min, max) { - return Math.floor(min + Math.random() * (max - min + 1)); - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + } + } \ No newline at end of file diff --git a/episode17/vector.js b/episode17/vector.js index 609f6d5..4d66796 100644 --- a/episode17/vector.js +++ b/episode17/vector.js @@ -1,83 +1,83 @@ -var vector = { - _x: 1, - _y: 0, - - create: function(x, y) { - var obj = Object.create(this); - obj.setX(x); - obj.setY(y); - return obj; - }, - - setX: function(value) { - this._x = value; - }, - - getX: function() { - return this._x; - }, - - setY: function(value) { - this._y = value; - }, - - getY: function() { - return this._y; - }, - - setAngle: function(angle) { - var length = this.getLength(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getAngle: function() { - return Math.atan2(this._y, this._x); - }, - - setLength: function(length) { - var angle = this.getAngle(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getLength: function() { - return Math.sqrt(this._x * this._x + this._y * this._y); - }, - - add: function(v2) { - return vector.create(this._x + v2.getX(), this._y + v2.getY()); - }, - - subtract: function(v2) { - return vector.create(this._x - v2.getX(), this._y - v2.getY()); - }, - - multiply: function(val) { - return vector.create(this._x * val, this._y * val); - }, - - divide: function(val) { - return vector.create(this._x / val, this._y / val); - }, - - addTo: function(v2) { - this._x += v2.getX(); - this._y += v2.getY(); - }, - - subtractFrom: function(v2) { - this._x -= v2.getX(); - this._y -= v2.getY(); - }, - - multiplyBy: function(val) { - this._x *= val; - this._y *= val; - }, - - divideBy: function(val) { - this._x /= val; - this._y /= val; - } +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } }; \ No newline at end of file diff --git a/episode18/index.html b/episode18/index.html index cb3cccd..1f0560b 100644 --- a/episode18/index.html +++ b/episode18/index.html @@ -1,23 +1,23 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/episode18/main.js b/episode18/main.js index 928ac35..46c59ac 100644 --- a/episode18/main.js +++ b/episode18/main.js @@ -1,132 +1,132 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - gun = { - x: 100, - y: height, - angle: -Math.PI / 4 - }, - cannonball = particle.create(gun.x, gun.y, 15, gun.angle, 0.2), - isShooting = false, - forceAngle = 0, - forceSpeed = 0.1, - rawForce = 0, - target = {}; - - cannonball.radius = 7; - - setTarget(); - update (); - - function setTarget() { - target.x = utils.randomRange(200, width); - target.y = height; - target.radius = utils.randomRange(10, 40); - } - - document.body.addEventListener("mousedown", onMouseDown); - - document.body.addEventListener("keydown", function(event) { - switch(event.keyCode) { - case 32: // space - if(!isShooting) { - shoot(); - } - break; - - default: - break; - } - }); - - function shoot() { - var force = utils.map(rawForce, -1, 1, 2, 20); - cannonball.x = gun.x + Math.cos(gun.angle) * 40; - cannonball.y = gun.y + Math.sin(gun.angle) * 40; - cannonball.setSpeed(force); - cannonball.setHeading(gun.angle); - - isShooting = true; - } - - function update() { - if(!isShooting) { - forceAngle += forceSpeed; - } - rawForce = Math.sin(forceAngle); - if(isShooting) { - cannonball.update(); - checkTarget(); - } - draw(); - - if(cannonball.y > height) { - isShooting = false; - } - requestAnimationFrame(update); - } - - function checkTarget() { - if(utils.circleCollision(target, cannonball)) { - // create amazing collision reaction!!! - setTarget(); - } - } - - function onMouseDown(event) { - document.body.addEventListener("mousemove", onMouseMove); - document.body.addEventListener("mouseup", onMouseUp); - aimGun(event.clientX, event.clientY); - } - - function onMouseMove(event) { - aimGun(event.clientX, event.clientY); - } - - function onMouseUp(event) { - document.body.removeEventListener("mousemove", onMouseMove); - document.body.removeEventListener("mouseup", onMouseUp); - aimGun(event.clientX, event.clientY); - } - - function aimGun(mouseX, mouseY) { - gun.angle = utils.clamp(Math.atan2(mouseY - gun.y, mouseX - gun.x), -Math.PI / 2, -0.3); - } - - function draw() { - context.clearRect(0, 0, width, height); - - context.fillStyle = "#ccc"; - context.fillRect(10, height - 10, 20, -100); - - context.fillStyle = "#666"; - context.fillRect(10, height - 10, 20, utils.map(rawForce, -1, 1, 0, -100)); - - context.fillStyle = "#000"; - - context.beginPath(); - context.arc(gun.x, gun.y, 24, 0, Math.PI * 2, false); - context.fill(); - - context.save(); - context.translate(gun.x, gun.y); - context.rotate(gun.angle); - context.fillRect(0, -8, 40, 16); - context.restore(); - - context.beginPath(); - context.arc(cannonball.x, - cannonball.y, - cannonball.radius, - 0, Math.PI * 2, false); - context.fill(); - - context.fillStyle = "red"; - context.beginPath(); - context.arc(target.x, target.y, target.radius, 0, Math.PI * 2, false); - context.fill(); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + gun = { + x: 100, + y: height, + angle: -Math.PI / 4 + }, + cannonball = particle.create(gun.x, gun.y, 15, gun.angle, 0.2), + isShooting = false, + forceAngle = 0, + forceSpeed = 0.1, + rawForce = 0, + target = {}; + + cannonball.radius = 7; + + setTarget(); + update (); + + function setTarget() { + target.x = utils.randomRange(200, width); + target.y = height; + target.radius = utils.randomRange(10, 40); + } + + document.body.addEventListener("mousedown", onMouseDown); + + document.body.addEventListener("keydown", function(event) { + switch(event.keyCode) { + case 32: // space + if(!isShooting) { + shoot(); + } + break; + + default: + break; + } + }); + + function shoot() { + var force = utils.map(rawForce, -1, 1, 2, 20); + cannonball.x = gun.x + Math.cos(gun.angle) * 40; + cannonball.y = gun.y + Math.sin(gun.angle) * 40; + cannonball.setSpeed(force); + cannonball.setHeading(gun.angle); + + isShooting = true; + } + + function update() { + if(!isShooting) { + forceAngle += forceSpeed; + } + rawForce = Math.sin(forceAngle); + if(isShooting) { + cannonball.update(); + checkTarget(); + } + draw(); + + if(cannonball.y > height) { + isShooting = false; + } + requestAnimationFrame(update); + } + + function checkTarget() { + if(utils.circleCollision(target, cannonball)) { + // create amazing collision reaction!!! + setTarget(); + } + } + + function onMouseDown(event) { + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function onMouseMove(event) { + aimGun(event.clientX, event.clientY); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + aimGun(event.clientX, event.clientY); + } + + function aimGun(mouseX, mouseY) { + gun.angle = utils.clamp(Math.atan2(mouseY - gun.y, mouseX - gun.x), -Math.PI / 2, -0.3); + } + + function draw() { + context.clearRect(0, 0, width, height); + + context.fillStyle = "#ccc"; + context.fillRect(10, height - 10, 20, -100); + + context.fillStyle = "#666"; + context.fillRect(10, height - 10, 20, utils.map(rawForce, -1, 1, 0, -100)); + + context.fillStyle = "#000"; + + context.beginPath(); + context.arc(gun.x, gun.y, 24, 0, Math.PI * 2, false); + context.fill(); + + context.save(); + context.translate(gun.x, gun.y); + context.rotate(gun.angle); + context.fillRect(0, -8, 40, 16); + context.restore(); + + context.beginPath(); + context.arc(cannonball.x, + cannonball.y, + cannonball.radius, + 0, Math.PI * 2, false); + context.fill(); + + context.fillStyle = "red"; + context.beginPath(); + context.arc(target.x, target.y, target.radius, 0, Math.PI * 2, false); + context.fill(); + } + }; \ No newline at end of file diff --git a/episode18/multigravity.js b/episode18/multigravity.js index 55c22df..cc960d1 100644 --- a/episode18/multigravity.js +++ b/episode18/multigravity.js @@ -1,63 +1,63 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - sun1 = particle.create(300, 200, 0, 0), - sun2 = particle.create(800, 600, 0, 0), - emitter = { - x: 100, - y: 0 - }, - particles = [], - numParticles = 100; - - - sun1.mass = 10000; - sun1.radius = 10; - sun2.mass = 20000; - sun2.radius = 20; - - for(var i = 0; i < numParticles; i += 1) { - var p = particle.create(emitter.x, emitter.y, utils.randomRange(7, 8), Math.PI / 2 + utils.randomRange(-0.1, 0.1)); - p.addGravitation(sun1); - p.addGravitation(sun2); - p.radius = 3; - particles.push(p); - } - - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - draw(sun1, "yellow"); - draw(sun2, "yellow"); - - for(var i = 0; i < numParticles; i += 1) { - var p = particles[i]; - p.update(); - draw(p, "black"); - if(p.x > width || - p.x < 0 || - p.y > height || - p.y < 0) { - p.x = emitter.x; - p.y = emitter.y; - p.setSpeed(utils.randomRange(7, 8)); - p.setHeading(Math.PI / 2 + utils.randomRange(-.1, .1)); - } - } - - requestAnimationFrame(update); - } - - function draw(p, color) { - context.fillStyle = color; - context.beginPath(); - context.arc(p.x, p.y, p.radius, 0, Math.PI * 2, false); - context.fill(); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + sun1 = particle.create(300, 200, 0, 0), + sun2 = particle.create(800, 600, 0, 0), + emitter = { + x: 100, + y: 0 + }, + particles = [], + numParticles = 100; + + + sun1.mass = 10000; + sun1.radius = 10; + sun2.mass = 20000; + sun2.radius = 20; + + for(var i = 0; i < numParticles; i += 1) { + var p = particle.create(emitter.x, emitter.y, utils.randomRange(7, 8), Math.PI / 2 + utils.randomRange(-0.1, 0.1)); + p.addGravitation(sun1); + p.addGravitation(sun2); + p.radius = 3; + particles.push(p); + } + + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + draw(sun1, "yellow"); + draw(sun2, "yellow"); + + for(var i = 0; i < numParticles; i += 1) { + var p = particles[i]; + p.update(); + draw(p, "black"); + if(p.x > width || + p.x < 0 || + p.y > height || + p.y < 0) { + p.x = emitter.x; + p.y = emitter.y; + p.setSpeed(utils.randomRange(7, 8)); + p.setHeading(Math.PI / 2 + utils.randomRange(-.1, .1)); + } + } + + requestAnimationFrame(update); + } + + function draw(p, color) { + context.fillStyle = color; + context.beginPath(); + context.arc(p.x, p.y, p.radius, 0, Math.PI * 2, false); + context.fill(); + } + }; \ No newline at end of file diff --git a/episode18/particle.js b/episode18/particle.js index b6ef621..948e47a 100644 --- a/episode18/particle.js +++ b/episode18/particle.js @@ -1,138 +1,138 @@ -var particle = { - x: 0, - y: 0, - vx: 0, - vy: 0, - mass: 1, - radius: 0, - bounce: -1, - friction: 1, - gravity: 0, - springs: null, - gravitations: null, - - create: function(x, y, speed, direction, grav) { - var obj = Object.create(this); - obj.x = x; - obj.y = y; - obj.vx = Math.cos(direction) * speed; - obj.vy = Math.sin(direction) * speed; - obj.gravity = grav || 0; - obj.springs = []; - obj.gravitations = []; - return obj; - }, - - addGravitation: function(p) { - this.removeGravitation(p); - this.gravitations.push(p); - }, - - removeGravitation: function(p) { - for(var i = 0; i < this.gravitations.length; i += 1) { - if(p === this.gravitations[i]) { - this.gravitations.splice(i, 1); - return; - } - } - }, - - addSpring: function(point, k, length) { - this.removeSpring(point); - this.springs.push({ - point: point, - k: k, - length: length || 0 - }); - }, - - removeSpring: function(point) { - for(var i = 0; i < this.springs.length; i += 1) { - if(point === this.springs[i].point) { - this.springs.splice(i, 1); - return; - } - } - }, - - getSpeed: function() { - return Math.sqrt(this.vx * this.vx + this.vy * this.vy); - }, - - setSpeed: function(speed) { - var heading = this.getHeading(); - this.vx = Math.cos(heading) * speed; - this.vy = Math.sin(heading) * speed; - }, - - getHeading: function() { - return Math.atan2(this.vy, this.vx); - }, - - setHeading: function(heading) { - var speed = this.getSpeed(); - this.vx = Math.cos(heading) * speed; - this.vy = Math.sin(heading) * speed; - }, - - accelerate: function(ax, ay) { - this.vx += ax; - this.vy += ay; - }, - - update: function() { - this.handleSprings(); - this.handleGravitations(); - this.vx *= this.friction; - this.vy *= this.friction; - this.vy += this.gravity; - this.x += this.vx; - this.y += this.vy; - }, - - handleGravitations: function() { - for(var i = 0; i < this.gravitations.length; i += 1) { - this.gravitateTo(this.gravitations[i]); - } - }, - - handleSprings: function() { - for(var i = 0; i < this.springs.length; i += 1) { - var spring = this.springs[i]; - this.springTo(spring.point, spring.k, spring.length); - } - }, - - angleTo: function(p2) { - return Math.atan2(p2.y - this.y, p2.x - this.x); - }, - - distanceTo: function(p2) { - var dx = p2.x - this.x, - dy = p2.y - this.y; - - return Math.sqrt(dx * dx + dy * dy); - }, - - gravitateTo: function(p2) { - var dx = p2.x - this.x, - dy = p2.y - this.y, - distSQ = dx * dx + dy * dy, - dist = Math.sqrt(distSQ), - force = p2.mass / distSQ, - ax = dx / dist * force, - ay = dy / dist * force; - - this.vx += ax; - this.vy += ay; - }, - - springTo: function(point, k, length) { - var dx = point.x - this.x, - dy = point.y - this.y, - distance = Math.sqrt(dx * dx + dy * dy), - springForce = (distance - length || 0) * k; - this.vx += dx / distance * springForce, - this.vy += dy / distance * springForce; - } +var particle = { + x: 0, + y: 0, + vx: 0, + vy: 0, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + springs: null, + gravitations: null, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.x = x; + obj.y = y; + obj.vx = Math.cos(direction) * speed; + obj.vy = Math.sin(direction) * speed; + obj.gravity = grav || 0; + obj.springs = []; + obj.gravitations = []; + return obj; + }, + + addGravitation: function(p) { + this.removeGravitation(p); + this.gravitations.push(p); + }, + + removeGravitation: function(p) { + for(var i = 0; i < this.gravitations.length; i += 1) { + if(p === this.gravitations[i]) { + this.gravitations.splice(i, 1); + return; + } + } + }, + + addSpring: function(point, k, length) { + this.removeSpring(point); + this.springs.push({ + point: point, + k: k, + length: length || 0 + }); + }, + + removeSpring: function(point) { + for(var i = 0; i < this.springs.length; i += 1) { + if(point === this.springs[i].point) { + this.springs.splice(i, 1); + return; + } + } + }, + + getSpeed: function() { + return Math.sqrt(this.vx * this.vx + this.vy * this.vy); + }, + + setSpeed: function(speed) { + var heading = this.getHeading(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + getHeading: function() { + return Math.atan2(this.vy, this.vx); + }, + + setHeading: function(heading) { + var speed = this.getSpeed(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + accelerate: function(ax, ay) { + this.vx += ax; + this.vy += ay; + }, + + update: function() { + this.handleSprings(); + this.handleGravitations(); + this.vx *= this.friction; + this.vy *= this.friction; + this.vy += this.gravity; + this.x += this.vx; + this.y += this.vy; + }, + + handleGravitations: function() { + for(var i = 0; i < this.gravitations.length; i += 1) { + this.gravitateTo(this.gravitations[i]); + } + }, + + handleSprings: function() { + for(var i = 0; i < this.springs.length; i += 1) { + var spring = this.springs[i]; + this.springTo(spring.point, spring.k, spring.length); + } + }, + + angleTo: function(p2) { + return Math.atan2(p2.y - this.y, p2.x - this.x); + }, + + distanceTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y; + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y, + distSQ = dx * dx + dy * dy, + dist = Math.sqrt(distSQ), + force = p2.mass / distSQ, + ax = dx / dist * force, + ay = dy / dist * force; + + this.vx += ax; + this.vy += ay; + }, + + springTo: function(point, k, length) { + var dx = point.x - this.x, + dy = point.y - this.y, + distance = Math.sqrt(dx * dx + dy * dy), + springForce = (distance - length || 0) * k; + this.vx += dx / distance * springForce, + this.vy += dy / distance * springForce; + } }; \ No newline at end of file diff --git a/episode18/spring1.js b/episode18/spring1.js index 1b81c3c..73bea15 100644 --- a/episode18/spring1.js +++ b/episode18/spring1.js @@ -1,56 +1,56 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - springPoint = { - x: width / 2, - y: height / 2 - }, - springPoint2 = { - x: utils.randomRange(0, width), - y: utils.randomRange(0, height) - }, - weight = particle.create(Math.random() * width, Math.random() * height, - 50, Math.random() * Math.PI * 2, 0.5), - k = 0.1, - springLength = 100; - - weight.radius = 20; - weight.friction = 0.95; - weight.addSpring(springPoint, k, springLength); - weight.addSpring(springPoint2, k, springLength); - - document.body.addEventListener("mousemove", function(event) { - springPoint.x = event.clientX ; - springPoint.y = event.clientY; - }); - - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - weight.update(); - - context.beginPath(); - context.arc(weight.x, weight.y, weight.radius, - 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(springPoint.x, springPoint.y, 4, - 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.moveTo(springPoint2.x, springPoint2.y); - context.lineTo(weight.x, weight.y); - context.lineTo(springPoint.x, springPoint.y); - context.stroke(); - - requestAnimationFrame(update); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + springPoint = { + x: width / 2, + y: height / 2 + }, + springPoint2 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + weight = particle.create(Math.random() * width, Math.random() * height, + 50, Math.random() * Math.PI * 2, 0.5), + k = 0.1, + springLength = 100; + + weight.radius = 20; + weight.friction = 0.95; + weight.addSpring(springPoint, k, springLength); + weight.addSpring(springPoint2, k, springLength); + + document.body.addEventListener("mousemove", function(event) { + springPoint.x = event.clientX ; + springPoint.y = event.clientY; + }); + + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + weight.update(); + + context.beginPath(); + context.arc(weight.x, weight.y, weight.radius, + 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(springPoint.x, springPoint.y, 4, + 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.moveTo(springPoint2.x, springPoint2.y); + context.lineTo(weight.x, weight.y); + context.lineTo(springPoint.x, springPoint.y); + context.stroke(); + + requestAnimationFrame(update); + } + }; \ No newline at end of file diff --git a/episode18/utils.js b/episode18/utils.js index 37ae5ef..9728633 100644 --- a/episode18/utils.js +++ b/episode18/utils.js @@ -1,73 +1,73 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - }, - - degreesToRads: function(degrees) { - return degrees / 180 * Math.PI; - }, - - radsToDegrees: function(radians) { - return radians * 180 / Math.PI; - }, - - randomRange: function(min, max) { - return min + Math.random() * (max - min); - }, - - randomInt: function(min, max) { - return Math.floor(min + Math.random() * (max - min + 1)); - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + } + } \ No newline at end of file diff --git a/episode18/vector.js b/episode18/vector.js index 609f6d5..4d66796 100644 --- a/episode18/vector.js +++ b/episode18/vector.js @@ -1,83 +1,83 @@ -var vector = { - _x: 1, - _y: 0, - - create: function(x, y) { - var obj = Object.create(this); - obj.setX(x); - obj.setY(y); - return obj; - }, - - setX: function(value) { - this._x = value; - }, - - getX: function() { - return this._x; - }, - - setY: function(value) { - this._y = value; - }, - - getY: function() { - return this._y; - }, - - setAngle: function(angle) { - var length = this.getLength(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getAngle: function() { - return Math.atan2(this._y, this._x); - }, - - setLength: function(length) { - var angle = this.getAngle(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getLength: function() { - return Math.sqrt(this._x * this._x + this._y * this._y); - }, - - add: function(v2) { - return vector.create(this._x + v2.getX(), this._y + v2.getY()); - }, - - subtract: function(v2) { - return vector.create(this._x - v2.getX(), this._y - v2.getY()); - }, - - multiply: function(val) { - return vector.create(this._x * val, this._y * val); - }, - - divide: function(val) { - return vector.create(this._x / val, this._y / val); - }, - - addTo: function(v2) { - this._x += v2.getX(); - this._y += v2.getY(); - }, - - subtractFrom: function(v2) { - this._x -= v2.getX(); - this._y -= v2.getY(); - }, - - multiplyBy: function(val) { - this._x *= val; - this._y *= val; - }, - - divideBy: function(val) { - this._x /= val; - this._y /= val; - } +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } }; \ No newline at end of file diff --git a/episode19/demo1.js b/episode19/demo1.js index 51b154e..b6ca34f 100644 --- a/episode19/demo1.js +++ b/episode19/demo1.js @@ -1,74 +1,74 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - p0 = { - x: 100, - y: 500 - }, - p1 = { - x: 600, - y: 200 - }, - pA = {}, - t = 0; - - context.scale(1.5, 1.5); - context.font = "16px Arial"; - draw(); - - document.body.addEventListener("click", function() { - draw(); - }); - - function draw() { - context.clearRect(0, 0, width, height); - - context.beginPath(); - context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); - context.fill(); - - pA.x = utils.lerp(t, p0.x, p1.x); - pA.y = utils.lerp(t, p0.y, p1.y); - - context.beginPath(); - context.arc(pA.x, pA.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.lineTo(pA.x, pA.y); - context.stroke(); - - labelPointLeft(p0, "p0"); - labelPointLeft(p1, "p1 "); - labelPoint(pA, "pA"); - labelT(); - - t += .1; - t = Math.min(t, 1); - - } - - function labelPoint(p, name) { - context.fillText(name, p.x + 10, p.y + 10); - context.fillText("x: " + Math.round(p.x), p.x + 10, p.y + 25); - context.fillText("y: " + Math.round(p.y), p.x + 10, p.y + 40); - } - - function labelPointLeft(p, name) { - context.fillText(name, p.x - 40, p.y - 40); - context.fillText("x: " + Math.round(p.x), p.x - 40, p.y - 25); - context.fillText("y: " + Math.round(p.y), p.x - 40, p.y - 10); - } - - function labelT() { - context.fillText("t = " + utils.roundToPlaces(t, 1), 200, 250); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: 100, + y: 500 + }, + p1 = { + x: 600, + y: 200 + }, + pA = {}, + t = 0; + + context.scale(1.5, 1.5); + context.font = "16px Arial"; + draw(); + + document.body.addEventListener("click", function() { + draw(); + }); + + function draw() { + context.clearRect(0, 0, width, height); + + context.beginPath(); + context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); + context.fill(); + + pA.x = utils.lerp(t, p0.x, p1.x); + pA.y = utils.lerp(t, p0.y, p1.y); + + context.beginPath(); + context.arc(pA.x, pA.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(pA.x, pA.y); + context.stroke(); + + labelPointLeft(p0, "p0"); + labelPointLeft(p1, "p1 "); + labelPoint(pA, "pA"); + labelT(); + + t += .1; + t = Math.min(t, 1); + + } + + function labelPoint(p, name) { + context.fillText(name, p.x + 10, p.y + 10); + context.fillText("x: " + Math.round(p.x), p.x + 10, p.y + 25); + context.fillText("y: " + Math.round(p.y), p.x + 10, p.y + 40); + } + + function labelPointLeft(p, name) { + context.fillText(name, p.x - 40, p.y - 40); + context.fillText("x: " + Math.round(p.x), p.x - 40, p.y - 25); + context.fillText("y: " + Math.round(p.y), p.x - 40, p.y - 10); + } + + function labelT() { + context.fillText("t = " + utils.roundToPlaces(t, 1), 200, 250); + } + }; \ No newline at end of file diff --git a/episode19/demo2.js b/episode19/demo2.js index 52dff70..6b43846 100644 --- a/episode19/demo2.js +++ b/episode19/demo2.js @@ -1,96 +1,96 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - p0 = { - x: 100, - y: 500 - }, - p1 = { - x: 600, - y: 200 - }, - p2 = { - x: 1000, - y: 400 - }, - pA = {}, - pB = {}, - t = 0; - - context.scale(1.5, 1.5); - context.font = "16px Arial"; - draw(); - - document.body.addEventListener("click", function() { - draw(); - }); - - function draw() { - context.clearRect(0, 0, width, height); - - context.beginPath(); - context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(p2.x, p2.y, 4, 0, Math.PI * 2, false); - context.fill(); - - pA.x = utils.lerp(t, p0.x, p1.x); - pA.y = utils.lerp(t, p0.y, p1.y); - - pB.x = utils.lerp(t, p1.x, p2.x); - pB.y = utils.lerp(t, p1.y, p2.y); - - context.beginPath(); - context.arc(pA.x, pA.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(pB.x, pB.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.lineTo(pA.x, pA.y); - context.moveTo(p1.x, p1.y); - context.lineTo(pB.x, pB.y); - context.stroke(); - - labelPointLeft(p0, "p0"); - labelPointLeft(p1, "p1"); - labelPointLeft(p2, "p2"); - labelPoint(pA, "pA"); - labelPoint(pB, "pB"); - labelT(); - - t += .1; - t = Math.min(t, 1); - - } - - function labelPoint(p, name) { - context.fillStyle = "black"; - context.fillText(name, p.x + 10, p.y + 10); - context.fillText("x: " + Math.round(p.x), p.x + 10, p.y + 25); - context.fillText("y: " + Math.round(p.y), p.x + 10, p.y + 40); - } - - function labelPointLeft(p, name) { - context.fillStyle = "gray"; - context.fillText(name, p.x - 40, p.y - 40); - context.fillText("x: " + Math.round(p.x), p.x - 40, p.y - 25); - context.fillText("y: " + Math.round(p.y), p.x - 40, p.y - 10); - } - - function labelT() { - context.fillText("t = " + utils.roundToPlaces(t, 1), 200, 300); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: 100, + y: 500 + }, + p1 = { + x: 600, + y: 200 + }, + p2 = { + x: 1000, + y: 400 + }, + pA = {}, + pB = {}, + t = 0; + + context.scale(1.5, 1.5); + context.font = "16px Arial"; + draw(); + + document.body.addEventListener("click", function() { + draw(); + }); + + function draw() { + context.clearRect(0, 0, width, height); + + context.beginPath(); + context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p2.x, p2.y, 4, 0, Math.PI * 2, false); + context.fill(); + + pA.x = utils.lerp(t, p0.x, p1.x); + pA.y = utils.lerp(t, p0.y, p1.y); + + pB.x = utils.lerp(t, p1.x, p2.x); + pB.y = utils.lerp(t, p1.y, p2.y); + + context.beginPath(); + context.arc(pA.x, pA.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(pB.x, pB.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(pA.x, pA.y); + context.moveTo(p1.x, p1.y); + context.lineTo(pB.x, pB.y); + context.stroke(); + + labelPointLeft(p0, "p0"); + labelPointLeft(p1, "p1"); + labelPointLeft(p2, "p2"); + labelPoint(pA, "pA"); + labelPoint(pB, "pB"); + labelT(); + + t += .1; + t = Math.min(t, 1); + + } + + function labelPoint(p, name) { + context.fillStyle = "black"; + context.fillText(name, p.x + 10, p.y + 10); + context.fillText("x: " + Math.round(p.x), p.x + 10, p.y + 25); + context.fillText("y: " + Math.round(p.y), p.x + 10, p.y + 40); + } + + function labelPointLeft(p, name) { + context.fillStyle = "gray"; + context.fillText(name, p.x - 40, p.y - 40); + context.fillText("x: " + Math.round(p.x), p.x - 40, p.y - 25); + context.fillText("y: " + Math.round(p.y), p.x - 40, p.y - 10); + } + + function labelT() { + context.fillText("t = " + utils.roundToPlaces(t, 1), 200, 300); + } + }; \ No newline at end of file diff --git a/episode19/demo3.js b/episode19/demo3.js index b709cac..2f5cf38 100644 --- a/episode19/demo3.js +++ b/episode19/demo3.js @@ -1,106 +1,106 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - p0 = { - x: 100, - y: 500 - }, - p1 = { - x: 600, - y: 200 - }, - p2 = { - x: 1000, - y: 400 - }, - pA = {}, - pB = {}, - t = 0, - maxT = 0; - - context.scale(1.5, 1.5); - context.font = "16px Arial"; - draw(); - - document.body.addEventListener("click", function() { - draw(); - }); - - function draw() { - context.clearRect(0, 0, width, height); - - context.strokeStyle = "#ccc"; - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.lineTo(p1.x, p1.y); - context.lineTo(p2.x, p2.y); - context.stroke(); - context.beginPath(); - context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.strokeStyle = "black"; - - context.beginPath(); - context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(p2.x, p2.y, 4, 0, Math.PI * 2, false); - context.fill(); - - for(var t = 0; t <= maxT; t += .1) { - pA.x = utils.lerp(t, p0.x, p1.x); - pA.y = utils.lerp(t, p0.y, p1.y); - - pB.x = utils.lerp(t, p1.x, p2.x); - pB.y = utils.lerp(t, p1.y, p2.y); - - context.beginPath(); - context.moveTo(pA.x, pA.y); - context.lineTo(pB.x, pB.y); - context.stroke(); - } - - context.beginPath(); - context.arc(pA.x, pA.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(pB.x, pB.y, 4, 0, Math.PI * 2, false); - context.fill(); - - - // labelPointLeft(p0, "p0"); - // labelPointLeft(p1, "p1"); - // labelPointLeft(p2, "p2"); - // labelPoint(pA, "pA"); - // labelPoint(pB, "pB"); - labelT(); - - maxT += .1; - maxT = Math.min(t, 1); - - } - - function labelPoint(p, name) { - context.fillStyle = "black"; - context.fillText(name, p.x + 10, p.y + 10); - context.fillText("x: " + Math.round(p.x), p.x + 10, p.y + 25); - context.fillText("y: " + Math.round(p.y), p.x + 10, p.y + 40); - } - - function labelPointLeft(p, name) { - context.fillStyle = "gray"; - context.fillText(name, p.x - 40, p.y - 40); - context.fillText("x: " + Math.round(p.x), p.x - 40, p.y - 25); - context.fillText("y: " + Math.round(p.y), p.x - 40, p.y - 10); - } - - function labelT() { - context.fillText("t = " + utils.roundToPlaces(maxT, 1), 200, 250); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: 100, + y: 500 + }, + p1 = { + x: 600, + y: 200 + }, + p2 = { + x: 1000, + y: 400 + }, + pA = {}, + pB = {}, + t = 0, + maxT = 0; + + context.scale(1.5, 1.5); + context.font = "16px Arial"; + draw(); + + document.body.addEventListener("click", function() { + draw(); + }); + + function draw() { + context.clearRect(0, 0, width, height); + + context.strokeStyle = "#ccc"; + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.lineTo(p2.x, p2.y); + context.stroke(); + context.beginPath(); + context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.strokeStyle = "black"; + + context.beginPath(); + context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p2.x, p2.y, 4, 0, Math.PI * 2, false); + context.fill(); + + for(var t = 0; t <= maxT; t += .1) { + pA.x = utils.lerp(t, p0.x, p1.x); + pA.y = utils.lerp(t, p0.y, p1.y); + + pB.x = utils.lerp(t, p1.x, p2.x); + pB.y = utils.lerp(t, p1.y, p2.y); + + context.beginPath(); + context.moveTo(pA.x, pA.y); + context.lineTo(pB.x, pB.y); + context.stroke(); + } + + context.beginPath(); + context.arc(pA.x, pA.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(pB.x, pB.y, 4, 0, Math.PI * 2, false); + context.fill(); + + + // labelPointLeft(p0, "p0"); + // labelPointLeft(p1, "p1"); + // labelPointLeft(p2, "p2"); + // labelPoint(pA, "pA"); + // labelPoint(pB, "pB"); + labelT(); + + maxT += .1; + maxT = Math.min(t, 1); + + } + + function labelPoint(p, name) { + context.fillStyle = "black"; + context.fillText(name, p.x + 10, p.y + 10); + context.fillText("x: " + Math.round(p.x), p.x + 10, p.y + 25); + context.fillText("y: " + Math.round(p.y), p.x + 10, p.y + 40); + } + + function labelPointLeft(p, name) { + context.fillStyle = "gray"; + context.fillText(name, p.x - 40, p.y - 40); + context.fillText("x: " + Math.round(p.x), p.x - 40, p.y - 25); + context.fillText("y: " + Math.round(p.y), p.x - 40, p.y - 10); + } + + function labelT() { + context.fillText("t = " + utils.roundToPlaces(maxT, 1), 200, 250); + } + }; \ No newline at end of file diff --git a/episode19/demo4.js b/episode19/demo4.js index b966be7..c0fc7e9 100644 --- a/episode19/demo4.js +++ b/episode19/demo4.js @@ -1,125 +1,125 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - p0 = { - x: 100, - y: 500 - }, - p1 = { - x: 100, - y: 300 - }, - p2 = { - x: 1000, - y: 400 - }, - pA = {}, - pB = {}, - pFinal = {}, - t = 0, - maxT = 0; - - context.scale(1.5, 1.5); - context.font = "16px Arial"; - draw(); - - document.body.addEventListener("click", function() { - draw(); - }); - - function draw() { - context.clearRect(0, 0, width, height); - - context.strokeStyle = "#ccc"; - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.lineTo(p1.x, p1.y); - context.lineTo(p2.x, p2.y); - context.stroke(); - - context.beginPath(); - context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(p2.x, p2.y, 4, 0, Math.PI * 2, false); - context.fill(); - - - context.strokeStyle = "red"; - context.beginPath(); - context.moveTo(p0.x, p0.y); - - for(t = 0; t <= maxT; t += .1) { - pA.x = utils.lerp(t, p0.x, p1.x); - pA.y = utils.lerp(t, p0.y, p1.y); - - pB.x = utils.lerp(t, p1.x, p2.x); - pB.y = utils.lerp(t, p1.y, p2.y); - - pFinal.x = utils.lerp(t, pA.x, pB.x); - pFinal.y = utils.lerp(t, pA.y, pB.y); - - context.lineTo(pFinal.x, pFinal.y); - } - context.stroke(); - - context.beginPath(); - context.strokeStyle = "gray"; - context.moveTo(pA.x, pA.y); - context.lineTo(pB.x, pB.y); - context.stroke(); - - context.beginPath(); - context.arc(pA.x, pA.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(pB.x, pB.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.fillStyle = "red"; - context.beginPath(); - context.arc(pFinal.x, pFinal.y, 4, 0, Math.PI * 2, false); - context.fill(); - context.fillStyle = "black"; - - - - // labelPointLeft(p0, "p0"); - // labelPointLeft(p1, "p1"); - // labelPointLeft(p2, "p2"); - // labelPoint(pA, "pA"); - // labelPoint(pB, "pB"); - labelT(); - - maxT += .1; - maxT = Math.min(t, 1); - - } - - function labelPoint(p, name) { - context.fillStyle = "black"; - context.fillText(name, p.x + 10, p.y + 10); - context.fillText("x: " + Math.round(p.x), p.x + 10, p.y + 25); - context.fillText("y: " + Math.round(p.y), p.x + 10, p.y + 40); - } - - function labelPointLeft(p, name) { - context.fillStyle = "gray"; - context.fillText(name, p.x - 40, p.y - 40); - context.fillText("x: " + Math.round(p.x), p.x - 40, p.y - 25); - context.fillText("y: " + Math.round(p.y), p.x - 40, p.y - 10); - } - - function labelT() { - context.fillText("t = " + utils.roundToPlaces(maxT, 1), 200, 250); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: 100, + y: 500 + }, + p1 = { + x: 100, + y: 300 + }, + p2 = { + x: 1000, + y: 400 + }, + pA = {}, + pB = {}, + pFinal = {}, + t = 0, + maxT = 0; + + context.scale(1.5, 1.5); + context.font = "16px Arial"; + draw(); + + document.body.addEventListener("click", function() { + draw(); + }); + + function draw() { + context.clearRect(0, 0, width, height); + + context.strokeStyle = "#ccc"; + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.lineTo(p2.x, p2.y); + context.stroke(); + + context.beginPath(); + context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p2.x, p2.y, 4, 0, Math.PI * 2, false); + context.fill(); + + + context.strokeStyle = "red"; + context.beginPath(); + context.moveTo(p0.x, p0.y); + + for(t = 0; t <= maxT; t += .1) { + pA.x = utils.lerp(t, p0.x, p1.x); + pA.y = utils.lerp(t, p0.y, p1.y); + + pB.x = utils.lerp(t, p1.x, p2.x); + pB.y = utils.lerp(t, p1.y, p2.y); + + pFinal.x = utils.lerp(t, pA.x, pB.x); + pFinal.y = utils.lerp(t, pA.y, pB.y); + + context.lineTo(pFinal.x, pFinal.y); + } + context.stroke(); + + context.beginPath(); + context.strokeStyle = "gray"; + context.moveTo(pA.x, pA.y); + context.lineTo(pB.x, pB.y); + context.stroke(); + + context.beginPath(); + context.arc(pA.x, pA.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(pB.x, pB.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.fillStyle = "red"; + context.beginPath(); + context.arc(pFinal.x, pFinal.y, 4, 0, Math.PI * 2, false); + context.fill(); + context.fillStyle = "black"; + + + + // labelPointLeft(p0, "p0"); + // labelPointLeft(p1, "p1"); + // labelPointLeft(p2, "p2"); + // labelPoint(pA, "pA"); + // labelPoint(pB, "pB"); + labelT(); + + maxT += .1; + maxT = Math.min(t, 1); + + } + + function labelPoint(p, name) { + context.fillStyle = "black"; + context.fillText(name, p.x + 10, p.y + 10); + context.fillText("x: " + Math.round(p.x), p.x + 10, p.y + 25); + context.fillText("y: " + Math.round(p.y), p.x + 10, p.y + 40); + } + + function labelPointLeft(p, name) { + context.fillStyle = "gray"; + context.fillText(name, p.x - 40, p.y - 40); + context.fillText("x: " + Math.round(p.x), p.x - 40, p.y - 25); + context.fillText("y: " + Math.round(p.y), p.x - 40, p.y - 10); + } + + function labelT() { + context.fillText("t = " + utils.roundToPlaces(maxT, 1), 200, 250); + } + }; \ No newline at end of file diff --git a/episode19/demo5.js b/episode19/demo5.js index c9000cf..ac0993b 100644 --- a/episode19/demo5.js +++ b/episode19/demo5.js @@ -1,130 +1,130 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - p0 = { - x: 100, - y: 500 - }, - p1 = { - x: 600, - y: 200 - }, - p2 = { - x: 1000, - y: 400 - }, - pA = {}, - pB = {}, - pFinal = {}, - t = 0, - maxT = 0, - dir = 0.01; - - context.scale(1.5, 1.5); - context.font = "16px Arial"; - draw(); - - function draw() { - context.clearRect(0, 0, width, height); - - context.strokeStyle = "#ccc"; - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.lineTo(p1.x, p1.y); - context.lineTo(p2.x, p2.y); - context.stroke(); - - context.beginPath(); - context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(p2.x, p2.y, 4, 0, Math.PI * 2, false); - context.fill(); - - - context.strokeStyle = "red"; - context.beginPath(); - context.moveTo(p0.x, p0.y); - - for(t = 0; t <= maxT; t += Math.abs(dir)) { - pA.x = utils.lerp(t, p0.x, p1.x); - pA.y = utils.lerp(t, p0.y, p1.y); - - pB.x = utils.lerp(t, p1.x, p2.x); - pB.y = utils.lerp(t, p1.y, p2.y); - - pFinal.x = utils.lerp(t, pA.x, pB.x); - pFinal.y = utils.lerp(t, pA.y, pB.y); - - context.lineTo(pFinal.x, pFinal.y); - } - context.stroke(); - - context.beginPath(); - context.strokeStyle = "gray"; - context.moveTo(pA.x, pA.y); - context.lineTo(pB.x, pB.y); - context.stroke(); - - context.beginPath(); - context.arc(pA.x, pA.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(pB.x, pB.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.fillStyle = "red"; - context.beginPath(); - context.arc(pFinal.x, pFinal.y, 4, 0, Math.PI * 2, false); - context.fill(); - context.fillStyle = "black"; - - - - // labelPointLeft(p0, "p0"); - // labelPointLeft(p1, "p1"); - // labelPointLeft(p2, "p2"); - // labelPoint(pA, "pA"); - // labelPoint(pB, "pB"); - labelT(); - - maxT += dir; - if(maxT >= 1) { - maxT = 1; - dir *= -1; - } - if(maxT <= 0) { - maxT = 0; - dir *= -1; - } - - requestAnimationFrame(draw); - } - - function labelPoint(p, name) { - context.fillStyle = "black"; - context.fillText(name, p.x + 10, p.y + 10); - context.fillText("x: " + Math.round(p.x), p.x + 10, p.y + 25); - context.fillText("y: " + Math.round(p.y), p.x + 10, p.y + 40); - } - - function labelPointLeft(p, name) { - context.fillStyle = "gray"; - context.fillText(name, p.x - 40, p.y - 40); - context.fillText("x: " + Math.round(p.x), p.x - 40, p.y - 25); - context.fillText("y: " + Math.round(p.y), p.x - 40, p.y - 10); - } - - function labelT() { - context.fillText("t = " + utils.roundToPlaces(maxT, 2), 200, 250); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: 100, + y: 500 + }, + p1 = { + x: 600, + y: 200 + }, + p2 = { + x: 1000, + y: 400 + }, + pA = {}, + pB = {}, + pFinal = {}, + t = 0, + maxT = 0, + dir = 0.01; + + context.scale(1.5, 1.5); + context.font = "16px Arial"; + draw(); + + function draw() { + context.clearRect(0, 0, width, height); + + context.strokeStyle = "#ccc"; + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.lineTo(p2.x, p2.y); + context.stroke(); + + context.beginPath(); + context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p2.x, p2.y, 4, 0, Math.PI * 2, false); + context.fill(); + + + context.strokeStyle = "red"; + context.beginPath(); + context.moveTo(p0.x, p0.y); + + for(t = 0; t <= maxT; t += Math.abs(dir)) { + pA.x = utils.lerp(t, p0.x, p1.x); + pA.y = utils.lerp(t, p0.y, p1.y); + + pB.x = utils.lerp(t, p1.x, p2.x); + pB.y = utils.lerp(t, p1.y, p2.y); + + pFinal.x = utils.lerp(t, pA.x, pB.x); + pFinal.y = utils.lerp(t, pA.y, pB.y); + + context.lineTo(pFinal.x, pFinal.y); + } + context.stroke(); + + context.beginPath(); + context.strokeStyle = "gray"; + context.moveTo(pA.x, pA.y); + context.lineTo(pB.x, pB.y); + context.stroke(); + + context.beginPath(); + context.arc(pA.x, pA.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(pB.x, pB.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.fillStyle = "red"; + context.beginPath(); + context.arc(pFinal.x, pFinal.y, 4, 0, Math.PI * 2, false); + context.fill(); + context.fillStyle = "black"; + + + + // labelPointLeft(p0, "p0"); + // labelPointLeft(p1, "p1"); + // labelPointLeft(p2, "p2"); + // labelPoint(pA, "pA"); + // labelPoint(pB, "pB"); + labelT(); + + maxT += dir; + if(maxT >= 1) { + maxT = 1; + dir *= -1; + } + if(maxT <= 0) { + maxT = 0; + dir *= -1; + } + + requestAnimationFrame(draw); + } + + function labelPoint(p, name) { + context.fillStyle = "black"; + context.fillText(name, p.x + 10, p.y + 10); + context.fillText("x: " + Math.round(p.x), p.x + 10, p.y + 25); + context.fillText("y: " + Math.round(p.y), p.x + 10, p.y + 40); + } + + function labelPointLeft(p, name) { + context.fillStyle = "gray"; + context.fillText(name, p.x - 40, p.y - 40); + context.fillText("x: " + Math.round(p.x), p.x - 40, p.y - 25); + context.fillText("y: " + Math.round(p.y), p.x - 40, p.y - 10); + } + + function labelT() { + context.fillText("t = " + utils.roundToPlaces(maxT, 2), 200, 250); + } + }; \ No newline at end of file diff --git a/episode19/demo6.js b/episode19/demo6.js index ab2d52d..00e4eb8 100644 --- a/episode19/demo6.js +++ b/episode19/demo6.js @@ -1,180 +1,180 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - p0 = { - x: 100, - y: 500 - }, - p1 = { - x: 400, - y: 200 - }, - p2 = { - x: 1000, - y: 400 - }, - p3 = { - x: 800, - y: 50 - }, - pA = {}, - pB = {}, - pC = {}, - pM = {}, - pN = {}, - pFinal = {}, - t = 0, - maxT = 0, - dir = 0.005, - animating = false;; - - context.scale(1.5, 1.5); - context.font = "16px Arial"; - - draw(); - document.body.addEventListener("click", function() { - animating = true; - draw(); - }); - - function draw() { - context.clearRect(0, 0, width, height); - - context.strokeStyle = "#ccc"; - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.lineTo(p1.x, p1.y); - context.lineTo(p2.x, p2.y); - context.lineTo(p3.x, p3.y); - context.stroke(); - - context.beginPath(); - context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(p2.x, p2.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(p3.x, p3.y, 4, 0, Math.PI * 2, false); - context.fill(); - - - context.strokeStyle = "red"; - context.beginPath(); - context.moveTo(p0.x, p0.y); - - for(t = 0; t <= maxT; t += Math.abs(dir)) { - pA.x = utils.lerp(t, p0.x, p1.x); - pA.y = utils.lerp(t, p0.y, p1.y); - - pB.x = utils.lerp(t, p1.x, p2.x); - pB.y = utils.lerp(t, p1.y, p2.y); - - pC.x = utils.lerp(t, p2.x, p3.x); - pC.y = utils.lerp(t, p2.y, p3.y); - - pM.x = utils.lerp(t, pA.x, pB.x); - pM.y = utils.lerp(t, pA.y, pB.y); - - pN.x = utils.lerp(t, pB.x, pC.x); - pN.y = utils.lerp(t, pB.y, pC.y); - - pFinal.x = utils.lerp(t, pM.x, pN.x); - pFinal.y = utils.lerp(t, pM.y, pN.y); - - context.lineTo(pFinal.x, pFinal.y); - } - context.stroke(); - - context.beginPath(); - context.strokeStyle = "green"; - context.moveTo(pA.x, pA.y); - context.lineTo(pB.x, pB.y); - context.lineTo(pC.x, pC.y); - context.stroke(); - - context.beginPath(); - context.strokeStyle = "blue"; - context.moveTo(pM.x, pM.y); - context.lineTo(pN.x, pN.y); - context.stroke(); - - context.fillStyle = "green"; - context.beginPath(); - context.arc(pA.x, pA.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(pB.x, pB.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(pC.x, pC.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.fillStyle = "blue"; - context.beginPath(); - context.arc(pM.x, pM.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(pN.x, pN.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.fillStyle = "red"; - context.beginPath(); - context.arc(pFinal.x, pFinal.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.fillStyle = "black"; - - - - // labelPointLeft(p0, "p0"); - // labelPointLeft(p1, "p1"); - // labelPointLeft(p2, "p2"); - // labelPoint(pA, "pA"); - // labelPoint(pB, "pB"); - labelT(); - - maxT += dir; - if(maxT >= 1) { - maxT = 1; - dir *= -1; - } - if(maxT <= 0) { - maxT = 0; - dir *= -1; - } - - if(animating) - requestAnimationFrame(draw); - } - - function labelPoint(p, name) { - context.fillStyle = "black"; - context.fillText(name, p.x + 10, p.y + 10); - context.fillText("x: " + Math.round(p.x), p.x + 10, p.y + 25); - context.fillText("y: " + Math.round(p.y), p.x + 10, p.y + 40); - } - - function labelPointLeft(p, name) { - context.fillStyle = "gray"; - context.fillText(name, p.x - 40, p.y - 40); - context.fillText("x: " + Math.round(p.x), p.x - 40, p.y - 25); - context.fillText("y: " + Math.round(p.y), p.x - 40, p.y - 10); - } - - function labelT() { - context.fillText("t = " + utils.roundToPlaces(maxT, 2), 200, 250); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: 100, + y: 500 + }, + p1 = { + x: 400, + y: 200 + }, + p2 = { + x: 1000, + y: 400 + }, + p3 = { + x: 800, + y: 50 + }, + pA = {}, + pB = {}, + pC = {}, + pM = {}, + pN = {}, + pFinal = {}, + t = 0, + maxT = 0, + dir = 0.005, + animating = false;; + + context.scale(1.5, 1.5); + context.font = "16px Arial"; + + draw(); + document.body.addEventListener("click", function() { + animating = true; + draw(); + }); + + function draw() { + context.clearRect(0, 0, width, height); + + context.strokeStyle = "#ccc"; + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.lineTo(p2.x, p2.y); + context.lineTo(p3.x, p3.y); + context.stroke(); + + context.beginPath(); + context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p2.x, p2.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p3.x, p3.y, 4, 0, Math.PI * 2, false); + context.fill(); + + + context.strokeStyle = "red"; + context.beginPath(); + context.moveTo(p0.x, p0.y); + + for(t = 0; t <= maxT; t += Math.abs(dir)) { + pA.x = utils.lerp(t, p0.x, p1.x); + pA.y = utils.lerp(t, p0.y, p1.y); + + pB.x = utils.lerp(t, p1.x, p2.x); + pB.y = utils.lerp(t, p1.y, p2.y); + + pC.x = utils.lerp(t, p2.x, p3.x); + pC.y = utils.lerp(t, p2.y, p3.y); + + pM.x = utils.lerp(t, pA.x, pB.x); + pM.y = utils.lerp(t, pA.y, pB.y); + + pN.x = utils.lerp(t, pB.x, pC.x); + pN.y = utils.lerp(t, pB.y, pC.y); + + pFinal.x = utils.lerp(t, pM.x, pN.x); + pFinal.y = utils.lerp(t, pM.y, pN.y); + + context.lineTo(pFinal.x, pFinal.y); + } + context.stroke(); + + context.beginPath(); + context.strokeStyle = "green"; + context.moveTo(pA.x, pA.y); + context.lineTo(pB.x, pB.y); + context.lineTo(pC.x, pC.y); + context.stroke(); + + context.beginPath(); + context.strokeStyle = "blue"; + context.moveTo(pM.x, pM.y); + context.lineTo(pN.x, pN.y); + context.stroke(); + + context.fillStyle = "green"; + context.beginPath(); + context.arc(pA.x, pA.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(pB.x, pB.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(pC.x, pC.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.fillStyle = "blue"; + context.beginPath(); + context.arc(pM.x, pM.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(pN.x, pN.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.fillStyle = "red"; + context.beginPath(); + context.arc(pFinal.x, pFinal.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.fillStyle = "black"; + + + + // labelPointLeft(p0, "p0"); + // labelPointLeft(p1, "p1"); + // labelPointLeft(p2, "p2"); + // labelPoint(pA, "pA"); + // labelPoint(pB, "pB"); + labelT(); + + maxT += dir; + if(maxT >= 1) { + maxT = 1; + dir *= -1; + } + if(maxT <= 0) { + maxT = 0; + dir *= -1; + } + + if(animating) + requestAnimationFrame(draw); + } + + function labelPoint(p, name) { + context.fillStyle = "black"; + context.fillText(name, p.x + 10, p.y + 10); + context.fillText("x: " + Math.round(p.x), p.x + 10, p.y + 25); + context.fillText("y: " + Math.round(p.y), p.x + 10, p.y + 40); + } + + function labelPointLeft(p, name) { + context.fillStyle = "gray"; + context.fillText(name, p.x - 40, p.y - 40); + context.fillText("x: " + Math.round(p.x), p.x - 40, p.y - 25); + context.fillText("y: " + Math.round(p.y), p.x - 40, p.y - 10); + } + + function labelT() { + context.fillText("t = " + utils.roundToPlaces(maxT, 2), 200, 250); + } + }; \ No newline at end of file diff --git a/episode19/index.html b/episode19/index.html index ec278a5..30c3a9a 100644 --- a/episode19/index.html +++ b/episode19/index.html @@ -1,21 +1,21 @@ - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/episode19/main1.js b/episode19/main1.js index 7538236..4e63997 100644 --- a/episode19/main1.js +++ b/episode19/main1.js @@ -1,53 +1,53 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - p0 = { - x: utils.randomRange(0, width), - y: utils.randomRange(0, height) - }, - p1 = { - x: utils.randomRange(0, width), - y: utils.randomRange(0, height) - }, - p2 = { - x: utils.randomRange(0, width), - y: utils.randomRange(0, height) - }, - p3 = { - x: utils.randomRange(0, width), - y: utils.randomRange(0, height) - }; - - context.beginPath(); - context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(p2.x, p2.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.arc(p3.x, p3.y, 4, 0, Math.PI * 2, false); - context.fill(); - - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.bezierCurveTo(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); - context.stroke(); - - var pFinal = {}; - - for(var t = 0; t <= 1; t += 0.01) { - utils.cubicBezier(p0, p1, p2, p3, t, pFinal); - context.beginPath(); - context.arc(pFinal.x, pFinal.y, 10, 0, Math.PI * 2, false); - context.stroke(); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + p1 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + p2 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + p3 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }; + + context.beginPath(); + context.arc(p0.x, p0.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p1.x, p1.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p2.x, p2.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.arc(p3.x, p3.y, 4, 0, Math.PI * 2, false); + context.fill(); + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.bezierCurveTo(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); + context.stroke(); + + var pFinal = {}; + + for(var t = 0; t <= 1; t += 0.01) { + utils.cubicBezier(p0, p1, p2, p3, t, pFinal); + context.beginPath(); + context.arc(pFinal.x, pFinal.y, 10, 0, Math.PI * 2, false); + context.stroke(); + } + }; \ No newline at end of file diff --git a/episode19/main2.js b/episode19/main2.js index c794624..0eb8097 100644 --- a/episode19/main2.js +++ b/episode19/main2.js @@ -1,44 +1,44 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - p0 = { - x: utils.randomRange(0, width), - y: utils.randomRange(0, height) - }, - p1 = { - x: utils.randomRange(0, width), - y: utils.randomRange(0, height) - }, - p2 = { - x: utils.randomRange(0, width), - y: utils.randomRange(0, height) - }, - p3 = { - x: utils.randomRange(0, width), - y: utils.randomRange(0, height) - }, - maxT = 0, - pFinal = {}; - - - draw(); - - function draw() { - context.clearRect(0, 0, width, height); - context.beginPath(); - context.moveTo(p0.x, p0.y); - for(var t = 0; t <= maxT; t += 0.01) { - utils.cubicBezier(p0, p1, p2, p3, t, pFinal); - context.lineTo(pFinal.x, pFinal.y); - } - context.stroke(); - maxT += 0.01; - if(maxT > 1) { - maxT = 0; - } - - requestAnimationFrame(draw); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + p1 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + p2 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + p3 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + maxT = 0, + pFinal = {}; + + + draw(); + + function draw() { + context.clearRect(0, 0, width, height); + context.beginPath(); + context.moveTo(p0.x, p0.y); + for(var t = 0; t <= maxT; t += 0.01) { + utils.cubicBezier(p0, p1, p2, p3, t, pFinal); + context.lineTo(pFinal.x, pFinal.y); + } + context.stroke(); + maxT += 0.01; + if(maxT > 1) { + maxT = 0; + } + + requestAnimationFrame(draw); + } }; \ No newline at end of file diff --git a/episode19/main3.js b/episode19/main3.js index da0e8a9..33c7ecf 100644 --- a/episode19/main3.js +++ b/episode19/main3.js @@ -1,49 +1,49 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - p0 = { - x: utils.randomRange(0, width), - y: utils.randomRange(0, height) - }, - p1 = { - x: utils.randomRange(0, width), - y: utils.randomRange(0, height) - }, - p2 = { - x: utils.randomRange(0, width), - y: utils.randomRange(0, height) - }, - p3 = { - x: utils.randomRange(0, width), - y: utils.randomRange(0, height) - }, - t = 0, - direction = 0.01, - pFinal = {}; - - - draw(); - - function draw() { - context.clearRect(0, 0, width, height); - - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.bezierCurveTo(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); - context.stroke(); - - utils.cubicBezier(p0, p1, p2, p3, t, pFinal); - context.beginPath(); - context.arc(pFinal.x, pFinal.y, 10, 0, Math.PI * 2, false); - context.fill(); - - t += direction; - if(t > 1 || t < 0) { - direction = -direction; - } - - requestAnimationFrame(draw); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + p1 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + p2 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + p3 = { + x: utils.randomRange(0, width), + y: utils.randomRange(0, height) + }, + t = 0, + direction = 0.01, + pFinal = {}; + + + draw(); + + function draw() { + context.clearRect(0, 0, width, height); + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.bezierCurveTo(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); + context.stroke(); + + utils.cubicBezier(p0, p1, p2, p3, t, pFinal); + context.beginPath(); + context.arc(pFinal.x, pFinal.y, 10, 0, Math.PI * 2, false); + context.fill(); + + t += direction; + if(t > 1 || t < 0) { + direction = -direction; + } + + requestAnimationFrame(draw); + } }; \ No newline at end of file diff --git a/episode19/utils.js b/episode19/utils.js index 7c659e4..25aa5da 100644 --- a/episode19/utils.js +++ b/episode19/utils.js @@ -1,106 +1,106 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - }, - - degreesToRads: function(degrees) { - return degrees / 180 * Math.PI; - }, - - radsToDegrees: function(radians) { - return radians * 180 / Math.PI; - }, - - randomRange: function(min, max) { - return min + Math.random() * (max - min); - }, - - randomInt: function(min, max) { - return Math.floor(min + Math.random() * (max - min + 1)); - }, - - roundToPlaces: function(value, places) { - var mult = Math.pow(10, places); - return Math.round(value * mult) / mult; - }, - - roundNearest: function(value, nearest) { - return Math.round(value / nearest) * nearest; - }, - - quadraticBezier: function(p0, p1, p2, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 2) * p0.x + - (1 - t) * 2 * t * p1.x + - t * t * p2.x; - pFinal.y = Math.pow(1 - t, 2) * p0.y + - (1 - t) * 2 * t * p1.y + - t * t * p2.y; - return pFinal; - }, - - cubicBezier: function(p0, p1, p2, p3, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 3) * p0.x + - Math.pow(1 - t, 2) * 3 * t * p1.x + - (1 - t) * 3 * t * t * p2.x + - t * t * t * p3.x; - pFinal.y = Math.pow(1 - t, 3) * p0.y + - Math.pow(1 - t, 2) * 3 * t * p1.y + - (1 - t) * 3 * t * t * p2.y + - t * t * t * p3.y; - return pFinal; - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + } + } \ No newline at end of file diff --git a/episode2/index.html b/episode2/index.html index 157f160..8c1aafb 100644 --- a/episode2/index.html +++ b/episode2/index.html @@ -1,18 +1,18 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/episode2/trig01.js b/episode2/trig01.js index 52ddad6..296d191 100644 --- a/episode2/trig01.js +++ b/episode2/trig01.js @@ -1,21 +1,21 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - context.translate(0, height / 2); - context.scale(1, -1); - - for(var angle = 0; angle < Math.PI * 2; angle += .01) { - var x = angle * 200, - y = Math.sin(angle) * 200; - - context.fillStyle = "black"; - context.fillRect(x, y, 5, 5); - - y = Math.cos(angle) * 200; - context.fillStyle = "red"; - context.fillRect(x, y, 5, 5); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + context.translate(0, height / 2); + context.scale(1, -1); + + for(var angle = 0; angle < Math.PI * 2; angle += .01) { + var x = angle * 200, + y = Math.sin(angle) * 200; + + context.fillStyle = "black"; + context.fillRect(x, y, 5, 5); + + y = Math.cos(angle) * 200; + context.fillStyle = "red"; + context.fillRect(x, y, 5, 5); + } }; \ No newline at end of file diff --git a/episode20/index.html b/episode20/index.html index ec278a5..30c3a9a 100644 --- a/episode20/index.html +++ b/episode20/index.html @@ -1,21 +1,21 @@ - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/episode20/main1.js b/episode20/main1.js index 044e788..2a0a17c 100644 --- a/episode20/main1.js +++ b/episode20/main1.js @@ -1,46 +1,46 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - p0 = { - x: Math.random() * width, - y: Math.random() * height - }, - p1 = { - x: Math.random() * width, - y: Math.random() * height - }, - p2 = { - x: Math.random() * width, - y: Math.random() * height - }, - cp = {}; - - cp.x = p1.x * 2 - (p0.x + p2.x) / 2; - cp.y = p1.y * 2 - (p0.y + p2.y) / 2; - - drawPoint(p0); - drawPoint(p1); - drawPoint(p2); - drawPoint(cp); - - context.strokeStyle = "lightgray"; - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.lineTo(cp.x, cp.y); - context.lineTo(p2.x, p2.y); - context.stroke(); - - context.strokeStyle = "black"; - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.quadraticCurveTo(cp.x, cp.y, p2.x, p2.y); - context.stroke(); - - function drawPoint(p) { - context.beginPath(); - context.arc(p.x, p.y, 3, 0, Math.PI * 2, false); - context.fill(); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: Math.random() * width, + y: Math.random() * height + }, + p1 = { + x: Math.random() * width, + y: Math.random() * height + }, + p2 = { + x: Math.random() * width, + y: Math.random() * height + }, + cp = {}; + + cp.x = p1.x * 2 - (p0.x + p2.x) / 2; + cp.y = p1.y * 2 - (p0.y + p2.y) / 2; + + drawPoint(p0); + drawPoint(p1); + drawPoint(p2); + drawPoint(cp); + + context.strokeStyle = "lightgray"; + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(cp.x, cp.y); + context.lineTo(p2.x, p2.y); + context.stroke(); + + context.strokeStyle = "black"; + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.quadraticCurveTo(cp.x, cp.y, p2.x, p2.y); + context.stroke(); + + function drawPoint(p) { + context.beginPath(); + context.arc(p.x, p.y, 3, 0, Math.PI * 2, false); + context.fill(); + } }; \ No newline at end of file diff --git a/episode20/main2.js b/episode20/main2.js index 9d2c7bc..c5031ab 100644 --- a/episode20/main2.js +++ b/episode20/main2.js @@ -1,36 +1,36 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - points = [], - numPoints = 10; - - for(var i = 0; i < numPoints; i += 1) { - var p = { - x: Math.random() * width, - y: Math.random() * height - }; - - context.beginPath(); - context.arc(p.x, p.y, 3, 0, Math.PI * 2, false); - context.fill(); - - points.push(p); - } - - context.strokeStyle = "lightgray"; - context.beginPath(); - context.moveTo(points[0].x, points[0].y); - for(var i = 1; i < numPoints; i += 1) { - context.lineTo(points[i].x, points[i].y); - } - context.stroke(); - - context.strokeStyle = "black"; - - context.beginPath(); - utils.multicurve(points, context); - context.stroke(); - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + points = [], + numPoints = 10; + + for(var i = 0; i < numPoints; i += 1) { + var p = { + x: Math.random() * width, + y: Math.random() * height + }; + + context.beginPath(); + context.arc(p.x, p.y, 3, 0, Math.PI * 2, false); + context.fill(); + + points.push(p); + } + + context.strokeStyle = "lightgray"; + context.beginPath(); + context.moveTo(points[0].x, points[0].y); + for(var i = 1; i < numPoints; i += 1) { + context.lineTo(points[i].x, points[i].y); + } + context.stroke(); + + context.strokeStyle = "black"; + + context.beginPath(); + utils.multicurve(points, context); + context.stroke(); + }; \ No newline at end of file diff --git a/episode20/main3.js b/episode20/main3.js index 68347c9..fd2b2a6 100644 --- a/episode20/main3.js +++ b/episode20/main3.js @@ -1,33 +1,33 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - p0 = { - x: Math.random() * width, - y: Math.random() * height - }, - p1 = { - x: Math.random() * width, - y: Math.random() * height - }, - p2 = { - x: Math.random() * width, - y: Math.random() * height - }, - p3 = { - x: Math.random() * width, - y: Math.random() * height - }; - - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.bezierCurveTo(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); - context.stroke(); - - context.strokeStyle = "red"; - context.beginPath(); - utils.multicurve([p0, p1, p2, p3], context); - context.stroke(); - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p0 = { + x: Math.random() * width, + y: Math.random() * height + }, + p1 = { + x: Math.random() * width, + y: Math.random() * height + }, + p2 = { + x: Math.random() * width, + y: Math.random() * height + }, + p3 = { + x: Math.random() * width, + y: Math.random() * height + }; + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.bezierCurveTo(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); + context.stroke(); + + context.strokeStyle = "red"; + context.beginPath(); + utils.multicurve([p0, p1, p2, p3], context); + context.stroke(); + }; \ No newline at end of file diff --git a/episode20/utils.js b/episode20/utils.js index 3c0f824..04715df 100644 --- a/episode20/utils.js +++ b/episode20/utils.js @@ -1,123 +1,123 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - }, - - degreesToRads: function(degrees) { - return degrees / 180 * Math.PI; - }, - - radsToDegrees: function(radians) { - return radians * 180 / Math.PI; - }, - - randomRange: function(min, max) { - return min + Math.random() * (max - min); - }, - - randomInt: function(min, max) { - return Math.floor(min + Math.random() * (max - min + 1)); - }, - - roundToPlaces: function(value, places) { - var mult = Math.pow(10, places); - return Math.round(value * mult) / mult; - }, - - roundNearest: function(value, nearest) { - return Math.round(value / nearest) * nearest; - }, - - quadraticBezier: function(p0, p1, p2, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 2) * p0.x + - (1 - t) * 2 * t * p1.x + - t * t * p2.x; - pFinal.y = Math.pow(1 - t, 2) * p0.y + - (1 - t) * 2 * t * p1.y + - t * t * p2.y; - return pFinal; - }, - - cubicBezier: function(p0, p1, p2, p3, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 3) * p0.x + - Math.pow(1 - t, 2) * 3 * t * p1.x + - (1 - t) * 3 * t * t * p2.x + - t * t * t * p3.x; - pFinal.y = Math.pow(1 - t, 3) * p0.y + - Math.pow(1 - t, 2) * 3 * t * p1.y + - (1 - t) * 3 * t * t * p2.y + - t * t * t * p3.y; - return pFinal; - }, - - multicurve: function(points, context) { - var p0, p1, midx, midy; - - context.moveTo(points[0].x, points[0].y); - - for(var i = 1; i < points.length - 2; i += 1) { - p0 = points[i]; - p1 = points[i + 1]; - midx = (p0.x + p1.x) / 2; - midy = (p0.y + p1.y) / 2; - context.quadraticCurveTo(p0.x, p0.y, midx, midy); - } - p0 = points[points.length - 2]; - p1 = points[points.length - 1]; - context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + }, + + multicurve: function(points, context) { + var p0, p1, midx, midy; + + context.moveTo(points[0].x, points[0].y); + + for(var i = 1; i < points.length - 2; i += 1) { + p0 = points[i]; + p1 = points[i + 1]; + midx = (p0.x + p1.x) / 2; + midy = (p0.y + p1.y) / 2; + context.quadraticCurveTo(p0.x, p0.y, midx, midy); + } + p0 = points[points.length - 2]; + p1 = points[points.length - 1]; + context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); + } + } \ No newline at end of file diff --git a/episode21/index.html b/episode21/index.html index 5a12f32..570ae0b 100644 --- a/episode21/index.html +++ b/episode21/index.html @@ -1,27 +1,27 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/episode21/main.js b/episode21/main.js index aac23c0..7c879c7 100644 --- a/episode21/main.js +++ b/episode21/main.js @@ -1,46 +1,46 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - targetCanvas = document.getElementById("target"), - targetContext = targetCanvas.getContext("2d"), - width = canvas.width = targetCanvas.width = window.innerWidth, - height = canvas.height = targetCanvas.height = window.innerHeight, - p = particle.create(0, height / 2, 10, 0); - - targetContext.beginPath(); - targetContext.arc(width / 2, height / 2, 200, 0, Math.PI * 2, false); - targetContext.fill(); - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - p.update(); - context.beginPath(); - context.arc(p.x, p.y, 4, 0, Math.PI * 2, false); - context.fill(); - - var imageData = targetContext.getImageData(p.x, p.y, 1, 1); - if(imageData.data[3] > 0) { - targetContext.globalCompositeOperation = "destination-out"; - targetContext.beginPath(); - targetContext.arc(p.x, p.y, 20, 0, Math.PI * 2, false); - targetContext.fill(); - - resetParticle(); - } - else if(p.x > width) { - resetParticle(); - } - requestAnimationFrame(update); - } - - function resetParticle() { - p.x = 0; - p.y = height / 2; - p.setHeading(utils.randomRange(-0.1, 0.1)); - } - - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + targetCanvas = document.getElementById("target"), + targetContext = targetCanvas.getContext("2d"), + width = canvas.width = targetCanvas.width = window.innerWidth, + height = canvas.height = targetCanvas.height = window.innerHeight, + p = particle.create(0, height / 2, 10, 0); + + targetContext.beginPath(); + targetContext.arc(width / 2, height / 2, 200, 0, Math.PI * 2, false); + targetContext.fill(); + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + p.update(); + context.beginPath(); + context.arc(p.x, p.y, 4, 0, Math.PI * 2, false); + context.fill(); + + var imageData = targetContext.getImageData(p.x, p.y, 1, 1); + if(imageData.data[3] > 0) { + targetContext.globalCompositeOperation = "destination-out"; + targetContext.beginPath(); + targetContext.arc(p.x, p.y, 20, 0, Math.PI * 2, false); + targetContext.fill(); + + resetParticle(); + } + else if(p.x > width) { + resetParticle(); + } + requestAnimationFrame(update); + } + + function resetParticle() { + p.x = 0; + p.y = height / 2; + p.setHeading(utils.randomRange(-0.1, 0.1)); + } + + }; \ No newline at end of file diff --git a/episode21/particle.js b/episode21/particle.js index b6ef621..948e47a 100644 --- a/episode21/particle.js +++ b/episode21/particle.js @@ -1,138 +1,138 @@ -var particle = { - x: 0, - y: 0, - vx: 0, - vy: 0, - mass: 1, - radius: 0, - bounce: -1, - friction: 1, - gravity: 0, - springs: null, - gravitations: null, - - create: function(x, y, speed, direction, grav) { - var obj = Object.create(this); - obj.x = x; - obj.y = y; - obj.vx = Math.cos(direction) * speed; - obj.vy = Math.sin(direction) * speed; - obj.gravity = grav || 0; - obj.springs = []; - obj.gravitations = []; - return obj; - }, - - addGravitation: function(p) { - this.removeGravitation(p); - this.gravitations.push(p); - }, - - removeGravitation: function(p) { - for(var i = 0; i < this.gravitations.length; i += 1) { - if(p === this.gravitations[i]) { - this.gravitations.splice(i, 1); - return; - } - } - }, - - addSpring: function(point, k, length) { - this.removeSpring(point); - this.springs.push({ - point: point, - k: k, - length: length || 0 - }); - }, - - removeSpring: function(point) { - for(var i = 0; i < this.springs.length; i += 1) { - if(point === this.springs[i].point) { - this.springs.splice(i, 1); - return; - } - } - }, - - getSpeed: function() { - return Math.sqrt(this.vx * this.vx + this.vy * this.vy); - }, - - setSpeed: function(speed) { - var heading = this.getHeading(); - this.vx = Math.cos(heading) * speed; - this.vy = Math.sin(heading) * speed; - }, - - getHeading: function() { - return Math.atan2(this.vy, this.vx); - }, - - setHeading: function(heading) { - var speed = this.getSpeed(); - this.vx = Math.cos(heading) * speed; - this.vy = Math.sin(heading) * speed; - }, - - accelerate: function(ax, ay) { - this.vx += ax; - this.vy += ay; - }, - - update: function() { - this.handleSprings(); - this.handleGravitations(); - this.vx *= this.friction; - this.vy *= this.friction; - this.vy += this.gravity; - this.x += this.vx; - this.y += this.vy; - }, - - handleGravitations: function() { - for(var i = 0; i < this.gravitations.length; i += 1) { - this.gravitateTo(this.gravitations[i]); - } - }, - - handleSprings: function() { - for(var i = 0; i < this.springs.length; i += 1) { - var spring = this.springs[i]; - this.springTo(spring.point, spring.k, spring.length); - } - }, - - angleTo: function(p2) { - return Math.atan2(p2.y - this.y, p2.x - this.x); - }, - - distanceTo: function(p2) { - var dx = p2.x - this.x, - dy = p2.y - this.y; - - return Math.sqrt(dx * dx + dy * dy); - }, - - gravitateTo: function(p2) { - var dx = p2.x - this.x, - dy = p2.y - this.y, - distSQ = dx * dx + dy * dy, - dist = Math.sqrt(distSQ), - force = p2.mass / distSQ, - ax = dx / dist * force, - ay = dy / dist * force; - - this.vx += ax; - this.vy += ay; - }, - - springTo: function(point, k, length) { - var dx = point.x - this.x, - dy = point.y - this.y, - distance = Math.sqrt(dx * dx + dy * dy), - springForce = (distance - length || 0) * k; - this.vx += dx / distance * springForce, - this.vy += dy / distance * springForce; - } +var particle = { + x: 0, + y: 0, + vx: 0, + vy: 0, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + springs: null, + gravitations: null, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.x = x; + obj.y = y; + obj.vx = Math.cos(direction) * speed; + obj.vy = Math.sin(direction) * speed; + obj.gravity = grav || 0; + obj.springs = []; + obj.gravitations = []; + return obj; + }, + + addGravitation: function(p) { + this.removeGravitation(p); + this.gravitations.push(p); + }, + + removeGravitation: function(p) { + for(var i = 0; i < this.gravitations.length; i += 1) { + if(p === this.gravitations[i]) { + this.gravitations.splice(i, 1); + return; + } + } + }, + + addSpring: function(point, k, length) { + this.removeSpring(point); + this.springs.push({ + point: point, + k: k, + length: length || 0 + }); + }, + + removeSpring: function(point) { + for(var i = 0; i < this.springs.length; i += 1) { + if(point === this.springs[i].point) { + this.springs.splice(i, 1); + return; + } + } + }, + + getSpeed: function() { + return Math.sqrt(this.vx * this.vx + this.vy * this.vy); + }, + + setSpeed: function(speed) { + var heading = this.getHeading(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + getHeading: function() { + return Math.atan2(this.vy, this.vx); + }, + + setHeading: function(heading) { + var speed = this.getSpeed(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + accelerate: function(ax, ay) { + this.vx += ax; + this.vy += ay; + }, + + update: function() { + this.handleSprings(); + this.handleGravitations(); + this.vx *= this.friction; + this.vy *= this.friction; + this.vy += this.gravity; + this.x += this.vx; + this.y += this.vy; + }, + + handleGravitations: function() { + for(var i = 0; i < this.gravitations.length; i += 1) { + this.gravitateTo(this.gravitations[i]); + } + }, + + handleSprings: function() { + for(var i = 0; i < this.springs.length; i += 1) { + var spring = this.springs[i]; + this.springTo(spring.point, spring.k, spring.length); + } + }, + + angleTo: function(p2) { + return Math.atan2(p2.y - this.y, p2.x - this.x); + }, + + distanceTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y; + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y, + distSQ = dx * dx + dy * dy, + dist = Math.sqrt(distSQ), + force = p2.mass / distSQ, + ax = dx / dist * force, + ay = dy / dist * force; + + this.vx += ax; + this.vy += ay; + }, + + springTo: function(point, k, length) { + var dx = point.x - this.x, + dy = point.y - this.y, + distance = Math.sqrt(dx * dx + dy * dy), + springForce = (distance - length || 0) * k; + this.vx += dx / distance * springForce, + this.vy += dy / distance * springForce; + } }; \ No newline at end of file diff --git a/episode21/utils.js b/episode21/utils.js index 3c0f824..04715df 100644 --- a/episode21/utils.js +++ b/episode21/utils.js @@ -1,123 +1,123 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - }, - - degreesToRads: function(degrees) { - return degrees / 180 * Math.PI; - }, - - radsToDegrees: function(radians) { - return radians * 180 / Math.PI; - }, - - randomRange: function(min, max) { - return min + Math.random() * (max - min); - }, - - randomInt: function(min, max) { - return Math.floor(min + Math.random() * (max - min + 1)); - }, - - roundToPlaces: function(value, places) { - var mult = Math.pow(10, places); - return Math.round(value * mult) / mult; - }, - - roundNearest: function(value, nearest) { - return Math.round(value / nearest) * nearest; - }, - - quadraticBezier: function(p0, p1, p2, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 2) * p0.x + - (1 - t) * 2 * t * p1.x + - t * t * p2.x; - pFinal.y = Math.pow(1 - t, 2) * p0.y + - (1 - t) * 2 * t * p1.y + - t * t * p2.y; - return pFinal; - }, - - cubicBezier: function(p0, p1, p2, p3, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 3) * p0.x + - Math.pow(1 - t, 2) * 3 * t * p1.x + - (1 - t) * 3 * t * t * p2.x + - t * t * t * p3.x; - pFinal.y = Math.pow(1 - t, 3) * p0.y + - Math.pow(1 - t, 2) * 3 * t * p1.y + - (1 - t) * 3 * t * t * p2.y + - t * t * t * p3.y; - return pFinal; - }, - - multicurve: function(points, context) { - var p0, p1, midx, midy; - - context.moveTo(points[0].x, points[0].y); - - for(var i = 1; i < points.length - 2; i += 1) { - p0 = points[i]; - p1 = points[i + 1]; - midx = (p0.x + p1.x) / 2; - midy = (p0.y + p1.y) / 2; - context.quadraticCurveTo(p0.x, p0.y, midx, midy); - } - p0 = points[points.length - 2]; - p1 = points[points.length - 1]; - context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + }, + + multicurve: function(points, context) { + var p0, p1, midx, midy; + + context.moveTo(points[0].x, points[0].y); + + for(var i = 1; i < points.length - 2; i += 1) { + p0 = points[i]; + p1 = points[i + 1]; + midx = (p0.x + p1.x) / 2; + midy = (p0.y + p1.y) / 2; + context.quadraticCurveTo(p0.x, p0.y, midx, midy); + } + p0 = points[points.length - 2]; + p1 = points[points.length - 1]; + context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); + } + } \ No newline at end of file diff --git a/episode22/index.html b/episode22/index.html index 3723d24..f8d8212 100644 --- a/episode22/index.html +++ b/episode22/index.html @@ -1,23 +1,23 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/episode22/main.js b/episode22/main.js index b53403f..c040ba8 100644 --- a/episode22/main.js +++ b/episode22/main.js @@ -1,22 +1,22 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - fl = 300, - shapePos = { - x: 500, - y: 300, - z: 10000 - }; - - context.translate(width / 2, height / 2); - - var perspective = fl / (fl + shapePos.z); - context.translate(shapePos.x * perspective, shapePos.y * perspective); - context.scale(perspective, perspective); - context.fillRect(-100, -100, 200, 200); - - - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + fl = 300, + shapePos = { + x: 500, + y: 300, + z: 10000 + }; + + context.translate(width / 2, height / 2); + + var perspective = fl / (fl + shapePos.z); + context.translate(shapePos.x * perspective, shapePos.y * perspective); + context.scale(perspective, perspective); + context.fillRect(-100, -100, 200, 200); + + + }; \ No newline at end of file diff --git a/episode22/main2.js b/episode22/main2.js index 61c9d28..3f6ef2e 100644 --- a/episode22/main2.js +++ b/episode22/main2.js @@ -1,60 +1,60 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - fl = 300, - shapes = [], - numShapes = 100; - - for(var i = 0; i < numShapes; i += 1) { - shapes[i] = { - x: utils.randomRange(-1000, 1000), - y: utils.randomRange(-1000, 1000), - z: utils.randomRange(0, 10000), - char: String.fromCharCode(utils.randomRange(65, 91)) - }; - } - - context.translate(width / 2, height / 2); - context.font = "200px Arial"; - - update(); - - function update() { - context.clearRect(-width / 2, -height / 2, width, height); - for(var i = 0; i < numShapes; i += 1) { - var shape = shapes[i], - perspective = fl / (fl + shape.z); - - context.save(); - context.translate(shape.x * perspective, shape.y * perspective); - context.scale(perspective, perspective); - // square: - // context.fillRect(-100, -100, 200, 200); - - // circle: - // context.beginPath(); - // context.arc(0, 0, 100, 0, Math.PI * 2, false); - // context.fill(); - - // letter: - context.fillText(shape.char, -100, -100) - - context.restore(); - - // move away: - // shape.z += 5; - // if(shape.z > 10000) { - // shape.z = 0; - // } - - // move toward: - shape.z -= 5; - if(shape.z < 0) { - shape.z = 10000; - } - } - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + fl = 300, + shapes = [], + numShapes = 100; + + for(var i = 0; i < numShapes; i += 1) { + shapes[i] = { + x: utils.randomRange(-1000, 1000), + y: utils.randomRange(-1000, 1000), + z: utils.randomRange(0, 10000), + char: String.fromCharCode(utils.randomRange(65, 91)) + }; + } + + context.translate(width / 2, height / 2); + context.font = "200px Arial"; + + update(); + + function update() { + context.clearRect(-width / 2, -height / 2, width, height); + for(var i = 0; i < numShapes; i += 1) { + var shape = shapes[i], + perspective = fl / (fl + shape.z); + + context.save(); + context.translate(shape.x * perspective, shape.y * perspective); + context.scale(perspective, perspective); + // square: + // context.fillRect(-100, -100, 200, 200); + + // circle: + // context.beginPath(); + // context.arc(0, 0, 100, 0, Math.PI * 2, false); + // context.fill(); + + // letter: + context.fillText(shape.char, -100, -100) + + context.restore(); + + // move away: + // shape.z += 5; + // if(shape.z > 10000) { + // shape.z = 0; + // } + + // move toward: + shape.z -= 5; + if(shape.z < 0) { + shape.z = 10000; + } + } + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/episode22/particle.js b/episode22/particle.js index b6ef621..948e47a 100644 --- a/episode22/particle.js +++ b/episode22/particle.js @@ -1,138 +1,138 @@ -var particle = { - x: 0, - y: 0, - vx: 0, - vy: 0, - mass: 1, - radius: 0, - bounce: -1, - friction: 1, - gravity: 0, - springs: null, - gravitations: null, - - create: function(x, y, speed, direction, grav) { - var obj = Object.create(this); - obj.x = x; - obj.y = y; - obj.vx = Math.cos(direction) * speed; - obj.vy = Math.sin(direction) * speed; - obj.gravity = grav || 0; - obj.springs = []; - obj.gravitations = []; - return obj; - }, - - addGravitation: function(p) { - this.removeGravitation(p); - this.gravitations.push(p); - }, - - removeGravitation: function(p) { - for(var i = 0; i < this.gravitations.length; i += 1) { - if(p === this.gravitations[i]) { - this.gravitations.splice(i, 1); - return; - } - } - }, - - addSpring: function(point, k, length) { - this.removeSpring(point); - this.springs.push({ - point: point, - k: k, - length: length || 0 - }); - }, - - removeSpring: function(point) { - for(var i = 0; i < this.springs.length; i += 1) { - if(point === this.springs[i].point) { - this.springs.splice(i, 1); - return; - } - } - }, - - getSpeed: function() { - return Math.sqrt(this.vx * this.vx + this.vy * this.vy); - }, - - setSpeed: function(speed) { - var heading = this.getHeading(); - this.vx = Math.cos(heading) * speed; - this.vy = Math.sin(heading) * speed; - }, - - getHeading: function() { - return Math.atan2(this.vy, this.vx); - }, - - setHeading: function(heading) { - var speed = this.getSpeed(); - this.vx = Math.cos(heading) * speed; - this.vy = Math.sin(heading) * speed; - }, - - accelerate: function(ax, ay) { - this.vx += ax; - this.vy += ay; - }, - - update: function() { - this.handleSprings(); - this.handleGravitations(); - this.vx *= this.friction; - this.vy *= this.friction; - this.vy += this.gravity; - this.x += this.vx; - this.y += this.vy; - }, - - handleGravitations: function() { - for(var i = 0; i < this.gravitations.length; i += 1) { - this.gravitateTo(this.gravitations[i]); - } - }, - - handleSprings: function() { - for(var i = 0; i < this.springs.length; i += 1) { - var spring = this.springs[i]; - this.springTo(spring.point, spring.k, spring.length); - } - }, - - angleTo: function(p2) { - return Math.atan2(p2.y - this.y, p2.x - this.x); - }, - - distanceTo: function(p2) { - var dx = p2.x - this.x, - dy = p2.y - this.y; - - return Math.sqrt(dx * dx + dy * dy); - }, - - gravitateTo: function(p2) { - var dx = p2.x - this.x, - dy = p2.y - this.y, - distSQ = dx * dx + dy * dy, - dist = Math.sqrt(distSQ), - force = p2.mass / distSQ, - ax = dx / dist * force, - ay = dy / dist * force; - - this.vx += ax; - this.vy += ay; - }, - - springTo: function(point, k, length) { - var dx = point.x - this.x, - dy = point.y - this.y, - distance = Math.sqrt(dx * dx + dy * dy), - springForce = (distance - length || 0) * k; - this.vx += dx / distance * springForce, - this.vy += dy / distance * springForce; - } +var particle = { + x: 0, + y: 0, + vx: 0, + vy: 0, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + springs: null, + gravitations: null, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.x = x; + obj.y = y; + obj.vx = Math.cos(direction) * speed; + obj.vy = Math.sin(direction) * speed; + obj.gravity = grav || 0; + obj.springs = []; + obj.gravitations = []; + return obj; + }, + + addGravitation: function(p) { + this.removeGravitation(p); + this.gravitations.push(p); + }, + + removeGravitation: function(p) { + for(var i = 0; i < this.gravitations.length; i += 1) { + if(p === this.gravitations[i]) { + this.gravitations.splice(i, 1); + return; + } + } + }, + + addSpring: function(point, k, length) { + this.removeSpring(point); + this.springs.push({ + point: point, + k: k, + length: length || 0 + }); + }, + + removeSpring: function(point) { + for(var i = 0; i < this.springs.length; i += 1) { + if(point === this.springs[i].point) { + this.springs.splice(i, 1); + return; + } + } + }, + + getSpeed: function() { + return Math.sqrt(this.vx * this.vx + this.vy * this.vy); + }, + + setSpeed: function(speed) { + var heading = this.getHeading(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + getHeading: function() { + return Math.atan2(this.vy, this.vx); + }, + + setHeading: function(heading) { + var speed = this.getSpeed(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + accelerate: function(ax, ay) { + this.vx += ax; + this.vy += ay; + }, + + update: function() { + this.handleSprings(); + this.handleGravitations(); + this.vx *= this.friction; + this.vy *= this.friction; + this.vy += this.gravity; + this.x += this.vx; + this.y += this.vy; + }, + + handleGravitations: function() { + for(var i = 0; i < this.gravitations.length; i += 1) { + this.gravitateTo(this.gravitations[i]); + } + }, + + handleSprings: function() { + for(var i = 0; i < this.springs.length; i += 1) { + var spring = this.springs[i]; + this.springTo(spring.point, spring.k, spring.length); + } + }, + + angleTo: function(p2) { + return Math.atan2(p2.y - this.y, p2.x - this.x); + }, + + distanceTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y; + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y, + distSQ = dx * dx + dy * dy, + dist = Math.sqrt(distSQ), + force = p2.mass / distSQ, + ax = dx / dist * force, + ay = dy / dist * force; + + this.vx += ax; + this.vy += ay; + }, + + springTo: function(point, k, length) { + var dx = point.x - this.x, + dy = point.y - this.y, + distance = Math.sqrt(dx * dx + dy * dy), + springForce = (distance - length || 0) * k; + this.vx += dx / distance * springForce, + this.vy += dy / distance * springForce; + } }; \ No newline at end of file diff --git a/episode22/postcards.js b/episode22/postcards.js index cea41ca..08166c8 100644 --- a/episode22/postcards.js +++ b/episode22/postcards.js @@ -1,48 +1,48 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - fl = 300, - cards = [], - numCards = 21; - - for(var i = 0; i < numCards; i += 1) { - var card = { - x: utils.randomRange(-1000, 1000), - y: utils.randomRange(-1000, 1000), - z: utils.randomRange(0, 5000), - img: document.createElement("img") - }; - card.img.src = "postcard" + (i % 7) + ".jpg"; - cards.push(card); - } - - context.translate(width / 2, height / 2); - context.font = "200px Arial"; - - update(); - - function update() { - context.clearRect(-width / 2, -height / 2, width, height); - for(var i = 0; i < numCards; i += 1) { - var card = cards[i], - perspective = fl / (fl + card.z); - - context.save(); - context.translate(card.x * perspective, card.y * perspective); - context.scale(perspective, perspective); - - context.translate(-card.img.width / 2, -card.img.height / 2); - context.drawImage(card.img, 0, 0); - - context.restore(); - - card.z -= 5; - if(card.z < 0) { - card.z = 5000; - } - } - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + fl = 300, + cards = [], + numCards = 21; + + for(var i = 0; i < numCards; i += 1) { + var card = { + x: utils.randomRange(-1000, 1000), + y: utils.randomRange(-1000, 1000), + z: utils.randomRange(0, 5000), + img: document.createElement("img") + }; + card.img.src = "postcard" + (i % 7) + ".jpg"; + cards.push(card); + } + + context.translate(width / 2, height / 2); + context.font = "200px Arial"; + + update(); + + function update() { + context.clearRect(-width / 2, -height / 2, width, height); + for(var i = 0; i < numCards; i += 1) { + var card = cards[i], + perspective = fl / (fl + card.z); + + context.save(); + context.translate(card.x * perspective, card.y * perspective); + context.scale(perspective, perspective); + + context.translate(-card.img.width / 2, -card.img.height / 2); + context.drawImage(card.img, 0, 0); + + context.restore(); + + card.z -= 5; + if(card.z < 0) { + card.z = 5000; + } + } + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/episode22/stars.js b/episode22/stars.js index 3d8b16f..8751810 100644 --- a/episode22/stars.js +++ b/episode22/stars.js @@ -1,20 +1,20 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - context.fillRect(0, 0, width, height); - context.fillStyle = "white"; - - for(var i = 0; i < 800; i += 1) { - context.beginPath(); - context.arc(utils.randomRange(0, width), - utils.randomRange(0, height), - utils.randomRange(0, 1), - 0, Math.PI * 2, false); - context.fill(); - } - - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + context.fillRect(0, 0, width, height); + context.fillStyle = "white"; + + for(var i = 0; i < 800; i += 1) { + context.beginPath(); + context.arc(utils.randomRange(0, width), + utils.randomRange(0, height), + utils.randomRange(0, 1), + 0, Math.PI * 2, false); + context.fill(); + } + + }; \ No newline at end of file diff --git a/episode22/utils.js b/episode22/utils.js index 3c0f824..04715df 100644 --- a/episode22/utils.js +++ b/episode22/utils.js @@ -1,123 +1,123 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - }, - - degreesToRads: function(degrees) { - return degrees / 180 * Math.PI; - }, - - radsToDegrees: function(radians) { - return radians * 180 / Math.PI; - }, - - randomRange: function(min, max) { - return min + Math.random() * (max - min); - }, - - randomInt: function(min, max) { - return Math.floor(min + Math.random() * (max - min + 1)); - }, - - roundToPlaces: function(value, places) { - var mult = Math.pow(10, places); - return Math.round(value * mult) / mult; - }, - - roundNearest: function(value, nearest) { - return Math.round(value / nearest) * nearest; - }, - - quadraticBezier: function(p0, p1, p2, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 2) * p0.x + - (1 - t) * 2 * t * p1.x + - t * t * p2.x; - pFinal.y = Math.pow(1 - t, 2) * p0.y + - (1 - t) * 2 * t * p1.y + - t * t * p2.y; - return pFinal; - }, - - cubicBezier: function(p0, p1, p2, p3, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 3) * p0.x + - Math.pow(1 - t, 2) * 3 * t * p1.x + - (1 - t) * 3 * t * t * p2.x + - t * t * t * p3.x; - pFinal.y = Math.pow(1 - t, 3) * p0.y + - Math.pow(1 - t, 2) * 3 * t * p1.y + - (1 - t) * 3 * t * t * p2.y + - t * t * t * p3.y; - return pFinal; - }, - - multicurve: function(points, context) { - var p0, p1, midx, midy; - - context.moveTo(points[0].x, points[0].y); - - for(var i = 1; i < points.length - 2; i += 1) { - p0 = points[i]; - p1 = points[i + 1]; - midx = (p0.x + p1.x) / 2; - midy = (p0.y + p1.y) / 2; - context.quadraticCurveTo(p0.x, p0.y, midx, midy); - } - p0 = points[points.length - 2]; - p1 = points[points.length - 1]; - context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + }, + + multicurve: function(points, context) { + var p0, p1, midx, midy; + + context.moveTo(points[0].x, points[0].y); + + for(var i = 1; i < points.length - 2; i += 1) { + p0 = points[i]; + p1 = points[i + 1]; + midx = (p0.x + p1.x) / 2; + midy = (p0.y + p1.y) / 2; + context.quadraticCurveTo(p0.x, p0.y, midx, midy); + } + p0 = points[points.length - 2]; + p1 = points[points.length - 1]; + context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); + } + } \ No newline at end of file diff --git a/episode23/final.js b/episode23/final.js index 4544081..f552c04 100644 --- a/episode23/final.js +++ b/episode23/final.js @@ -1,68 +1,68 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - fl = 300, - cards = [], - numCards = 200, - centerZ = 1000, - baseAngle = 0, - rotationSpeed = 0.01; - - - for(var i = 0; i < numCards; i += 1) { - var card = { - angle: utils.randomRange(0, Math.PI * 2), - radius: utils.randomRange(100, 1100), - y: utils.randomRange(2000, -2000) - }; - card.x = Math.cos(card.angle + baseAngle) * card.radius; - card.z = centerZ + Math.sin(card.angle + baseAngle) * card.radius; - cards.push(card); - } - - context.translate(width / 2, height / 2); - context.fillStyle = "white"; - - document.body.addEventListener("mousemove", function(event) { - rotationSpeed = (event.clientX - width / 2) * 0.00005; - ypos = (event.clientY - height / 2) * 2; - }); - - update(); - - function update() { - baseAngle += rotationSpeed; - cards.sort(zsort); - context.clearRect(-width / 2, -height / 2, width, height); - for(var i = 0; i < numCards; i += 1) { - var card = cards[i], - perspective = fl / (fl + card.z); - - context.save(); - context.scale(perspective, perspective); - context.translate(card.x, card.y); - context.globalAlpha = utils.map(card.y, 2000, -2000, 1, 0); - - context.beginPath(); - context.arc(0, 0, 40, 0, Math.PI * 2, false); - context.fill(); - - context.restore(); - - card.x = Math.cos(card.angle + baseAngle) * card.radius; - card.z = centerZ + Math.sin(card.angle + baseAngle) * card.radius; - card.y -= 10; - - if(card.y < -2000) { - card.y = 2000; - } - } - requestAnimationFrame(update); - } - - function zsort(cardA, cardB) { - return cardB.z - cardA.z; - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + fl = 300, + cards = [], + numCards = 200, + centerZ = 1000, + baseAngle = 0, + rotationSpeed = 0.01; + + + for(var i = 0; i < numCards; i += 1) { + var card = { + angle: utils.randomRange(0, Math.PI * 2), + radius: utils.randomRange(100, 1100), + y: utils.randomRange(2000, -2000) + }; + card.x = Math.cos(card.angle + baseAngle) * card.radius; + card.z = centerZ + Math.sin(card.angle + baseAngle) * card.radius; + cards.push(card); + } + + context.translate(width / 2, height / 2); + context.fillStyle = "white"; + + document.body.addEventListener("mousemove", function(event) { + rotationSpeed = (event.clientX - width / 2) * 0.00005; + ypos = (event.clientY - height / 2) * 2; + }); + + update(); + + function update() { + baseAngle += rotationSpeed; + cards.sort(zsort); + context.clearRect(-width / 2, -height / 2, width, height); + for(var i = 0; i < numCards; i += 1) { + var card = cards[i], + perspective = fl / (fl + card.z); + + context.save(); + context.scale(perspective, perspective); + context.translate(card.x, card.y); + context.globalAlpha = utils.map(card.y, 2000, -2000, 1, 0); + + context.beginPath(); + context.arc(0, 0, 40, 0, Math.PI * 2, false); + context.fill(); + + context.restore(); + + card.x = Math.cos(card.angle + baseAngle) * card.radius; + card.z = centerZ + Math.sin(card.angle + baseAngle) * card.radius; + card.y -= 10; + + if(card.y < -2000) { + card.y = 2000; + } + } + requestAnimationFrame(update); + } + + function zsort(cardA, cardB) { + return cardB.z - cardA.z; + } }; \ No newline at end of file diff --git a/episode23/index.html b/episode23/index.html index 1fdfdf9..71cd261 100644 --- a/episode23/index.html +++ b/episode23/index.html @@ -1,24 +1,24 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/episode23/particle.js b/episode23/particle.js index b6ef621..948e47a 100644 --- a/episode23/particle.js +++ b/episode23/particle.js @@ -1,138 +1,138 @@ -var particle = { - x: 0, - y: 0, - vx: 0, - vy: 0, - mass: 1, - radius: 0, - bounce: -1, - friction: 1, - gravity: 0, - springs: null, - gravitations: null, - - create: function(x, y, speed, direction, grav) { - var obj = Object.create(this); - obj.x = x; - obj.y = y; - obj.vx = Math.cos(direction) * speed; - obj.vy = Math.sin(direction) * speed; - obj.gravity = grav || 0; - obj.springs = []; - obj.gravitations = []; - return obj; - }, - - addGravitation: function(p) { - this.removeGravitation(p); - this.gravitations.push(p); - }, - - removeGravitation: function(p) { - for(var i = 0; i < this.gravitations.length; i += 1) { - if(p === this.gravitations[i]) { - this.gravitations.splice(i, 1); - return; - } - } - }, - - addSpring: function(point, k, length) { - this.removeSpring(point); - this.springs.push({ - point: point, - k: k, - length: length || 0 - }); - }, - - removeSpring: function(point) { - for(var i = 0; i < this.springs.length; i += 1) { - if(point === this.springs[i].point) { - this.springs.splice(i, 1); - return; - } - } - }, - - getSpeed: function() { - return Math.sqrt(this.vx * this.vx + this.vy * this.vy); - }, - - setSpeed: function(speed) { - var heading = this.getHeading(); - this.vx = Math.cos(heading) * speed; - this.vy = Math.sin(heading) * speed; - }, - - getHeading: function() { - return Math.atan2(this.vy, this.vx); - }, - - setHeading: function(heading) { - var speed = this.getSpeed(); - this.vx = Math.cos(heading) * speed; - this.vy = Math.sin(heading) * speed; - }, - - accelerate: function(ax, ay) { - this.vx += ax; - this.vy += ay; - }, - - update: function() { - this.handleSprings(); - this.handleGravitations(); - this.vx *= this.friction; - this.vy *= this.friction; - this.vy += this.gravity; - this.x += this.vx; - this.y += this.vy; - }, - - handleGravitations: function() { - for(var i = 0; i < this.gravitations.length; i += 1) { - this.gravitateTo(this.gravitations[i]); - } - }, - - handleSprings: function() { - for(var i = 0; i < this.springs.length; i += 1) { - var spring = this.springs[i]; - this.springTo(spring.point, spring.k, spring.length); - } - }, - - angleTo: function(p2) { - return Math.atan2(p2.y - this.y, p2.x - this.x); - }, - - distanceTo: function(p2) { - var dx = p2.x - this.x, - dy = p2.y - this.y; - - return Math.sqrt(dx * dx + dy * dy); - }, - - gravitateTo: function(p2) { - var dx = p2.x - this.x, - dy = p2.y - this.y, - distSQ = dx * dx + dy * dy, - dist = Math.sqrt(distSQ), - force = p2.mass / distSQ, - ax = dx / dist * force, - ay = dy / dist * force; - - this.vx += ax; - this.vy += ay; - }, - - springTo: function(point, k, length) { - var dx = point.x - this.x, - dy = point.y - this.y, - distance = Math.sqrt(dx * dx + dy * dy), - springForce = (distance - length || 0) * k; - this.vx += dx / distance * springForce, - this.vy += dy / distance * springForce; - } +var particle = { + x: 0, + y: 0, + vx: 0, + vy: 0, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + springs: null, + gravitations: null, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.x = x; + obj.y = y; + obj.vx = Math.cos(direction) * speed; + obj.vy = Math.sin(direction) * speed; + obj.gravity = grav || 0; + obj.springs = []; + obj.gravitations = []; + return obj; + }, + + addGravitation: function(p) { + this.removeGravitation(p); + this.gravitations.push(p); + }, + + removeGravitation: function(p) { + for(var i = 0; i < this.gravitations.length; i += 1) { + if(p === this.gravitations[i]) { + this.gravitations.splice(i, 1); + return; + } + } + }, + + addSpring: function(point, k, length) { + this.removeSpring(point); + this.springs.push({ + point: point, + k: k, + length: length || 0 + }); + }, + + removeSpring: function(point) { + for(var i = 0; i < this.springs.length; i += 1) { + if(point === this.springs[i].point) { + this.springs.splice(i, 1); + return; + } + } + }, + + getSpeed: function() { + return Math.sqrt(this.vx * this.vx + this.vy * this.vy); + }, + + setSpeed: function(speed) { + var heading = this.getHeading(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + getHeading: function() { + return Math.atan2(this.vy, this.vx); + }, + + setHeading: function(heading) { + var speed = this.getSpeed(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + accelerate: function(ax, ay) { + this.vx += ax; + this.vy += ay; + }, + + update: function() { + this.handleSprings(); + this.handleGravitations(); + this.vx *= this.friction; + this.vy *= this.friction; + this.vy += this.gravity; + this.x += this.vx; + this.y += this.vy; + }, + + handleGravitations: function() { + for(var i = 0; i < this.gravitations.length; i += 1) { + this.gravitateTo(this.gravitations[i]); + } + }, + + handleSprings: function() { + for(var i = 0; i < this.springs.length; i += 1) { + var spring = this.springs[i]; + this.springTo(spring.point, spring.k, spring.length); + } + }, + + angleTo: function(p2) { + return Math.atan2(p2.y - this.y, p2.x - this.x); + }, + + distanceTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y; + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y, + distSQ = dx * dx + dy * dy, + dist = Math.sqrt(distSQ), + force = p2.mass / distSQ, + ax = dx / dist * force, + ay = dy / dist * force; + + this.vx += ax; + this.vy += ay; + }, + + springTo: function(point, k, length) { + var dx = point.x - this.x, + dy = point.y - this.y, + distance = Math.sqrt(dx * dx + dy * dy), + springForce = (distance - length || 0) * k; + this.vx += dx / distance * springForce, + this.vy += dy / distance * springForce; + } }; \ No newline at end of file diff --git a/episode23/postcards.js b/episode23/postcards.js index 827465d..9285644 100644 --- a/episode23/postcards.js +++ b/episode23/postcards.js @@ -1,61 +1,61 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - fl = 300, - cards = [], - numCards = 7, - centerZ = 1000, - radius = 1000, - baseAngle = 0, - rotationSpeed = 0.01; - - for(var i = 0; i < numCards; i += 1) { - var card = { - y: 0, - angle: Math.PI * 2 / numCards * i, - img: document.createElement("img") - }; - card.img.src = "postcard" + i + ".jpg"; - card.x = Math.cos(card.angle + baseAngle) * radius; - card.z = centerZ + Math.sin(card.angle + baseAngle) * radius; - cards.push(card); - } - - context.translate(width / 2, height / 2); - context.font = "200px Arial"; - - document.body.addEventListener("mousemove", function(event) { - rotationSpeed = (event.clientX - width / 2) * 0.00005; - }); - - update(); - - function update() { - baseAngle += rotationSpeed; - cards.sort(zsort); - context.clearRect(-width / 2, -height / 2, width, height); - for(var i = 0; i < numCards; i += 1) { - var card = cards[i], - perspective = fl / (fl + card.z); - - context.save(); - context.scale(perspective, perspective); - context.translate(card.x, card.y); - - context.translate(-card.img.width / 2, -card.img.height / 2); - context.drawImage(card.img, 0, 0); - - context.restore(); - - card.x = Math.cos(card.angle + baseAngle) * radius; - card.z = centerZ + Math.sin(card.angle + baseAngle) * radius; - } - requestAnimationFrame(update); - } - - function zsort(cardA, cardB) { - return cardB.z - cardA.z; - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + fl = 300, + cards = [], + numCards = 7, + centerZ = 1000, + radius = 1000, + baseAngle = 0, + rotationSpeed = 0.01; + + for(var i = 0; i < numCards; i += 1) { + var card = { + y: 0, + angle: Math.PI * 2 / numCards * i, + img: document.createElement("img") + }; + card.img.src = "postcard" + i + ".jpg"; + card.x = Math.cos(card.angle + baseAngle) * radius; + card.z = centerZ + Math.sin(card.angle + baseAngle) * radius; + cards.push(card); + } + + context.translate(width / 2, height / 2); + context.font = "200px Arial"; + + document.body.addEventListener("mousemove", function(event) { + rotationSpeed = (event.clientX - width / 2) * 0.00005; + }); + + update(); + + function update() { + baseAngle += rotationSpeed; + cards.sort(zsort); + context.clearRect(-width / 2, -height / 2, width, height); + for(var i = 0; i < numCards; i += 1) { + var card = cards[i], + perspective = fl / (fl + card.z); + + context.save(); + context.scale(perspective, perspective); + context.translate(card.x, card.y); + + context.translate(-card.img.width / 2, -card.img.height / 2); + context.drawImage(card.img, 0, 0); + + context.restore(); + + card.x = Math.cos(card.angle + baseAngle) * radius; + card.z = centerZ + Math.sin(card.angle + baseAngle) * radius; + } + requestAnimationFrame(update); + } + + function zsort(cardA, cardB) { + return cardB.z - cardA.z; + } }; \ No newline at end of file diff --git a/episode23/spiral.js b/episode23/spiral.js index acd9ebe..1800bd2 100644 --- a/episode23/spiral.js +++ b/episode23/spiral.js @@ -1,63 +1,63 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - fl = 300, - cards = [], - numCards = 200, - centerZ = 2000, - radius = 1000, - baseAngle = 0, - rotationSpeed = 0.01; - - - for(var i = 0; i < numCards; i += 1) { - var card = { - angle: 0.2 * i, - y: 2000 - 4000 / numCards * i, - img: document.createElement("img") - }; - card.x = Math.cos(card.angle + baseAngle) * radius; - card.z = centerZ + Math.sin(card.angle + baseAngle) * radius; - cards.push(card); - } - - context.translate(width / 2, height / 2); - context.font = "200px Arial"; - - document.body.addEventListener("mousemove", function(event) { - rotationSpeed = (event.clientX - width / 2) * 0.00005; - ypos = (event.clientY - height / 2) * 2; - }); - - update(); - - function update() { - baseAngle += rotationSpeed; - cards.sort(zsort); - context.clearRect(-width / 2, -height / 2, width, height); - for(var i = 0; i < numCards; i += 1) { - var card = cards[i], - perspective = fl / (fl + card.z); - - context.save(); - context.scale(perspective, perspective); - context.translate(card.x, card.y); - - context.beginPath(); - context.arc(0, 0, 40, 0, Math.PI * 2, false); - context.fill(); - - context.restore(); - - card.x = Math.cos(card.angle + baseAngle) * radius; - card.z = centerZ + Math.sin(card.angle + baseAngle) * radius; - } - requestAnimationFrame(update); - } - - function zsort(cardA, cardB) { - return cardB.z - cardA.z; - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + fl = 300, + cards = [], + numCards = 200, + centerZ = 2000, + radius = 1000, + baseAngle = 0, + rotationSpeed = 0.01; + + + for(var i = 0; i < numCards; i += 1) { + var card = { + angle: 0.2 * i, + y: 2000 - 4000 / numCards * i, + img: document.createElement("img") + }; + card.x = Math.cos(card.angle + baseAngle) * radius; + card.z = centerZ + Math.sin(card.angle + baseAngle) * radius; + cards.push(card); + } + + context.translate(width / 2, height / 2); + context.font = "200px Arial"; + + document.body.addEventListener("mousemove", function(event) { + rotationSpeed = (event.clientX - width / 2) * 0.00005; + ypos = (event.clientY - height / 2) * 2; + }); + + update(); + + function update() { + baseAngle += rotationSpeed; + cards.sort(zsort); + context.clearRect(-width / 2, -height / 2, width, height); + for(var i = 0; i < numCards; i += 1) { + var card = cards[i], + perspective = fl / (fl + card.z); + + context.save(); + context.scale(perspective, perspective); + context.translate(card.x, card.y); + + context.beginPath(); + context.arc(0, 0, 40, 0, Math.PI * 2, false); + context.fill(); + + context.restore(); + + card.x = Math.cos(card.angle + baseAngle) * radius; + card.z = centerZ + Math.sin(card.angle + baseAngle) * radius; + } + requestAnimationFrame(update); + } + + function zsort(cardA, cardB) { + return cardB.z - cardA.z; + } }; \ No newline at end of file diff --git a/episode23/stars.js b/episode23/stars.js index 0de703a..89b76f5 100644 --- a/episode23/stars.js +++ b/episode23/stars.js @@ -1,64 +1,64 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - fl = 300, - cards = [], - numCards = 20, - centerZ = 1000, - ypos = 0, - radius = 1000, - baseAngle = 0, - rotationSpeed = 0.01, - star = document.createElement("img"); - - star.src = "star.png" - - for(var i = 0; i < numCards; i += 1) { - var card = { - angle: Math.PI * 2 / numCards * i, - img: document.createElement("img") - }; - card.x = Math.cos(card.angle + baseAngle) * radius; - card.z = centerZ + Math.sin(card.angle + baseAngle) * radius; - cards.push(card); - } - - context.translate(width / 2, height / 2); - context.font = "200px Arial"; - - document.body.addEventListener("mousemove", function(event) { - rotationSpeed = (event.clientX - width / 2) * 0.00005; - ypos = (event.clientY - height / 2) * 2; - }); - - update(); - - function update() { - baseAngle += rotationSpeed; - cards.sort(zsort); - context.clearRect(-width / 2, -height / 2, width, height); - for(var i = 0; i < numCards; i += 1) { - var card = cards[i], - perspective = fl / (fl + card.z); - - context.save(); - context.scale(perspective, perspective); - context.translate(card.x, ypos); - - context.translate(-card.img.width / 2, -card.img.height / 2); - context.drawImage(star, 0, 0); - - context.restore(); - - card.x = Math.cos(card.angle + baseAngle) * radius; - card.z = centerZ + Math.sin(card.angle + baseAngle) * radius; - } - requestAnimationFrame(update); - } - - function zsort(cardA, cardB) { - return cardB.z - cardA.z; - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + fl = 300, + cards = [], + numCards = 20, + centerZ = 1000, + ypos = 0, + radius = 1000, + baseAngle = 0, + rotationSpeed = 0.01, + star = document.createElement("img"); + + star.src = "star.png" + + for(var i = 0; i < numCards; i += 1) { + var card = { + angle: Math.PI * 2 / numCards * i, + img: document.createElement("img") + }; + card.x = Math.cos(card.angle + baseAngle) * radius; + card.z = centerZ + Math.sin(card.angle + baseAngle) * radius; + cards.push(card); + } + + context.translate(width / 2, height / 2); + context.font = "200px Arial"; + + document.body.addEventListener("mousemove", function(event) { + rotationSpeed = (event.clientX - width / 2) * 0.00005; + ypos = (event.clientY - height / 2) * 2; + }); + + update(); + + function update() { + baseAngle += rotationSpeed; + cards.sort(zsort); + context.clearRect(-width / 2, -height / 2, width, height); + for(var i = 0; i < numCards; i += 1) { + var card = cards[i], + perspective = fl / (fl + card.z); + + context.save(); + context.scale(perspective, perspective); + context.translate(card.x, ypos); + + context.translate(-card.img.width / 2, -card.img.height / 2); + context.drawImage(star, 0, 0); + + context.restore(); + + card.x = Math.cos(card.angle + baseAngle) * radius; + card.z = centerZ + Math.sin(card.angle + baseAngle) * radius; + } + requestAnimationFrame(update); + } + + function zsort(cardA, cardB) { + return cardB.z - cardA.z; + } }; \ No newline at end of file diff --git a/episode23/utils.js b/episode23/utils.js index 3c0f824..04715df 100644 --- a/episode23/utils.js +++ b/episode23/utils.js @@ -1,123 +1,123 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - }, - - degreesToRads: function(degrees) { - return degrees / 180 * Math.PI; - }, - - radsToDegrees: function(radians) { - return radians * 180 / Math.PI; - }, - - randomRange: function(min, max) { - return min + Math.random() * (max - min); - }, - - randomInt: function(min, max) { - return Math.floor(min + Math.random() * (max - min + 1)); - }, - - roundToPlaces: function(value, places) { - var mult = Math.pow(10, places); - return Math.round(value * mult) / mult; - }, - - roundNearest: function(value, nearest) { - return Math.round(value / nearest) * nearest; - }, - - quadraticBezier: function(p0, p1, p2, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 2) * p0.x + - (1 - t) * 2 * t * p1.x + - t * t * p2.x; - pFinal.y = Math.pow(1 - t, 2) * p0.y + - (1 - t) * 2 * t * p1.y + - t * t * p2.y; - return pFinal; - }, - - cubicBezier: function(p0, p1, p2, p3, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 3) * p0.x + - Math.pow(1 - t, 2) * 3 * t * p1.x + - (1 - t) * 3 * t * t * p2.x + - t * t * t * p3.x; - pFinal.y = Math.pow(1 - t, 3) * p0.y + - Math.pow(1 - t, 2) * 3 * t * p1.y + - (1 - t) * 3 * t * t * p2.y + - t * t * t * p3.y; - return pFinal; - }, - - multicurve: function(points, context) { - var p0, p1, midx, midy; - - context.moveTo(points[0].x, points[0].y); - - for(var i = 1; i < points.length - 2; i += 1) { - p0 = points[i]; - p1 = points[i + 1]; - midx = (p0.x + p1.x) / 2; - midy = (p0.y + p1.y) / 2; - context.quadraticCurveTo(p0.x, p0.y, midx, midy); - } - p0 = points[points.length - 2]; - p1 = points[points.length - 1]; - context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + }, + + multicurve: function(points, context) { + var p0, p1, midx, midy; + + context.moveTo(points[0].x, points[0].y); + + for(var i = 1; i < points.length - 2; i += 1) { + p0 = points[i]; + p1 = points[i + 1]; + midx = (p0.x + p1.x) / 2; + midy = (p0.y + p1.y) / 2; + context.quadraticCurveTo(p0.x, p0.y, midx, midy); + } + p0 = points[points.length - 2]; + p1 = points[points.length - 1]; + context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); + } + } \ No newline at end of file diff --git a/episode24/index.html b/episode24/index.html index e9da3d3..d9672be 100644 --- a/episode24/index.html +++ b/episode24/index.html @@ -1,24 +1,24 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/episode24/particle.js b/episode24/particle.js index b6ef621..948e47a 100644 --- a/episode24/particle.js +++ b/episode24/particle.js @@ -1,138 +1,138 @@ -var particle = { - x: 0, - y: 0, - vx: 0, - vy: 0, - mass: 1, - radius: 0, - bounce: -1, - friction: 1, - gravity: 0, - springs: null, - gravitations: null, - - create: function(x, y, speed, direction, grav) { - var obj = Object.create(this); - obj.x = x; - obj.y = y; - obj.vx = Math.cos(direction) * speed; - obj.vy = Math.sin(direction) * speed; - obj.gravity = grav || 0; - obj.springs = []; - obj.gravitations = []; - return obj; - }, - - addGravitation: function(p) { - this.removeGravitation(p); - this.gravitations.push(p); - }, - - removeGravitation: function(p) { - for(var i = 0; i < this.gravitations.length; i += 1) { - if(p === this.gravitations[i]) { - this.gravitations.splice(i, 1); - return; - } - } - }, - - addSpring: function(point, k, length) { - this.removeSpring(point); - this.springs.push({ - point: point, - k: k, - length: length || 0 - }); - }, - - removeSpring: function(point) { - for(var i = 0; i < this.springs.length; i += 1) { - if(point === this.springs[i].point) { - this.springs.splice(i, 1); - return; - } - } - }, - - getSpeed: function() { - return Math.sqrt(this.vx * this.vx + this.vy * this.vy); - }, - - setSpeed: function(speed) { - var heading = this.getHeading(); - this.vx = Math.cos(heading) * speed; - this.vy = Math.sin(heading) * speed; - }, - - getHeading: function() { - return Math.atan2(this.vy, this.vx); - }, - - setHeading: function(heading) { - var speed = this.getSpeed(); - this.vx = Math.cos(heading) * speed; - this.vy = Math.sin(heading) * speed; - }, - - accelerate: function(ax, ay) { - this.vx += ax; - this.vy += ay; - }, - - update: function() { - this.handleSprings(); - this.handleGravitations(); - this.vx *= this.friction; - this.vy *= this.friction; - this.vy += this.gravity; - this.x += this.vx; - this.y += this.vy; - }, - - handleGravitations: function() { - for(var i = 0; i < this.gravitations.length; i += 1) { - this.gravitateTo(this.gravitations[i]); - } - }, - - handleSprings: function() { - for(var i = 0; i < this.springs.length; i += 1) { - var spring = this.springs[i]; - this.springTo(spring.point, spring.k, spring.length); - } - }, - - angleTo: function(p2) { - return Math.atan2(p2.y - this.y, p2.x - this.x); - }, - - distanceTo: function(p2) { - var dx = p2.x - this.x, - dy = p2.y - this.y; - - return Math.sqrt(dx * dx + dy * dy); - }, - - gravitateTo: function(p2) { - var dx = p2.x - this.x, - dy = p2.y - this.y, - distSQ = dx * dx + dy * dy, - dist = Math.sqrt(distSQ), - force = p2.mass / distSQ, - ax = dx / dist * force, - ay = dy / dist * force; - - this.vx += ax; - this.vy += ay; - }, - - springTo: function(point, k, length) { - var dx = point.x - this.x, - dy = point.y - this.y, - distance = Math.sqrt(dx * dx + dy * dy), - springForce = (distance - length || 0) * k; - this.vx += dx / distance * springForce, - this.vy += dy / distance * springForce; - } +var particle = { + x: 0, + y: 0, + vx: 0, + vy: 0, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + springs: null, + gravitations: null, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.x = x; + obj.y = y; + obj.vx = Math.cos(direction) * speed; + obj.vy = Math.sin(direction) * speed; + obj.gravity = grav || 0; + obj.springs = []; + obj.gravitations = []; + return obj; + }, + + addGravitation: function(p) { + this.removeGravitation(p); + this.gravitations.push(p); + }, + + removeGravitation: function(p) { + for(var i = 0; i < this.gravitations.length; i += 1) { + if(p === this.gravitations[i]) { + this.gravitations.splice(i, 1); + return; + } + } + }, + + addSpring: function(point, k, length) { + this.removeSpring(point); + this.springs.push({ + point: point, + k: k, + length: length || 0 + }); + }, + + removeSpring: function(point) { + for(var i = 0; i < this.springs.length; i += 1) { + if(point === this.springs[i].point) { + this.springs.splice(i, 1); + return; + } + } + }, + + getSpeed: function() { + return Math.sqrt(this.vx * this.vx + this.vy * this.vy); + }, + + setSpeed: function(speed) { + var heading = this.getHeading(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + getHeading: function() { + return Math.atan2(this.vy, this.vx); + }, + + setHeading: function(heading) { + var speed = this.getSpeed(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + accelerate: function(ax, ay) { + this.vx += ax; + this.vy += ay; + }, + + update: function() { + this.handleSprings(); + this.handleGravitations(); + this.vx *= this.friction; + this.vy *= this.friction; + this.vy += this.gravity; + this.x += this.vx; + this.y += this.vy; + }, + + handleGravitations: function() { + for(var i = 0; i < this.gravitations.length; i += 1) { + this.gravitateTo(this.gravitations[i]); + } + }, + + handleSprings: function() { + for(var i = 0; i < this.springs.length; i += 1) { + var spring = this.springs[i]; + this.springTo(spring.point, spring.k, spring.length); + } + }, + + angleTo: function(p2) { + return Math.atan2(p2.y - this.y, p2.x - this.x); + }, + + distanceTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y; + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y, + distSQ = dx * dx + dy * dy, + dist = Math.sqrt(distSQ), + force = p2.mass / distSQ, + ax = dx / dist * force, + ay = dy / dist * force; + + this.vx += ax; + this.vy += ay; + }, + + springTo: function(point, k, length) { + var dx = point.x - this.x, + dy = point.y - this.y, + distance = Math.sqrt(dx * dx + dy * dy), + springForce = (distance - length || 0) * k; + this.vx += dx / distance * springForce, + this.vy += dy / distance * springForce; + } }; \ No newline at end of file diff --git a/episode24/spiral.js b/episode24/spiral.js index cc64d83..d602b29 100644 --- a/episode24/spiral.js +++ b/episode24/spiral.js @@ -1,63 +1,63 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - fl = 300, - points = [], - numPoints = 200, - centerZ = 2000, - radius = 1000, - baseAngle = 0, - rotationSpeed = 0.01; - - - for(var i = 0; i < numPoints; i += 1) { - var point = { - angle: 0.2 * i, - y: 2000 - 4000 / numPoints * i + Math.random() * 500 - }; - point.x = Math.cos(point.angle + baseAngle) * radius; - point.z = centerZ + Math.sin(point.angle + baseAngle) * radius; - points.push(point); - } - - context.translate(width / 2, height / 2); - - document.body.addEventListener("mousemove", function(event) { - rotationSpeed = (event.clientX - width / 2) * 0.00005; - ypos = (event.clientY - height / 2) * 2; - }); - - update(); - - function update() { - baseAngle += rotationSpeed; - context.clearRect(-width / 2, -height / 2, width, height); - - context.beginPath(); - for(var i = 0; i < numPoints; i += 1) { - var point = points[i], - perspective = fl / (fl + point.z); - - context.save(); - context.scale(perspective, perspective); - context.translate(point.x, point.y); - - if(i == 0) { - context.moveTo(0, 0); - } - else { - context.lineTo(0, 0); - } - - context.restore(); - - point.x = Math.cos(point.angle + baseAngle) * radius; - point.z = centerZ + Math.sin(point.angle + baseAngle) * radius; - } - context.stroke(); - requestAnimationFrame(update); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + fl = 300, + points = [], + numPoints = 200, + centerZ = 2000, + radius = 1000, + baseAngle = 0, + rotationSpeed = 0.01; + + + for(var i = 0; i < numPoints; i += 1) { + var point = { + angle: 0.2 * i, + y: 2000 - 4000 / numPoints * i + Math.random() * 500 + }; + point.x = Math.cos(point.angle + baseAngle) * radius; + point.z = centerZ + Math.sin(point.angle + baseAngle) * radius; + points.push(point); + } + + context.translate(width / 2, height / 2); + + document.body.addEventListener("mousemove", function(event) { + rotationSpeed = (event.clientX - width / 2) * 0.00005; + ypos = (event.clientY - height / 2) * 2; + }); + + update(); + + function update() { + baseAngle += rotationSpeed; + context.clearRect(-width / 2, -height / 2, width, height); + + context.beginPath(); + for(var i = 0; i < numPoints; i += 1) { + var point = points[i], + perspective = fl / (fl + point.z); + + context.save(); + context.scale(perspective, perspective); + context.translate(point.x, point.y); + + if(i == 0) { + context.moveTo(0, 0); + } + else { + context.lineTo(0, 0); + } + + context.restore(); + + point.x = Math.cos(point.angle + baseAngle) * radius; + point.z = centerZ + Math.sin(point.angle + baseAngle) * radius; + } + context.stroke(); + requestAnimationFrame(update); + } + }; \ No newline at end of file diff --git a/episode24/utils.js b/episode24/utils.js index 3c0f824..04715df 100644 --- a/episode24/utils.js +++ b/episode24/utils.js @@ -1,123 +1,123 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - }, - - degreesToRads: function(degrees) { - return degrees / 180 * Math.PI; - }, - - radsToDegrees: function(radians) { - return radians * 180 / Math.PI; - }, - - randomRange: function(min, max) { - return min + Math.random() * (max - min); - }, - - randomInt: function(min, max) { - return Math.floor(min + Math.random() * (max - min + 1)); - }, - - roundToPlaces: function(value, places) { - var mult = Math.pow(10, places); - return Math.round(value * mult) / mult; - }, - - roundNearest: function(value, nearest) { - return Math.round(value / nearest) * nearest; - }, - - quadraticBezier: function(p0, p1, p2, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 2) * p0.x + - (1 - t) * 2 * t * p1.x + - t * t * p2.x; - pFinal.y = Math.pow(1 - t, 2) * p0.y + - (1 - t) * 2 * t * p1.y + - t * t * p2.y; - return pFinal; - }, - - cubicBezier: function(p0, p1, p2, p3, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 3) * p0.x + - Math.pow(1 - t, 2) * 3 * t * p1.x + - (1 - t) * 3 * t * t * p2.x + - t * t * t * p3.x; - pFinal.y = Math.pow(1 - t, 3) * p0.y + - Math.pow(1 - t, 2) * 3 * t * p1.y + - (1 - t) * 3 * t * t * p2.y + - t * t * t * p3.y; - return pFinal; - }, - - multicurve: function(points, context) { - var p0, p1, midx, midy; - - context.moveTo(points[0].x, points[0].y); - - for(var i = 1; i < points.length - 2; i += 1) { - p0 = points[i]; - p1 = points[i + 1]; - midx = (p0.x + p1.x) / 2; - midy = (p0.y + p1.y) / 2; - context.quadraticCurveTo(p0.x, p0.y, midx, midy); - } - p0 = points[points.length - 2]; - p1 = points[points.length - 1]; - context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + }, + + multicurve: function(points, context) { + var p0, p1, midx, midy; + + context.moveTo(points[0].x, points[0].y); + + for(var i = 1; i < points.length - 2; i += 1) { + p0 = points[i]; + p1 = points[i + 1]; + midx = (p0.x + p1.x) / 2; + midy = (p0.y + p1.y) / 2; + context.quadraticCurveTo(p0.x, p0.y, midx, midy); + } + p0 = points[points.length - 2]; + p1 = points[points.length - 1]; + context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); + } + } \ No newline at end of file diff --git a/episode25/index.html b/episode25/index.html index cee28ae..738796d 100644 --- a/episode25/index.html +++ b/episode25/index.html @@ -1,20 +1,20 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/episode25/main.js b/episode25/main.js index fc42656..3b5ff2a 100644 --- a/episode25/main.js +++ b/episode25/main.js @@ -1,97 +1,97 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight - fl = 300, - points = [], - needsUpdate = true; - - context.translate(width / 2, height / 2); - - points[0] = { x: -500, y: -500, z: 1000 }; - points[1] = { x: 500, y: -500, z: 1000 }; - points[2] = { x: 500, y: -500, z: 500 }; - points[3] = { x: -500, y: -500, z: 500 }; - points[4] = { x: -500, y: 500, z: 1000 }; - points[5] = { x: 500, y: 500, z: 1000 }; - points[6] = { x: 500, y: 500, z: 500 }; - points[7] = { x: -500, y: 500, z: 500 }; - - function project() { - for(var i = 0; i < points.length; i++) { - var p = points[i], - scale = fl / (fl + p.z); - - p.sx = p.x * scale; - p.sy = p.y * scale; - } - } - - function drawLine() { - var p = points[arguments[0]]; - context.moveTo(p.sx, p.sy); - - for(var i = 1; i < arguments.length; i++) { - p = points[arguments[i]]; - context.lineTo(p.sx, p.sy); - } - } - - function translateModel(x, y, z) { - for(var i = 0; i < points.length; i++) { - points[i].x += x; - points[i].y += y; - points[i].z += z; - } - needsUpdate = true; - } - - document.body.addEventListener("keydown", function(event) { - switch(event.keyCode) { - case 37: // left - translateModel(-20, 0, 0); - break; - case 39: // right - translateModel(20, 0, 0); - break; - case 38: // up - if(event.shiftKey) { - translateModel(0, 0, 20); - } - else { - translateModel(0, -20, 0); - } - break; - case 40: // down - if(event.shiftKey) { - translateModel(0, 0, -20); - } - else { - translateModel(0, 20, 0); - } - break; - } - }); - - update(); - - function update() { - if(needsUpdate) { - context.clearRect(-width / 2, -height / 2, width, height); - project(); - - context.beginPath(); - drawLine(0, 1, 2, 3, 0); - drawLine(4, 5, 6, 7, 4); - drawLine(0, 4); - drawLine(1, 5); - drawLine(2, 6); - drawLine(3, 7); - context.stroke(); - needsUpdate = false; - } - requestAnimationFrame(update); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight + fl = 300, + points = [], + needsUpdate = true; + + context.translate(width / 2, height / 2); + + points[0] = { x: -500, y: -500, z: 1000 }; + points[1] = { x: 500, y: -500, z: 1000 }; + points[2] = { x: 500, y: -500, z: 500 }; + points[3] = { x: -500, y: -500, z: 500 }; + points[4] = { x: -500, y: 500, z: 1000 }; + points[5] = { x: 500, y: 500, z: 1000 }; + points[6] = { x: 500, y: 500, z: 500 }; + points[7] = { x: -500, y: 500, z: 500 }; + + function project() { + for(var i = 0; i < points.length; i++) { + var p = points[i], + scale = fl / (fl + p.z); + + p.sx = p.x * scale; + p.sy = p.y * scale; + } + } + + function drawLine() { + var p = points[arguments[0]]; + context.moveTo(p.sx, p.sy); + + for(var i = 1; i < arguments.length; i++) { + p = points[arguments[i]]; + context.lineTo(p.sx, p.sy); + } + } + + function translateModel(x, y, z) { + for(var i = 0; i < points.length; i++) { + points[i].x += x; + points[i].y += y; + points[i].z += z; + } + needsUpdate = true; + } + + document.body.addEventListener("keydown", function(event) { + switch(event.keyCode) { + case 37: // left + translateModel(-20, 0, 0); + break; + case 39: // right + translateModel(20, 0, 0); + break; + case 38: // up + if(event.shiftKey) { + translateModel(0, 0, 20); + } + else { + translateModel(0, -20, 0); + } + break; + case 40: // down + if(event.shiftKey) { + translateModel(0, 0, -20); + } + else { + translateModel(0, 20, 0); + } + break; + } + }); + + update(); + + function update() { + if(needsUpdate) { + context.clearRect(-width / 2, -height / 2, width, height); + project(); + + context.beginPath(); + drawLine(0, 1, 2, 3, 0); + drawLine(4, 5, 6, 7, 4); + drawLine(0, 4); + drawLine(1, 5); + drawLine(2, 6); + drawLine(3, 7); + context.stroke(); + needsUpdate = false; + } + requestAnimationFrame(update); + } + }; \ No newline at end of file diff --git a/episode26/2d.js b/episode26/2d.js index 4992c05..b7a5368 100644 --- a/episode26/2d.js +++ b/episode26/2d.js @@ -1,33 +1,33 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - point = { - x: 300, - y: 200 - }, - delta = 0.05; - - context.translate(width / 2, height / 2); - - update(); - - function update() { - context.clearRect(-width / 2, -height / 2, width, height); - - context.beginPath(); - context.arc(point.x, point.y, 20, 0, Math.PI * 2, false); - context.fill(); - - var cos = Math.cos(delta), - sin = Math.sin(delta), - x = point.x * cos - point.y * sin, - y = point.y * cos + point.x * sin; - - point.x = x; - point.y = y; - - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + point = { + x: 300, + y: 200 + }, + delta = 0.05; + + context.translate(width / 2, height / 2); + + update(); + + function update() { + context.clearRect(-width / 2, -height / 2, width, height); + + context.beginPath(); + context.arc(point.x, point.y, 20, 0, Math.PI * 2, false); + context.fill(); + + var cos = Math.cos(delta), + sin = Math.sin(delta), + x = point.x * cos - point.y * sin, + y = point.y * cos + point.x * sin; + + point.x = x; + point.y = y; + + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/episode26/index.html b/episode26/index.html index 719fb94..dfde07f 100644 --- a/episode26/index.html +++ b/episode26/index.html @@ -1,20 +1,20 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/episode26/main.js b/episode26/main.js index 61da667..baae68b 100644 --- a/episode26/main.js +++ b/episode26/main.js @@ -1,156 +1,156 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight - fl = 300, - points = [], - needsUpdate = true, - centerZ = 1500; - - context.translate(width / 2, height / 2); - - points[0] = { x: -500, y: -500, z: 500 }; - points[1] = { x: 500, y: -500, z: 500 }; - points[2] = { x: 500, y: -500, z: -500 }; - points[3] = { x: -500, y: -500, z: -500 }; - points[4] = { x: -500, y: 500, z: 500 }; - points[5] = { x: 500, y: 500, z: 500 }; - points[6] = { x: 500, y: 500, z: -500 }; - points[7] = { x: -500, y: 500, z: -500 }; - - function project() { - for(var i = 0; i < points.length; i++) { - var p = points[i], - scale = fl / (fl + p.z + centerZ); - - p.sx = p.x * scale; - p.sy = p.y * scale; - } - } - - function drawLine() { - var p = points[arguments[0]]; - context.moveTo(p.sx, p.sy); - - for(var i = 1; i < arguments.length; i++) { - p = points[arguments[i]]; - context.lineTo(p.sx, p.sy); - } - } - - function translateModel(x, y, z) { - for(var i = 0; i < points.length; i++) { - points[i].x += x; - points[i].y += y; - points[i].z += z; - } - needsUpdate = true; - } - - function rotateX(angle) { - var cos = Math.cos(angle), - sin = Math.sin(angle); - - for(var i = 0; i < points.length; i++) { - var p = points[i], - y = p.y * cos - p.z * sin, - z = p.z * cos + p.y * sin; - p.y = y; - p.z = z; - } - needsUpdate = true; - } - - function rotateY(angle) { - var cos = Math.cos(angle), - sin = Math.sin(angle); - - for(var i = 0; i < points.length; i++) { - var p = points[i], - x = p.x * cos - p.z * sin, - z = p.z * cos + p.x * sin; - p.x = x; - p.z = z; - } - needsUpdate = true; - } - - function rotateZ(angle) { - var cos = Math.cos(angle), - sin = Math.sin(angle); - - for(var i = 0; i < points.length; i++) { - var p = points[i], - x = p.x * cos - p.y * sin, - y = p.y * cos + p.x * sin; - p.x = x; - p.y = y; - } - needsUpdate = true; - } - - document.body.addEventListener("keydown", function(event) { - switch(event.keyCode) { - case 37: // left - if(event.ctrlKey) { - rotateY(0.05); - } - else { - translateModel(-20, 0, 0); - } - break; - case 39: // right - if(event.ctrlKey) { - rotateY(-0.05); - } - else { - translateModel(20, 0, 0); - } - break; - case 38: // up - if(event.shiftKey) { - translateModel(0, 0, 20); - } - else if(event.ctrlKey) { - rotateX(0.05); - } - else { - translateModel(0, -20, 0); - } - break; - case 40: // down - if(event.shiftKey) { - translateModel(0, 0, -20); - } - else if(event.ctrlKey) { - rotateX(-0.05); - } - else { - translateModel(0, 20, 0); - } - break; - } - }); - - update(); - - function update() { - if(needsUpdate) { - context.clearRect(-width / 2, -height / 2, width, height); - project(); - - context.beginPath(); - drawLine(0, 1, 2, 3, 0); - drawLine(4, 5, 6, 7, 4); - drawLine(0, 4); - drawLine(1, 5); - drawLine(2, 6); - drawLine(3, 7); - context.stroke(); - needsUpdate = false; - } - requestAnimationFrame(update); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight + fl = 300, + points = [], + needsUpdate = true, + centerZ = 1500; + + context.translate(width / 2, height / 2); + + points[0] = { x: -500, y: -500, z: 500 }; + points[1] = { x: 500, y: -500, z: 500 }; + points[2] = { x: 500, y: -500, z: -500 }; + points[3] = { x: -500, y: -500, z: -500 }; + points[4] = { x: -500, y: 500, z: 500 }; + points[5] = { x: 500, y: 500, z: 500 }; + points[6] = { x: 500, y: 500, z: -500 }; + points[7] = { x: -500, y: 500, z: -500 }; + + function project() { + for(var i = 0; i < points.length; i++) { + var p = points[i], + scale = fl / (fl + p.z + centerZ); + + p.sx = p.x * scale; + p.sy = p.y * scale; + } + } + + function drawLine() { + var p = points[arguments[0]]; + context.moveTo(p.sx, p.sy); + + for(var i = 1; i < arguments.length; i++) { + p = points[arguments[i]]; + context.lineTo(p.sx, p.sy); + } + } + + function translateModel(x, y, z) { + for(var i = 0; i < points.length; i++) { + points[i].x += x; + points[i].y += y; + points[i].z += z; + } + needsUpdate = true; + } + + function rotateX(angle) { + var cos = Math.cos(angle), + sin = Math.sin(angle); + + for(var i = 0; i < points.length; i++) { + var p = points[i], + y = p.y * cos - p.z * sin, + z = p.z * cos + p.y * sin; + p.y = y; + p.z = z; + } + needsUpdate = true; + } + + function rotateY(angle) { + var cos = Math.cos(angle), + sin = Math.sin(angle); + + for(var i = 0; i < points.length; i++) { + var p = points[i], + x = p.x * cos - p.z * sin, + z = p.z * cos + p.x * sin; + p.x = x; + p.z = z; + } + needsUpdate = true; + } + + function rotateZ(angle) { + var cos = Math.cos(angle), + sin = Math.sin(angle); + + for(var i = 0; i < points.length; i++) { + var p = points[i], + x = p.x * cos - p.y * sin, + y = p.y * cos + p.x * sin; + p.x = x; + p.y = y; + } + needsUpdate = true; + } + + document.body.addEventListener("keydown", function(event) { + switch(event.keyCode) { + case 37: // left + if(event.ctrlKey) { + rotateY(0.05); + } + else { + translateModel(-20, 0, 0); + } + break; + case 39: // right + if(event.ctrlKey) { + rotateY(-0.05); + } + else { + translateModel(20, 0, 0); + } + break; + case 38: // up + if(event.shiftKey) { + translateModel(0, 0, 20); + } + else if(event.ctrlKey) { + rotateX(0.05); + } + else { + translateModel(0, -20, 0); + } + break; + case 40: // down + if(event.shiftKey) { + translateModel(0, 0, -20); + } + else if(event.ctrlKey) { + rotateX(-0.05); + } + else { + translateModel(0, 20, 0); + } + break; + } + }); + + update(); + + function update() { + if(needsUpdate) { + context.clearRect(-width / 2, -height / 2, width, height); + project(); + + context.beginPath(); + drawLine(0, 1, 2, 3, 0); + drawLine(4, 5, 6, 7, 4); + drawLine(0, 4); + drawLine(1, 5); + drawLine(2, 6); + drawLine(3, 7); + context.stroke(); + needsUpdate = false; + } + requestAnimationFrame(update); + } + }; \ No newline at end of file diff --git a/episode27/index.html b/episode27/index.html index 5989d5a..b211694 100644 --- a/episode27/index.html +++ b/episode27/index.html @@ -1,23 +1,23 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/episode27/main.js b/episode27/main.js index 12399a3..2b0eba4 100644 --- a/episode27/main.js +++ b/episode27/main.js @@ -1,46 +1,46 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - - target = { - x: width, - y: Math.random() * height - }, - - position = { - x: 0, - y: Math.random() * height - }, - - ease = 0.1; - - update(); - - document.body.addEventListener("mousemove", function(event) { - target.x = event.clientX; - target.y = event.clientY; - }); - - function update() { - context.clearRect(0, 0, width, height); - - context.beginPath(); - context.arc(position.x, position.y, 10, 0, Math.PI * 2, false); - context.fill(); - - - var dx = target.x - position.x, - dy = target.y - position.y, - vx = dx * ease, - vy = dy * ease; - - position.x += vx; - position.y += vy; - - - requestAnimationFrame(update); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + + target = { + x: width, + y: Math.random() * height + }, + + position = { + x: 0, + y: Math.random() * height + }, + + ease = 0.1; + + update(); + + document.body.addEventListener("mousemove", function(event) { + target.x = event.clientX; + target.y = event.clientY; + }); + + function update() { + context.clearRect(0, 0, width, height); + + context.beginPath(); + context.arc(position.x, position.y, 10, 0, Math.PI * 2, false); + context.fill(); + + + var dx = target.x - position.x, + dy = target.y - position.y, + vx = dx * ease, + vy = dy * ease; + + position.x += vx; + position.y += vy; + + + requestAnimationFrame(update); + } + }; \ No newline at end of file diff --git a/episode28/click.js b/episode28/click.js index 474b91a..7519fdc 100644 --- a/episode28/click.js +++ b/episode28/click.js @@ -1,59 +1,59 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - - target = { - x: width, - y: Math.random() * height - }, - - position = { - x: 0, - y: Math.random() * height - }, - - ease = 0.1, - easing = true; - - update(); - - document.body.addEventListener("click", function(event) { - target.x = event.clientX; - target.y = event.clientY; - if(!easing) { - easing = true; - update(); - } - }); - - function update() { - context.clearRect(0, 0, width, height); - - context.beginPath(); - context.arc(position.x, position.y, 10, 0, Math.PI * 2, false); - context.fill(); - - easing = easeTo(position, target, ease); - - if(easing) { - requestAnimationFrame(update); - } - } - - function easeTo(position, target, ease) { - var dx = target.x - position.x, - dy = target.y - position.y; - position.x += dx * ease; - position.y += dy * ease; - if(Math.abs(dx) < 0.1 && Math.abs(dy) < 0.1) { - position.x = target.x; - position.y = target.y; - console.log("stop"); - return false; - } - return true; - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + + target = { + x: width, + y: Math.random() * height + }, + + position = { + x: 0, + y: Math.random() * height + }, + + ease = 0.1, + easing = true; + + update(); + + document.body.addEventListener("click", function(event) { + target.x = event.clientX; + target.y = event.clientY; + if(!easing) { + easing = true; + update(); + } + }); + + function update() { + context.clearRect(0, 0, width, height); + + context.beginPath(); + context.arc(position.x, position.y, 10, 0, Math.PI * 2, false); + context.fill(); + + easing = easeTo(position, target, ease); + + if(easing) { + requestAnimationFrame(update); + } + } + + function easeTo(position, target, ease) { + var dx = target.x - position.x, + dy = target.y - position.y; + position.x += dx * ease; + position.y += dy * ease; + if(Math.abs(dx) < 0.1 && Math.abs(dy) < 0.1) { + position.x = target.x; + position.y = target.y; + console.log("stop"); + return false; + } + return true; + } + }; \ No newline at end of file diff --git a/episode28/index.html b/episode28/index.html index 4f21121..eb51211 100644 --- a/episode28/index.html +++ b/episode28/index.html @@ -1,24 +1,24 @@ - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/episode28/main.js b/episode28/main.js index b4eaa12..781320f 100644 --- a/episode28/main.js +++ b/episode28/main.js @@ -1,55 +1,55 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - - target = { - x: width, - y: Math.random() * height - }, - - points = [], - numPoints = 100, - ease = 0.5; - - for(var i = 0; i < numPoints; i++) { - points.push({ - x: 0, - y: 0 - }); - } - - update(); - - document.body.addEventListener("mousemove", function(event) { - target.x = event.clientX; - target.y = event.clientY; - }); - - function update() { - context.clearRect(0, 0, width, height); - - var leader = { - x: target.x, - y: target.y - }; - - for(var i = 0; i < numPoints; i++) { - var point = points[i]; - point.x += (leader.x - point.x) * ease; - point.y += (leader.y - point.y) * ease; - - context.beginPath(); - context.arc(point.x, point.y, 10, 0, Math.PI * 2, false); - context.fill(); - - leader.x = point.x; - leader.y = point.y; - } - - - requestAnimationFrame(update); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + + target = { + x: width, + y: Math.random() * height + }, + + points = [], + numPoints = 100, + ease = 0.5; + + for(var i = 0; i < numPoints; i++) { + points.push({ + x: 0, + y: 0 + }); + } + + update(); + + document.body.addEventListener("mousemove", function(event) { + target.x = event.clientX; + target.y = event.clientY; + }); + + function update() { + context.clearRect(0, 0, width, height); + + var leader = { + x: target.x, + y: target.y + }; + + for(var i = 0; i < numPoints; i++) { + var point = points[i]; + point.x += (leader.x - point.x) * ease; + point.y += (leader.y - point.y) * ease; + + context.beginPath(); + context.arc(point.x, point.y, 10, 0, Math.PI * 2, false); + context.fill(); + + leader.x = point.x; + leader.y = point.y; + } + + + requestAnimationFrame(update); + } + }; \ No newline at end of file diff --git a/episode28/steering.js b/episode28/steering.js index a22ff37..63d8039 100644 --- a/episode28/steering.js +++ b/episode28/steering.js @@ -1,38 +1,38 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - angle = 0, - targetAngle = 0, - ease = 0.05, - wheel; - - wheel = document.createElement("img"); - wheel.addEventListener("load", function() { - render(); - }); - wheel.src = "wheel.png"; - - - function render() { - context.clearRect(0, 0, width, height); - - angle += (targetAngle - angle) * ease; - - context.save(); - context.translate(width / 2, height / 2); - context.rotate(angle); - - context.drawImage(wheel, -wheel.width / 2, -wheel.height / 2); - - context.restore(); - requestAnimationFrame(render); - } - - document.body.addEventListener("mousemove", function(event) { - targetAngle = utils.map(event.clientX, 0, width, -Math.PI, Math.PI); - }); - - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + angle = 0, + targetAngle = 0, + ease = 0.05, + wheel; + + wheel = document.createElement("img"); + wheel.addEventListener("load", function() { + render(); + }); + wheel.src = "wheel.png"; + + + function render() { + context.clearRect(0, 0, width, height); + + angle += (targetAngle - angle) * ease; + + context.save(); + context.translate(width / 2, height / 2); + context.rotate(angle); + + context.drawImage(wheel, -wheel.width / 2, -wheel.height / 2); + + context.restore(); + requestAnimationFrame(render); + } + + document.body.addEventListener("mousemove", function(event) { + targetAngle = utils.map(event.clientX, 0, width, -Math.PI, Math.PI); + }); + + }; \ No newline at end of file diff --git a/episode28/string.js b/episode28/string.js index bce76bd..23692c2 100644 --- a/episode28/string.js +++ b/episode28/string.js @@ -1,57 +1,57 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - - target = { - x: width, - y: Math.random() * height - }, - - points = [], - numPoints = 50, - ease = 0.25; - - for(var i = 0; i < numPoints; i++) { - points.push({ - x: 0, - y: 0 - }); - } - - update(); - - document.body.addEventListener("mousemove", function(event) { - target.x = event.clientX; - target.y = event.clientY; - }); - - function update() { - context.clearRect(0, 0, width, height); - - var leader = { - x: target.x, - y: target.y - }; - - context.beginPath(); - context.moveTo(leader.x, leader.y); - - for(var i = 0; i < numPoints; i++) { - var point = points[i]; - point.x += (leader.x - point.x) * ease; - point.y += (leader.y - point.y) * ease; - - context.lineTo(point.x, point.y); - - leader.x = point.x; - leader.y = point.y; - } - - context.stroke(); - - requestAnimationFrame(update); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + + target = { + x: width, + y: Math.random() * height + }, + + points = [], + numPoints = 50, + ease = 0.25; + + for(var i = 0; i < numPoints; i++) { + points.push({ + x: 0, + y: 0 + }); + } + + update(); + + document.body.addEventListener("mousemove", function(event) { + target.x = event.clientX; + target.y = event.clientY; + }); + + function update() { + context.clearRect(0, 0, width, height); + + var leader = { + x: target.x, + y: target.y + }; + + context.beginPath(); + context.moveTo(leader.x, leader.y); + + for(var i = 0; i < numPoints; i++) { + var point = points[i]; + point.x += (leader.x - point.x) * ease; + point.y += (leader.y - point.y) * ease; + + context.lineTo(point.x, point.y); + + leader.x = point.x; + leader.y = point.y; + } + + context.stroke(); + + requestAnimationFrame(update); + } + }; \ No newline at end of file diff --git a/episode28/utils.js b/episode28/utils.js index 3c0f824..04715df 100644 --- a/episode28/utils.js +++ b/episode28/utils.js @@ -1,123 +1,123 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - }, - - degreesToRads: function(degrees) { - return degrees / 180 * Math.PI; - }, - - radsToDegrees: function(radians) { - return radians * 180 / Math.PI; - }, - - randomRange: function(min, max) { - return min + Math.random() * (max - min); - }, - - randomInt: function(min, max) { - return Math.floor(min + Math.random() * (max - min + 1)); - }, - - roundToPlaces: function(value, places) { - var mult = Math.pow(10, places); - return Math.round(value * mult) / mult; - }, - - roundNearest: function(value, nearest) { - return Math.round(value / nearest) * nearest; - }, - - quadraticBezier: function(p0, p1, p2, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 2) * p0.x + - (1 - t) * 2 * t * p1.x + - t * t * p2.x; - pFinal.y = Math.pow(1 - t, 2) * p0.y + - (1 - t) * 2 * t * p1.y + - t * t * p2.y; - return pFinal; - }, - - cubicBezier: function(p0, p1, p2, p3, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 3) * p0.x + - Math.pow(1 - t, 2) * 3 * t * p1.x + - (1 - t) * 3 * t * t * p2.x + - t * t * t * p3.x; - pFinal.y = Math.pow(1 - t, 3) * p0.y + - Math.pow(1 - t, 2) * 3 * t * p1.y + - (1 - t) * 3 * t * t * p2.y + - t * t * t * p3.y; - return pFinal; - }, - - multicurve: function(points, context) { - var p0, p1, midx, midy; - - context.moveTo(points[0].x, points[0].y); - - for(var i = 1; i < points.length - 2; i += 1) { - p0 = points[i]; - p1 = points[i + 1]; - midx = (p0.x + p1.x) / 2; - midy = (p0.y + p1.y) / 2; - context.quadraticCurveTo(p0.x, p0.y, midx, midy); - } - p0 = points[points.length - 2]; - p1 = points[points.length - 1]; - context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + }, + + multicurve: function(points, context) { + var p0, p1, midx, midy; + + context.moveTo(points[0].x, points[0].y); + + for(var i = 1; i < points.length - 2; i += 1) { + p0 = points[i]; + p1 = points[i + 1]; + midx = (p0.x + p1.x) / 2; + midy = (p0.y + p1.y) / 2; + context.quadraticCurveTo(p0.x, p0.y, midx, midy); + } + p0 = points[points.length - 2]; + p1 = points[points.length - 1]; + context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); + } + } \ No newline at end of file diff --git a/episode29/index.html b/episode29/index.html index 5989d5a..b211694 100644 --- a/episode29/index.html +++ b/episode29/index.html @@ -1,23 +1,23 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/episode29/main.js b/episode29/main.js index 36c55d0..d212622 100644 --- a/episode29/main.js +++ b/episode29/main.js @@ -1,78 +1,78 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - start = { - x: 100, - y: 100 - }, - target = {}, - change = {}, - startTime, - duration = 1000; - - drawCircle(start.x, start.y); - - - document.body.addEventListener("click", function(event) { - target.x = event.clientX; - target.y = event.clientY; - change.x = target.x - start.x; - change.y = target.y - start.y; - startTime = new Date(); - update(); - }); - - function update() { - context.clearRect(0, 0, width, height); - - var time = new Date() - startTime; - if(time < duration) { - var x = easeInOutQuad(time, start.x, change.x, duration), - y = easeInOutQuad(time, start.y, change.y, duration); - drawCircle(x, y); - requestAnimationFrame(update); - } - else { - drawCircle(target.x, target.y); - start.x = target.x; - start.y = target.y; - } - - } - - // simple linear tweening - no easing - // t: current time, b: beginning value, c: change in value, d: duration - function linearTween(t, b, c, d) { - return c * t / d + b; - } - - ///////////// QUADRATIC EASING: t^2 /////////////////// - - // quadratic easing in - accelerating from zero velocity - // t: current time, b: beginning value, c: change in value, d: duration - // t and d can be in frames or seconds/milliseconds - function easeInQuad(t, b, c, d) { - return c*(t/=d)*t + b; - }; - - // quadratic easing out - decelerating to zero velocity - function easeOutQuad(t, b, c, d) { - return -c *(t/=d)*(t-2) + b; - }; - - // quadratic easing in/out - acceleration until halfway, then deceleration - function easeInOutQuad(t, b, c, d) { - if ((t/=d/2) < 1) return c/2*t*t + b; - return -c/2 * ((--t)*(t-2) - 1) + b; - }; - - - function drawCircle(x, y) { - context.beginPath(); - context.arc(x, y, 20, 0, Math.PI * 2, false); - context.fill(); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + start = { + x: 100, + y: 100 + }, + target = {}, + change = {}, + startTime, + duration = 1000; + + drawCircle(start.x, start.y); + + + document.body.addEventListener("click", function(event) { + target.x = event.clientX; + target.y = event.clientY; + change.x = target.x - start.x; + change.y = target.y - start.y; + startTime = new Date(); + update(); + }); + + function update() { + context.clearRect(0, 0, width, height); + + var time = new Date() - startTime; + if(time < duration) { + var x = easeInOutQuad(time, start.x, change.x, duration), + y = easeInOutQuad(time, start.y, change.y, duration); + drawCircle(x, y); + requestAnimationFrame(update); + } + else { + drawCircle(target.x, target.y); + start.x = target.x; + start.y = target.y; + } + + } + + // simple linear tweening - no easing + // t: current time, b: beginning value, c: change in value, d: duration + function linearTween(t, b, c, d) { + return c * t / d + b; + } + + ///////////// QUADRATIC EASING: t^2 /////////////////// + + // quadratic easing in - accelerating from zero velocity + // t: current time, b: beginning value, c: change in value, d: duration + // t and d can be in frames or seconds/milliseconds + function easeInQuad(t, b, c, d) { + return c*(t/=d)*t + b; + }; + + // quadratic easing out - decelerating to zero velocity + function easeOutQuad(t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + }; + + // quadratic easing in/out - acceleration until halfway, then deceleration + function easeInOutQuad(t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + }; + + + function drawCircle(x, y) { + context.beginPath(); + context.arc(x, y, 20, 0, Math.PI * 2, false); + context.fill(); + } + }; \ No newline at end of file diff --git a/episode29/penner_easing.as b/episode29/penner_easing.as index f96a2b1..cad54b5 100644 --- a/episode29/penner_easing.as +++ b/episode29/penner_easing.as @@ -1,282 +1,282 @@ -/* - Easing Equations v1.5 - May 1, 2003 - (c) 2003 Robert Penner, all rights reserved. - This work is subject to the terms in http://www.robertpenner.com/easing_terms_of_use.html. - - These tweening functions provide different flavors of - math-based motion under a consistent API. - - Types of easing: - - Linear - Quadratic - Cubic - Quartic - Quintic - Sinusoidal - Exponential - Circular - Elastic - Back - Bounce - - Changes: - 1.5 - added bounce easing - 1.4 - added elastic and back easing - 1.3 - tweaked the exponential easing functions to make endpoints exact - 1.2 - inline optimizations (changing t and multiplying in one step)--thanks to Tatsuo Kato for the idea - - Discussed in Chapter 7 of - Robert Penner's Programming Macromedia Flash MX - (including graphs of the easing equations) - - http://www.robertpenner.com/profmx - http://www.amazon.com/exec/obidos/ASIN/0072223561/robertpennerc-20 -*/ - - -// simple linear tweening - no easing -// t: current time, b: beginning value, c: change in value, d: duration -Math.linearTween = function (t, b, c, d) { - return c*t/d + b; -}; - - - ///////////// QUADRATIC EASING: t^2 /////////////////// - -// quadratic easing in - accelerating from zero velocity -// t: current time, b: beginning value, c: change in value, d: duration -// t and d can be in frames or seconds/milliseconds -Math.easeInQuad = function (t, b, c, d) { - return c*(t/=d)*t + b; -}; - -// quadratic easing out - decelerating to zero velocity -Math.easeOutQuad = function (t, b, c, d) { - return -c *(t/=d)*(t-2) + b; -}; - -// quadratic easing in/out - acceleration until halfway, then deceleration -Math.easeInOutQuad = function (t, b, c, d) { - if ((t/=d/2) < 1) return c/2*t*t + b; - return -c/2 * ((--t)*(t-2) - 1) + b; -}; - - - ///////////// CUBIC EASING: t^3 /////////////////////// - -// cubic easing in - accelerating from zero velocity -// t: current time, b: beginning value, c: change in value, d: duration -// t and d can be frames or seconds/milliseconds -Math.easeInCubic = function (t, b, c, d) { - return c*(t/=d)*t*t + b; -}; - -// cubic easing out - decelerating to zero velocity -Math.easeOutCubic = function (t, b, c, d) { - return c*((t=t/d-1)*t*t + 1) + b; -}; - -// cubic easing in/out - acceleration until halfway, then deceleration -Math.easeInOutCubic = function (t, b, c, d) { - if ((t/=d/2) < 1) return c/2*t*t*t + b; - return c/2*((t-=2)*t*t + 2) + b; -}; - - - ///////////// QUARTIC EASING: t^4 ///////////////////// - -// quartic easing in - accelerating from zero velocity -// t: current time, b: beginning value, c: change in value, d: duration -// t and d can be frames or seconds/milliseconds -Math.easeInQuart = function (t, b, c, d) { - return c*(t/=d)*t*t*t + b; -}; - -// quartic easing out - decelerating to zero velocity -Math.easeOutQuart = function (t, b, c, d) { - return -c * ((t=t/d-1)*t*t*t - 1) + b; -}; - -// quartic easing in/out - acceleration until halfway, then deceleration -Math.easeInOutQuart = function (t, b, c, d) { - if ((t/=d/2) < 1) return c/2*t*t*t*t + b; - return -c/2 * ((t-=2)*t*t*t - 2) + b; -}; - - - ///////////// QUINTIC EASING: t^5 //////////////////// - -// quintic easing in - accelerating from zero velocity -// t: current time, b: beginning value, c: change in value, d: duration -// t and d can be frames or seconds/milliseconds -Math.easeInQuint = function (t, b, c, d) { - return c*(t/=d)*t*t*t*t + b; -}; - -// quintic easing out - decelerating to zero velocity -Math.easeOutQuint = function (t, b, c, d) { - return c*((t=t/d-1)*t*t*t*t + 1) + b; -}; - -// quintic easing in/out - acceleration until halfway, then deceleration -Math.easeInOutQuint = function (t, b, c, d) { - if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; - return c/2*((t-=2)*t*t*t*t + 2) + b; -}; - - - - ///////////// SINUSOIDAL EASING: sin(t) /////////////// - -// sinusoidal easing in - accelerating from zero velocity -// t: current time, b: beginning value, c: change in position, d: duration -Math.easeInSine = function (t, b, c, d) { - return -c * Math.cos(t/d * (Math.PI/2)) + c + b; -}; - -// sinusoidal easing out - decelerating to zero velocity -Math.easeOutSine = function (t, b, c, d) { - return c * Math.sin(t/d * (Math.PI/2)) + b; -}; - -// sinusoidal easing in/out - accelerating until halfway, then decelerating -Math.easeInOutSine = function (t, b, c, d) { - return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; -}; - - - ///////////// EXPONENTIAL EASING: 2^t ///////////////// - -// exponential easing in - accelerating from zero velocity -// t: current time, b: beginning value, c: change in position, d: duration -Math.easeInExpo = function (t, b, c, d) { - return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; -}; - -// exponential easing out - decelerating to zero velocity -Math.easeOutExpo = function (t, b, c, d) { - return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; -}; - -// exponential easing in/out - accelerating until halfway, then decelerating -Math.easeInOutExpo = function (t, b, c, d) { - if (t==0) return b; - if (t==d) return b+c; - if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; - return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; -}; - - - /////////// CIRCULAR EASING: sqrt(1-t^2) ////////////// - -// circular easing in - accelerating from zero velocity -// t: current time, b: beginning value, c: change in position, d: duration -Math.easeInCirc = function (t, b, c, d) { - return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; -}; - -// circular easing out - decelerating to zero velocity -Math.easeOutCirc = function (t, b, c, d) { - return c * Math.sqrt(1 - (t=t/d-1)*t) + b; -}; - -// circular easing in/out - acceleration until halfway, then deceleration -Math.easeInOutCirc = function (t, b, c, d) { - if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; - return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; -}; - - - /////////// ELASTIC EASING: exponentially decaying sine wave ////////////// - -// t: current time, b: beginning value, c: change in value, d: duration, a: amplitude (optional), p: period (optional) -// t and d can be in frames or seconds/milliseconds - -Math.easeInElastic = function (t, b, c, d, a, p) { - if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; - if (a < Math.abs(c)) { a=c; var s=p/4; } - else var s = p/(2*Math.PI) * Math.asin (c/a); - return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; -}; - -Math.easeOutElastic = function (t, b, c, d, a, p) { - if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; - if (a < Math.abs(c)) { a=c; var s=p/4; } - else var s = p/(2*Math.PI) * Math.asin (c/a); - return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; -}; - -Math.easeInOutElastic = function (t, b, c, d, a, p) { - if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); - if (a < Math.abs(c)) { a=c; var s=p/4; } - else var s = p/(2*Math.PI) * Math.asin (c/a); - if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; - return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; -}; - - - /////////// BACK EASING: overshooting cubic easing: (s+1)*t^3 - s*t^2 ////////////// - -// back easing in - backtracking slightly, then reversing direction and moving to target -// t: current time, b: beginning value, c: change in value, d: duration, s: overshoot amount (optional) -// t and d can be in frames or seconds/milliseconds -// s controls the amount of overshoot: higher s means greater overshoot -// s has a default value of 1.70158, which produces an overshoot of 10 percent -// s==0 produces cubic easing with no overshoot -Math.easeInBack = function (t, b, c, d, s) { - if (s == undefined) s = 1.70158; - return c*(t/=d)*t*((s+1)*t - s) + b; -}; - -// back easing out - moving towards target, overshooting it slightly, then reversing and coming back to target -Math.easeOutBack = function (t, b, c, d, s) { - if (s == undefined) s = 1.70158; - return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; -}; - -// back easing in/out - backtracking slightly, then reversing direction and moving to target, -// then overshooting target, reversing, and finally coming back to target -Math.easeInOutBack = function (t, b, c, d, s) { - if (s == undefined) s = 1.70158; - if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; - return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; -}; - - - /////////// BOUNCE EASING: exponentially decaying parabolic bounce ////////////// - -// bounce easing in -// t: current time, b: beginning value, c: change in position, d: duration -Math.easeInBounce = function (t, b, c, d) { - return c - Math.easeOutBounce (d-t, 0, c, d) + b; -}; - -// bounce easing out -Math.easeOutBounce = function (t, b, c, d) { - if ((t/=d) < (1/2.75)) { - return c*(7.5625*t*t) + b; - } else if (t < (2/2.75)) { - return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; - } else if (t < (2.5/2.75)) { - return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; - } else { - return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; - } -}; - -// bounce easing in/out -Math.easeInOutBounce = function (t, b, c, d) { - if (t < d/2) return Math.easeInBounce (t*2, 0, c, d) * .5 + b; - return Math.easeOutBounce (t*2-d, 0, c, d) * .5 + c*.5 + b; -}; - - -//trace (">> Penner easing equations loaded"); - - - - - - +/* + Easing Equations v1.5 + May 1, 2003 + (c) 2003 Robert Penner, all rights reserved. + This work is subject to the terms in http://www.robertpenner.com/easing_terms_of_use.html. + + These tweening functions provide different flavors of + math-based motion under a consistent API. + + Types of easing: + + Linear + Quadratic + Cubic + Quartic + Quintic + Sinusoidal + Exponential + Circular + Elastic + Back + Bounce + + Changes: + 1.5 - added bounce easing + 1.4 - added elastic and back easing + 1.3 - tweaked the exponential easing functions to make endpoints exact + 1.2 - inline optimizations (changing t and multiplying in one step)--thanks to Tatsuo Kato for the idea + + Discussed in Chapter 7 of + Robert Penner's Programming Macromedia Flash MX + (including graphs of the easing equations) + + http://www.robertpenner.com/profmx + http://www.amazon.com/exec/obidos/ASIN/0072223561/robertpennerc-20 +*/ + + +// simple linear tweening - no easing +// t: current time, b: beginning value, c: change in value, d: duration +Math.linearTween = function (t, b, c, d) { + return c*t/d + b; +}; + + + ///////////// QUADRATIC EASING: t^2 /////////////////// + +// quadratic easing in - accelerating from zero velocity +// t: current time, b: beginning value, c: change in value, d: duration +// t and d can be in frames or seconds/milliseconds +Math.easeInQuad = function (t, b, c, d) { + return c*(t/=d)*t + b; +}; + +// quadratic easing out - decelerating to zero velocity +Math.easeOutQuad = function (t, b, c, d) { + return -c *(t/=d)*(t-2) + b; +}; + +// quadratic easing in/out - acceleration until halfway, then deceleration +Math.easeInOutQuad = function (t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; +}; + + + ///////////// CUBIC EASING: t^3 /////////////////////// + +// cubic easing in - accelerating from zero velocity +// t: current time, b: beginning value, c: change in value, d: duration +// t and d can be frames or seconds/milliseconds +Math.easeInCubic = function (t, b, c, d) { + return c*(t/=d)*t*t + b; +}; + +// cubic easing out - decelerating to zero velocity +Math.easeOutCubic = function (t, b, c, d) { + return c*((t=t/d-1)*t*t + 1) + b; +}; + +// cubic easing in/out - acceleration until halfway, then deceleration +Math.easeInOutCubic = function (t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t + b; + return c/2*((t-=2)*t*t + 2) + b; +}; + + + ///////////// QUARTIC EASING: t^4 ///////////////////// + +// quartic easing in - accelerating from zero velocity +// t: current time, b: beginning value, c: change in value, d: duration +// t and d can be frames or seconds/milliseconds +Math.easeInQuart = function (t, b, c, d) { + return c*(t/=d)*t*t*t + b; +}; + +// quartic easing out - decelerating to zero velocity +Math.easeOutQuart = function (t, b, c, d) { + return -c * ((t=t/d-1)*t*t*t - 1) + b; +}; + +// quartic easing in/out - acceleration until halfway, then deceleration +Math.easeInOutQuart = function (t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t + b; + return -c/2 * ((t-=2)*t*t*t - 2) + b; +}; + + + ///////////// QUINTIC EASING: t^5 //////////////////// + +// quintic easing in - accelerating from zero velocity +// t: current time, b: beginning value, c: change in value, d: duration +// t and d can be frames or seconds/milliseconds +Math.easeInQuint = function (t, b, c, d) { + return c*(t/=d)*t*t*t*t + b; +}; + +// quintic easing out - decelerating to zero velocity +Math.easeOutQuint = function (t, b, c, d) { + return c*((t=t/d-1)*t*t*t*t + 1) + b; +}; + +// quintic easing in/out - acceleration until halfway, then deceleration +Math.easeInOutQuint = function (t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; + return c/2*((t-=2)*t*t*t*t + 2) + b; +}; + + + + ///////////// SINUSOIDAL EASING: sin(t) /////////////// + +// sinusoidal easing in - accelerating from zero velocity +// t: current time, b: beginning value, c: change in position, d: duration +Math.easeInSine = function (t, b, c, d) { + return -c * Math.cos(t/d * (Math.PI/2)) + c + b; +}; + +// sinusoidal easing out - decelerating to zero velocity +Math.easeOutSine = function (t, b, c, d) { + return c * Math.sin(t/d * (Math.PI/2)) + b; +}; + +// sinusoidal easing in/out - accelerating until halfway, then decelerating +Math.easeInOutSine = function (t, b, c, d) { + return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; +}; + + + ///////////// EXPONENTIAL EASING: 2^t ///////////////// + +// exponential easing in - accelerating from zero velocity +// t: current time, b: beginning value, c: change in position, d: duration +Math.easeInExpo = function (t, b, c, d) { + return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; +}; + +// exponential easing out - decelerating to zero velocity +Math.easeOutExpo = function (t, b, c, d) { + return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; +}; + +// exponential easing in/out - accelerating until halfway, then decelerating +Math.easeInOutExpo = function (t, b, c, d) { + if (t==0) return b; + if (t==d) return b+c; + if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; + return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; +}; + + + /////////// CIRCULAR EASING: sqrt(1-t^2) ////////////// + +// circular easing in - accelerating from zero velocity +// t: current time, b: beginning value, c: change in position, d: duration +Math.easeInCirc = function (t, b, c, d) { + return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; +}; + +// circular easing out - decelerating to zero velocity +Math.easeOutCirc = function (t, b, c, d) { + return c * Math.sqrt(1 - (t=t/d-1)*t) + b; +}; + +// circular easing in/out - acceleration until halfway, then deceleration +Math.easeInOutCirc = function (t, b, c, d) { + if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; + return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; +}; + + + /////////// ELASTIC EASING: exponentially decaying sine wave ////////////// + +// t: current time, b: beginning value, c: change in value, d: duration, a: amplitude (optional), p: period (optional) +// t and d can be in frames or seconds/milliseconds + +Math.easeInElastic = function (t, b, c, d, a, p) { + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; +}; + +Math.easeOutElastic = function (t, b, c, d, a, p) { + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; +}; + +Math.easeInOutElastic = function (t, b, c, d, a, p) { + if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; +}; + + + /////////// BACK EASING: overshooting cubic easing: (s+1)*t^3 - s*t^2 ////////////// + +// back easing in - backtracking slightly, then reversing direction and moving to target +// t: current time, b: beginning value, c: change in value, d: duration, s: overshoot amount (optional) +// t and d can be in frames or seconds/milliseconds +// s controls the amount of overshoot: higher s means greater overshoot +// s has a default value of 1.70158, which produces an overshoot of 10 percent +// s==0 produces cubic easing with no overshoot +Math.easeInBack = function (t, b, c, d, s) { + if (s == undefined) s = 1.70158; + return c*(t/=d)*t*((s+1)*t - s) + b; +}; + +// back easing out - moving towards target, overshooting it slightly, then reversing and coming back to target +Math.easeOutBack = function (t, b, c, d, s) { + if (s == undefined) s = 1.70158; + return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; +}; + +// back easing in/out - backtracking slightly, then reversing direction and moving to target, +// then overshooting target, reversing, and finally coming back to target +Math.easeInOutBack = function (t, b, c, d, s) { + if (s == undefined) s = 1.70158; + if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; + return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; +}; + + + /////////// BOUNCE EASING: exponentially decaying parabolic bounce ////////////// + +// bounce easing in +// t: current time, b: beginning value, c: change in position, d: duration +Math.easeInBounce = function (t, b, c, d) { + return c - Math.easeOutBounce (d-t, 0, c, d) + b; +}; + +// bounce easing out +Math.easeOutBounce = function (t, b, c, d) { + if ((t/=d) < (1/2.75)) { + return c*(7.5625*t*t) + b; + } else if (t < (2/2.75)) { + return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; + } else if (t < (2.5/2.75)) { + return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; + } else { + return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; + } +}; + +// bounce easing in/out +Math.easeInOutBounce = function (t, b, c, d) { + if (t < d/2) return Math.easeInBounce (t*2, 0, c, d) * .5 + b; + return Math.easeOutBounce (t*2-d, 0, c, d) * .5 + c*.5 + b; +}; + + +//trace (">> Penner easing equations loaded"); + + + + + + diff --git a/episode29/utils.js b/episode29/utils.js index 3c0f824..04715df 100644 --- a/episode29/utils.js +++ b/episode29/utils.js @@ -1,123 +1,123 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - }, - - degreesToRads: function(degrees) { - return degrees / 180 * Math.PI; - }, - - radsToDegrees: function(radians) { - return radians * 180 / Math.PI; - }, - - randomRange: function(min, max) { - return min + Math.random() * (max - min); - }, - - randomInt: function(min, max) { - return Math.floor(min + Math.random() * (max - min + 1)); - }, - - roundToPlaces: function(value, places) { - var mult = Math.pow(10, places); - return Math.round(value * mult) / mult; - }, - - roundNearest: function(value, nearest) { - return Math.round(value / nearest) * nearest; - }, - - quadraticBezier: function(p0, p1, p2, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 2) * p0.x + - (1 - t) * 2 * t * p1.x + - t * t * p2.x; - pFinal.y = Math.pow(1 - t, 2) * p0.y + - (1 - t) * 2 * t * p1.y + - t * t * p2.y; - return pFinal; - }, - - cubicBezier: function(p0, p1, p2, p3, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 3) * p0.x + - Math.pow(1 - t, 2) * 3 * t * p1.x + - (1 - t) * 3 * t * t * p2.x + - t * t * t * p3.x; - pFinal.y = Math.pow(1 - t, 3) * p0.y + - Math.pow(1 - t, 2) * 3 * t * p1.y + - (1 - t) * 3 * t * t * p2.y + - t * t * t * p3.y; - return pFinal; - }, - - multicurve: function(points, context) { - var p0, p1, midx, midy; - - context.moveTo(points[0].x, points[0].y); - - for(var i = 1; i < points.length - 2; i += 1) { - p0 = points[i]; - p1 = points[i + 1]; - midx = (p0.x + p1.x) / 2; - midy = (p0.y + p1.y) / 2; - context.quadraticCurveTo(p0.x, p0.y, midx, midy); - } - p0 = points[points.length - 2]; - p1 = points[points.length - 1]; - context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + }, + + multicurve: function(points, context) { + var p0, p1, midx, midy; + + context.moveTo(points[0].x, points[0].y); + + for(var i = 1; i < points.length - 2; i += 1) { + p0 = points[i]; + p1 = points[i + 1]; + midx = (p0.x + p1.x) / 2; + midy = (p0.y + p1.y) / 2; + context.quadraticCurveTo(p0.x, p0.y, midx, midy); + } + p0 = points[points.length - 2]; + p1 = points[points.length - 1]; + context.quadraticCurveTo(p0.x, p0.y, p1.x, p1.y); + } + } \ No newline at end of file diff --git a/episode3/index.html b/episode3/index.html index 0693f9f..aa8bb25 100644 --- a/episode3/index.html +++ b/episode3/index.html @@ -1,18 +1,18 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/episode3/trig02.js b/episode3/trig02.js index 5b4e8f8..5dcfb64 100644 --- a/episode3/trig02.js +++ b/episode3/trig02.js @@ -1,30 +1,30 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - var centerY = height * .5, - centerX = width * .5, - baseAlpha = 0.5, - offset = 0.5, - speed = 0.1, - angle = 0; - - render(); - - function render() { - var alpha = baseAlpha + Math.sin(angle) * offset; - - context.fillStyle = "rgba(0, 0, 0, " + alpha + ")"; - - context.clearRect(0, 0, width, height); - context.beginPath(); - context.arc(centerX, centerY, 100, 0, Math.PI * 2, false); - context.fill(); - - angle += speed; - - requestAnimationFrame(render); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var centerY = height * .5, + centerX = width * .5, + baseAlpha = 0.5, + offset = 0.5, + speed = 0.1, + angle = 0; + + render(); + + function render() { + var alpha = baseAlpha + Math.sin(angle) * offset; + + context.fillStyle = "rgba(0, 0, 0, " + alpha + ")"; + + context.clearRect(0, 0, width, height); + context.beginPath(); + context.arc(centerX, centerY, 100, 0, Math.PI * 2, false); + context.fill(); + + angle += speed; + + requestAnimationFrame(render); + } }; \ No newline at end of file diff --git a/episode30/index.html b/episode30/index.html index b827fdb..0e26dca 100644 --- a/episode30/index.html +++ b/episode30/index.html @@ -1,23 +1,23 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/episode30/tweenBasic.js b/episode30/tweenBasic.js index cdaa484..d3f2c83 100644 --- a/episode30/tweenBasic.js +++ b/episode30/tweenBasic.js @@ -1,71 +1,71 @@ - -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - ball = { - x: 100, - y: 100, - alpha: 1 - }; - - tween(ball, "alpha", 0, 1000, easeInOutQuad); - - function tween(obj, prop, target, duration, easingFunc) { - var start = obj[prop], - change = target - start, - startTime = new Date(); - - update(); - - function update() { - var time = new Date() - startTime; - if(time < duration) { - obj[prop] = easingFunc(time, start, change, duration); - requestAnimationFrame(update); - } - else { - time = duration; - obj[prop] = easingFunc(time, start, change, duration); - } - render(); - } - } - - - function render() { - context.clearRect(0, 0, width, height); - context.globalAlpha = ball.alpha; - context.beginPath(); - context.arc(ball.x, ball.y, 20, 0, Math.PI * 2, false); - context.fill(); - } - - - // simple linear tweening - no easing - // t: current time, b: beginning value, c: change in value, d: duration - function linearTween(t, b, c, d) { - return c * t / d + b; - } - - ///////////// QUADRATIC EASING: t^2 /////////////////// - - // quadratic easing in - accelerating from zero velocity - // t: current time, b: beginning value, c: change in value, d: duration - // t and d can be in frames or seconds/milliseconds - function easeInQuad(t, b, c, d) { - return c*(t/=d)*t + b; - }; - - // quadratic easing out - decelerating to zero velocity - function easeOutQuad(t, b, c, d) { - return -c *(t/=d)*(t-2) + b; - }; - - // quadratic easing in/out - acceleration until halfway, then deceleration - function easeInOutQuad(t, b, c, d) { - if ((t/=d/2) < 1) return c/2*t*t + b; - return -c/2 * ((--t)*(t-2) - 1) + b; - }; + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + ball = { + x: 100, + y: 100, + alpha: 1 + }; + + tween(ball, "alpha", 0, 1000, easeInOutQuad); + + function tween(obj, prop, target, duration, easingFunc) { + var start = obj[prop], + change = target - start, + startTime = new Date(); + + update(); + + function update() { + var time = new Date() - startTime; + if(time < duration) { + obj[prop] = easingFunc(time, start, change, duration); + requestAnimationFrame(update); + } + else { + time = duration; + obj[prop] = easingFunc(time, start, change, duration); + } + render(); + } + } + + + function render() { + context.clearRect(0, 0, width, height); + context.globalAlpha = ball.alpha; + context.beginPath(); + context.arc(ball.x, ball.y, 20, 0, Math.PI * 2, false); + context.fill(); + } + + + // simple linear tweening - no easing + // t: current time, b: beginning value, c: change in value, d: duration + function linearTween(t, b, c, d) { + return c * t / d + b; + } + + ///////////// QUADRATIC EASING: t^2 /////////////////// + + // quadratic easing in - accelerating from zero velocity + // t: current time, b: beginning value, c: change in value, d: duration + // t and d can be in frames or seconds/milliseconds + function easeInQuad(t, b, c, d) { + return c*(t/=d)*t + b; + }; + + // quadratic easing out - decelerating to zero velocity + function easeOutQuad(t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + }; + + // quadratic easing in/out - acceleration until halfway, then deceleration + function easeInOutQuad(t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + }; }; \ No newline at end of file diff --git a/episode30/tweenFull.js b/episode30/tweenFull.js index e7599f7..950d02f 100644 --- a/episode30/tweenFull.js +++ b/episode30/tweenFull.js @@ -1,85 +1,85 @@ - -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - ball = { - x: 100, - y: 100, - alpha: 1 - }; - - tween(ball, {x: 900, y: 700, alpha: 0 }, 1000, easeInOutQuad, render, tweenBack); - - function tweenBack() { - tween(ball, {x: 100, y: 100, alpha: 1 }, 1000, easeInOutQuad, render, render); - } - - function tween(obj, props, duration, easingFunc, onProgress, onComplete) { - var starts = {}, - changes = {}, - startTime = new Date(); - - for(var prop in props) { - starts[prop] = obj[prop]; - changes[prop] = props[prop] - starts[prop]; - } - - update(); - - function update() { - var time = new Date() - startTime; - if(time < duration) { - for(var prop in props) { - obj[prop] = easingFunc(time, starts[prop], changes[prop], duration); - } - onProgress(); - requestAnimationFrame(update); - } - else { - time = duration; - for(var prop in props) { - obj[prop] = easingFunc(time, starts[prop], changes[prop], duration); - } - onComplete(); - } - } - } - - - function render() { - context.clearRect(0, 0, width, height); - context.globalAlpha = ball.alpha; - context.beginPath(); - context.arc(ball.x, ball.y, 20, 0, Math.PI * 2, false); - context.fill(); - } - - - // simple linear tweening - no easing - // t: current time, b: beginning value, c: change in value, d: duration - function linearTween(t, b, c, d) { - return c * t / d + b; - } - - ///////////// QUADRATIC EASING: t^2 /////////////////// - - // quadratic easing in - accelerating from zero velocity - // t: current time, b: beginning value, c: change in value, d: duration - // t and d can be in frames or seconds/milliseconds - function easeInQuad(t, b, c, d) { - return c*(t/=d)*t + b; - }; - - // quadratic easing out - decelerating to zero velocity - function easeOutQuad(t, b, c, d) { - return -c *(t/=d)*(t-2) + b; - }; - - // quadratic easing in/out - acceleration until halfway, then deceleration - function easeInOutQuad(t, b, c, d) { - if ((t/=d/2) < 1) return c/2*t*t + b; - return -c/2 * ((--t)*(t-2) - 1) + b; - }; + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + ball = { + x: 100, + y: 100, + alpha: 1 + }; + + tween(ball, {x: 900, y: 700, alpha: 0 }, 1000, easeInOutQuad, render, tweenBack); + + function tweenBack() { + tween(ball, {x: 100, y: 100, alpha: 1 }, 1000, easeInOutQuad, render, render); + } + + function tween(obj, props, duration, easingFunc, onProgress, onComplete) { + var starts = {}, + changes = {}, + startTime = new Date(); + + for(var prop in props) { + starts[prop] = obj[prop]; + changes[prop] = props[prop] - starts[prop]; + } + + update(); + + function update() { + var time = new Date() - startTime; + if(time < duration) { + for(var prop in props) { + obj[prop] = easingFunc(time, starts[prop], changes[prop], duration); + } + onProgress(); + requestAnimationFrame(update); + } + else { + time = duration; + for(var prop in props) { + obj[prop] = easingFunc(time, starts[prop], changes[prop], duration); + } + onComplete(); + } + } + } + + + function render() { + context.clearRect(0, 0, width, height); + context.globalAlpha = ball.alpha; + context.beginPath(); + context.arc(ball.x, ball.y, 20, 0, Math.PI * 2, false); + context.fill(); + } + + + // simple linear tweening - no easing + // t: current time, b: beginning value, c: change in value, d: duration + function linearTween(t, b, c, d) { + return c * t / d + b; + } + + ///////////// QUADRATIC EASING: t^2 /////////////////// + + // quadratic easing in - accelerating from zero velocity + // t: current time, b: beginning value, c: change in value, d: duration + // t and d can be in frames or seconds/milliseconds + function easeInQuad(t, b, c, d) { + return c*(t/=d)*t + b; + }; + + // quadratic easing out - decelerating to zero velocity + function easeOutQuad(t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + }; + + // quadratic easing in/out - acceleration until halfway, then deceleration + function easeInOutQuad(t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + }; }; \ No newline at end of file diff --git a/episode30/tweenx.js b/episode30/tweenx.js index b2c2642..80e46d6 100644 --- a/episode30/tweenx.js +++ b/episode30/tweenx.js @@ -1,69 +1,69 @@ - -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - ball = { - x: 100, - y: 100 - }; - - tweenX(ball, 800, 1000, easeInOutQuad); - - function tweenX(obj, targetX, duration, easingFunc) { - var startX = obj.x, - changeX = targetX - startX, - startTime = new Date(); - - update(); - - function update() { - var time = new Date() - startTime; - if(time < duration) { - obj.x = easingFunc(time, startX, changeX, duration); - requestAnimationFrame(update); - } - else { - time = duration; - obj.x = easingFunc(time, startX, changeX, duration); - } - render(); - } - } - - - function render() { - context.clearRect(0, 0, width, height); - context.beginPath(); - context.arc(ball.x, ball.y, 20, 0, Math.PI * 2, false); - context.fill(); - } - - - // simple linear tweening - no easing - // t: current time, b: beginning value, c: change in value, d: duration - function linearTween(t, b, c, d) { - return c * t / d + b; - } - - ///////////// QUADRATIC EASING: t^2 /////////////////// - - // quadratic easing in - accelerating from zero velocity - // t: current time, b: beginning value, c: change in value, d: duration - // t and d can be in frames or seconds/milliseconds - function easeInQuad(t, b, c, d) { - return c*(t/=d)*t + b; - }; - - // quadratic easing out - decelerating to zero velocity - function easeOutQuad(t, b, c, d) { - return -c *(t/=d)*(t-2) + b; - }; - - // quadratic easing in/out - acceleration until halfway, then deceleration - function easeInOutQuad(t, b, c, d) { - if ((t/=d/2) < 1) return c/2*t*t + b; - return -c/2 * ((--t)*(t-2) - 1) + b; - }; + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + ball = { + x: 100, + y: 100 + }; + + tweenX(ball, 800, 1000, easeInOutQuad); + + function tweenX(obj, targetX, duration, easingFunc) { + var startX = obj.x, + changeX = targetX - startX, + startTime = new Date(); + + update(); + + function update() { + var time = new Date() - startTime; + if(time < duration) { + obj.x = easingFunc(time, startX, changeX, duration); + requestAnimationFrame(update); + } + else { + time = duration; + obj.x = easingFunc(time, startX, changeX, duration); + } + render(); + } + } + + + function render() { + context.clearRect(0, 0, width, height); + context.beginPath(); + context.arc(ball.x, ball.y, 20, 0, Math.PI * 2, false); + context.fill(); + } + + + // simple linear tweening - no easing + // t: current time, b: beginning value, c: change in value, d: duration + function linearTween(t, b, c, d) { + return c * t / d + b; + } + + ///////////// QUADRATIC EASING: t^2 /////////////////// + + // quadratic easing in - accelerating from zero velocity + // t: current time, b: beginning value, c: change in value, d: duration + // t and d can be in frames or seconds/milliseconds + function easeInQuad(t, b, c, d) { + return c*(t/=d)*t + b; + }; + + // quadratic easing out - decelerating to zero velocity + function easeOutQuad(t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + }; + + // quadratic easing in/out - acceleration until halfway, then deceleration + function easeInOutQuad(t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + }; }; \ No newline at end of file diff --git a/episode32/index.html b/episode32/index.html index 5989d5a..b211694 100644 --- a/episode32/index.html +++ b/episode32/index.html @@ -1,23 +1,23 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/episode32/main.js b/episode32/main.js index fd14089..012edb5 100644 --- a/episode32/main.js +++ b/episode32/main.js @@ -1,55 +1,55 @@ - -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - var p0 = { - x: 100, - y: 100 - }, - p1 = { - x: 500, - y: 500 - }, - p2 = { - x: 600, - y: 50 - }, - p3 = { - x: 80, - y: 600 - }; - - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.lineTo(p1.x, p1.y); - context.moveTo(p2.x, p2.y); - context.lineTo(p3.x, p3.y); - context.stroke(); - - var intersect = lineIntersect(p0, p1, p2, p3); - - context.beginPath(); - context.arc(intersect.x, intersect.y, 20, 0, Math.PI * 2, false); - context.stroke(); - - - - function lineIntersect(p0, p1, p2, p3) { - var A1 = p1.y - p0.y, - B1 = p0.x - p1.x, - C1 = A1 * p0.x + B1 * p0.y, - A2 = p3.y - p2.y, - B2 = p2.x - p3.x, - C2 = A2 * p2.x + B2 * p2.y, - denominator = A1 * B2 - A2 * B1; - - return { - x: (B2 * C1 - B1 * C2) / denominator, - y: (A1 * C2 - A2 * C1) / denominator - } - } - + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var p0 = { + x: 100, + y: 100 + }, + p1 = { + x: 500, + y: 500 + }, + p2 = { + x: 600, + y: 50 + }, + p3 = { + x: 80, + y: 600 + }; + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.moveTo(p2.x, p2.y); + context.lineTo(p3.x, p3.y); + context.stroke(); + + var intersect = lineIntersect(p0, p1, p2, p3); + + context.beginPath(); + context.arc(intersect.x, intersect.y, 20, 0, Math.PI * 2, false); + context.stroke(); + + + + function lineIntersect(p0, p1, p2, p3) { + var A1 = p1.y - p0.y, + B1 = p0.x - p1.x, + C1 = A1 * p0.x + B1 * p0.y, + A2 = p3.y - p2.y, + B2 = p2.x - p3.x, + C2 = A2 * p2.x + B2 * p2.y, + denominator = A1 * B2 - A2 * B1; + + return { + x: (B2 * C1 - B1 * C2) / denominator, + y: (A1 * C2 - A2 * C1) / denominator + } + } + }; \ No newline at end of file diff --git a/episode32/main_interactive.js b/episode32/main_interactive.js index 2f67db2..25d9c66 100644 --- a/episode32/main_interactive.js +++ b/episode32/main_interactive.js @@ -1,108 +1,108 @@ - -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - var p0 = { - x: 100, - y: 100 - }, - p1 = { - x: 500, - y: 500 - }, - p2 = { - x: 600, - y: 50 - }, - p3 = { - x: 80, - y: 600 - }, - clickPoint; - - document.body.addEventListener("mousedown", onMouseDown); - - function onMouseDown(event) { - clickPoint = getClickPoint(event.clientX, event.clientY); - if(clickPoint) { - document.body.addEventListener("mousemove", onMouseMove); - document.body.addEventListener("mouseup", onMouseUp); - } - } - - function onMouseMove(event) { - clickPoint.x = event.clientX; - clickPoint.y = event.clientY; - render(); - } - - function onMouseUp(event) { - document.body.removeEventListener("mousemove", onMouseMove); - document.body.removeEventListener("mouseup", onMouseUp); - } - - function getClickPoint(x, y) { - var points = [p0, p1, p2, p3]; - for(var i = 0; i < points.length; i++) { - var p = points[i], - dx = p.x - x, - dy = p.y - y, - dist = Math.sqrt(dx * dx + dy * dy); - if(dist < 10) { - return p; - } - - } - } - - - render(); - - function render() { - context.clearRect(0, 0, width, height); - - drawPoint(p0); - drawPoint(p1); - drawPoint(p2); - drawPoint(p3); - - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.lineTo(p1.x, p1.y); - context.moveTo(p2.x, p2.y); - context.lineTo(p3.x, p3.y); - context.stroke(); - - var intersect = lineIntersect(p0, p1, p2, p3); - - context.beginPath(); - context.arc(intersect.x, intersect.y, 20, 0, Math.PI * 2, false); - context.stroke(); - } - - function drawPoint(p) { - context.beginPath(); - context.arc(p.x, p.y, 10, 0, Math.PI * 2, false); - context.fill(); - } - - - function lineIntersect(p0, p1, p2, p3) { - var A1 = p1.y - p0.y, - B1 = p0.x - p1.x, - C1 = A1 * p0.x + B1 * p0.y, - A2 = p3.y - p2.y, - B2 = p2.x - p3.x, - C2 = A2 * p2.x + B2 * p2.y, - denominator = A1 * B2 - A2 * B1; - - return { - x: (B2 * C1 - B1 * C2) / denominator, - y: (A1 * C2 - A2 * C1) / denominator - } - } - + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var p0 = { + x: 100, + y: 100 + }, + p1 = { + x: 500, + y: 500 + }, + p2 = { + x: 600, + y: 50 + }, + p3 = { + x: 80, + y: 600 + }, + clickPoint; + + document.body.addEventListener("mousedown", onMouseDown); + + function onMouseDown(event) { + clickPoint = getClickPoint(event.clientX, event.clientY); + if(clickPoint) { + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + } + } + + function onMouseMove(event) { + clickPoint.x = event.clientX; + clickPoint.y = event.clientY; + render(); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + } + + function getClickPoint(x, y) { + var points = [p0, p1, p2, p3]; + for(var i = 0; i < points.length; i++) { + var p = points[i], + dx = p.x - x, + dy = p.y - y, + dist = Math.sqrt(dx * dx + dy * dy); + if(dist < 10) { + return p; + } + + } + } + + + render(); + + function render() { + context.clearRect(0, 0, width, height); + + drawPoint(p0); + drawPoint(p1); + drawPoint(p2); + drawPoint(p3); + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.moveTo(p2.x, p2.y); + context.lineTo(p3.x, p3.y); + context.stroke(); + + var intersect = lineIntersect(p0, p1, p2, p3); + + context.beginPath(); + context.arc(intersect.x, intersect.y, 20, 0, Math.PI * 2, false); + context.stroke(); + } + + function drawPoint(p) { + context.beginPath(); + context.arc(p.x, p.y, 10, 0, Math.PI * 2, false); + context.fill(); + } + + + function lineIntersect(p0, p1, p2, p3) { + var A1 = p1.y - p0.y, + B1 = p0.x - p1.x, + C1 = A1 * p0.x + B1 * p0.y, + A2 = p3.y - p2.y, + B2 = p2.x - p3.x, + C2 = A2 * p2.x + B2 * p2.y, + denominator = A1 * B2 - A2 * B1; + + return { + x: (B2 * C1 - B1 * C2) / denominator, + y: (A1 * C2 - A2 * C1) / denominator + } + } + }; \ No newline at end of file diff --git a/episode33/index.html b/episode33/index.html index 0c87fbf..6a1d2b2 100644 --- a/episode33/index.html +++ b/episode33/index.html @@ -1,23 +1,23 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/episode33/main_interactive.js b/episode33/main_interactive.js index 4017e74..5007ff3 100644 --- a/episode33/main_interactive.js +++ b/episode33/main_interactive.js @@ -1,145 +1,145 @@ - -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - var p0 = { - x: 100, - y: 100 - }, - p1 = { - x: 500, - y: 500 - }, - p2 = { - x: 600, - y: 50 - }, - p3 = { - x: 80, - y: 600 - }, - clickPoint; - - document.body.addEventListener("mousedown", onMouseDown); - - function onMouseDown(event) { - clickPoint = getClickPoint(event.clientX, event.clientY); - if(clickPoint) { - document.body.addEventListener("mousemove", onMouseMove); - document.body.addEventListener("mouseup", onMouseUp); - } - } - - function onMouseMove(event) { - clickPoint.x = event.clientX; - clickPoint.y = event.clientY; - render(); - } - - function onMouseUp(event) { - document.body.removeEventListener("mousemove", onMouseMove); - document.body.removeEventListener("mouseup", onMouseUp); - } - - function getClickPoint(x, y) { - var points = [p0, p1, p2, p3]; - for(var i = 0; i < points.length; i++) { - var p = points[i], - dx = p.x - x, - dy = p.y - y, - dist = Math.sqrt(dx * dx + dy * dy); - if(dist < 10) { - return p; - } - - } - } - - - render(); - - function render() { - context.clearRect(0, 0, width, height); - - drawPoint(p0); - drawPoint(p1); - drawPoint(p2); - drawPoint(p3); - - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.lineTo(p1.x, p1.y); - context.moveTo(p2.x, p2.y); - context.lineTo(p3.x, p3.y); - context.stroke(); - - var intersect = segmentIntersect(p0, p1, p2, p3); - if(intersect) { - context.beginPath(); - context.arc(intersect.x, intersect.y, 20, 0, Math.PI * 2, false); - context.stroke(); - } - } - - function drawPoint(p) { - context.beginPath(); - context.arc(p.x, p.y, 10, 0, Math.PI * 2, false); - context.fill(); - } - - - function lineIntersect(p0, p1, p2, p3) { - var A1 = p1.y - p0.y, - B1 = p0.x - p1.x, - C1 = A1 * p0.x + B1 * p0.y, - A2 = p3.y - p2.y, - B2 = p2.x - p3.x, - C2 = A2 * p2.x + B2 * p2.y, - denominator = A1 * B2 - A2 * B1; - - if(denominator == 0) { - return null; - } - - return { - x: (B2 * C1 - B1 * C2) / denominator, - y: (A1 * C2 - A2 * C1) / denominator - } - } - - - function segmentIntersect(p0, p1, p2, p3) { - var A1 = p1.y - p0.y, - B1 = p0.x - p1.x, - C1 = A1 * p0.x + B1 * p0.y, - A2 = p3.y - p2.y, - B2 = p2.x - p3.x, - C2 = A2 * p2.x + B2 * p2.y, - denominator = A1 * B2 - A2 * B1; - - if(denominator == 0) { - return null; - } - - var intersectX = (B2 * C1 - B1 * C2) / denominator, - intersectY = (A1 * C2 - A2 * C1) / denominator, - rx0 = (intersectX - p0.x) / (p1.x - p0.x), - ry0 = (intersectY - p0.y) / (p1.y - p0.y), - rx1 = (intersectX - p2.x) / (p3.x - p2.x), - ry1 = (intersectY - p2.y) / (p3.y - p2.y); - - if(((rx0 >= 0 && rx0 <= 1) || (ry0 >= 0 && ry0 <= 1)) && - ((rx1 >= 0 && rx1 <= 1) || (ry1 >= 0 && ry1 <= 1))) { - return { - x: intersectX, - y: intersectY - }; - } - else { - return null; - } - } + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var p0 = { + x: 100, + y: 100 + }, + p1 = { + x: 500, + y: 500 + }, + p2 = { + x: 600, + y: 50 + }, + p3 = { + x: 80, + y: 600 + }, + clickPoint; + + document.body.addEventListener("mousedown", onMouseDown); + + function onMouseDown(event) { + clickPoint = getClickPoint(event.clientX, event.clientY); + if(clickPoint) { + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + } + } + + function onMouseMove(event) { + clickPoint.x = event.clientX; + clickPoint.y = event.clientY; + render(); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + } + + function getClickPoint(x, y) { + var points = [p0, p1, p2, p3]; + for(var i = 0; i < points.length; i++) { + var p = points[i], + dx = p.x - x, + dy = p.y - y, + dist = Math.sqrt(dx * dx + dy * dy); + if(dist < 10) { + return p; + } + + } + } + + + render(); + + function render() { + context.clearRect(0, 0, width, height); + + drawPoint(p0); + drawPoint(p1); + drawPoint(p2); + drawPoint(p3); + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.moveTo(p2.x, p2.y); + context.lineTo(p3.x, p3.y); + context.stroke(); + + var intersect = segmentIntersect(p0, p1, p2, p3); + if(intersect) { + context.beginPath(); + context.arc(intersect.x, intersect.y, 20, 0, Math.PI * 2, false); + context.stroke(); + } + } + + function drawPoint(p) { + context.beginPath(); + context.arc(p.x, p.y, 10, 0, Math.PI * 2, false); + context.fill(); + } + + + function lineIntersect(p0, p1, p2, p3) { + var A1 = p1.y - p0.y, + B1 = p0.x - p1.x, + C1 = A1 * p0.x + B1 * p0.y, + A2 = p3.y - p2.y, + B2 = p2.x - p3.x, + C2 = A2 * p2.x + B2 * p2.y, + denominator = A1 * B2 - A2 * B1; + + if(denominator == 0) { + return null; + } + + return { + x: (B2 * C1 - B1 * C2) / denominator, + y: (A1 * C2 - A2 * C1) / denominator + } + } + + + function segmentIntersect(p0, p1, p2, p3) { + var A1 = p1.y - p0.y, + B1 = p0.x - p1.x, + C1 = A1 * p0.x + B1 * p0.y, + A2 = p3.y - p2.y, + B2 = p2.x - p3.x, + C2 = A2 * p2.x + B2 * p2.y, + denominator = A1 * B2 - A2 * B1; + + if(denominator == 0) { + return null; + } + + var intersectX = (B2 * C1 - B1 * C2) / denominator, + intersectY = (A1 * C2 - A2 * C1) / denominator, + rx0 = (intersectX - p0.x) / (p1.x - p0.x), + ry0 = (intersectY - p0.y) / (p1.y - p0.y), + rx1 = (intersectX - p2.x) / (p3.x - p2.x), + ry1 = (intersectY - p2.y) / (p3.y - p2.y); + + if(((rx0 >= 0 && rx0 <= 1) || (ry0 >= 0 && ry0 <= 1)) && + ((rx1 >= 0 && rx1 <= 1) || (ry1 >= 0 && ry1 <= 1))) { + return { + x: intersectX, + y: intersectY + }; + } + else { + return null; + } + } }; \ No newline at end of file diff --git a/episode33/parallel.js b/episode33/parallel.js index 7b95020..729d701 100644 --- a/episode33/parallel.js +++ b/episode33/parallel.js @@ -1,59 +1,59 @@ - -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - var p0 = { - x: 100, - y: 100 - }, - p1 = { - x: 500, - y: 100 - }, - p2 = { - x: 100, - y: 200 - }, - p3 = { - x: 500, - y: 200 - }; - - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.lineTo(p1.x, p1.y); - context.moveTo(p2.x, p2.y); - context.lineTo(p3.x, p3.y); - context.stroke(); - - var intersect = lineIntersect(p0, p1, p2, p3); - if(intersect) { - context.beginPath(); - context.arc(intersect.x, intersect.y, 20, 0, Math.PI * 2, false); - context.stroke(); - } - - - function lineIntersect(p0, p1, p2, p3) { - var A1 = p1.y - p0.y, - B1 = p0.x - p1.x, - C1 = A1 * p0.x + B1 * p0.y, - A2 = p3.y - p2.y, - B2 = p2.x - p3.x, - C2 = A2 * p2.x + B2 * p2.y, - denominator = A1 * B2 - A2 * B1; - - if(denominator == 0) { - return null; - } - - return { - x: (B2 * C1 - B1 * C2) / denominator, - y: (A1 * C2 - A2 * C1) / denominator - } - } - + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var p0 = { + x: 100, + y: 100 + }, + p1 = { + x: 500, + y: 100 + }, + p2 = { + x: 100, + y: 200 + }, + p3 = { + x: 500, + y: 200 + }; + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.moveTo(p2.x, p2.y); + context.lineTo(p3.x, p3.y); + context.stroke(); + + var intersect = lineIntersect(p0, p1, p2, p3); + if(intersect) { + context.beginPath(); + context.arc(intersect.x, intersect.y, 20, 0, Math.PI * 2, false); + context.stroke(); + } + + + function lineIntersect(p0, p1, p2, p3) { + var A1 = p1.y - p0.y, + B1 = p0.x - p1.x, + C1 = A1 * p0.x + B1 * p0.y, + A2 = p3.y - p2.y, + B2 = p2.x - p3.x, + C2 = A2 * p2.x + B2 * p2.y, + denominator = A1 * B2 - A2 * B1; + + if(denominator == 0) { + return null; + } + + return { + x: (B2 * C1 - B1 * C2) / denominator, + y: (A1 * C2 - A2 * C1) / denominator + } + } + }; \ No newline at end of file diff --git a/episode34/index.html b/episode34/index.html index a65ae57..6ee2159 100644 --- a/episode34/index.html +++ b/episode34/index.html @@ -1,23 +1,23 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/episode34/particles.js b/episode34/particles.js index 6dba81e..5c94f8c 100644 --- a/episode34/particles.js +++ b/episode34/particles.js @@ -1,108 +1,108 @@ - -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - var particle = { - x: width / 2, - y: height / 2, - vx: Math.random() * 10 - 5, - vy: Math.random() * 10 - 5 - }, - - lines = []; - - for(var i = 0; i < 10; i++) { - lines[i] = { - p0: { - x: Math.random() * width, - y: Math.random() * height - }, - p1: { - x: Math.random() * width, - y: Math.random() * height - } - } - } - - update(); - - function update() { - context.clearRect(0, 0, width, height); - drawLines(); - - var p0 = { - x: particle.x, - y: particle.y - }; - particle.x += particle.vx; - particle.y += particle.vy; - context.fillRect(particle.x - 2, particle.y - 2, 4, 4); - - var p1 = { - x: particle.x, - y: particle.y - }; - - - for(var i = 0; i < lines.length; i++) { - var p2 = lines[i].p0, - p3 = lines[i].p1; - - var intersect = segmentIntersect(p0, p1, p2, p3); - if(intersect) { - context.beginPath(); - context.strokeStyle = "red"; - context.arc(intersect.x, intersect.y, 20, 0, Math.PI * 2, false); - context.stroke(); - return; - } - } - - - requestAnimationFrame(update); - } - - function drawLines() { - context.beginPath(); - for(var i = 0; i < lines.length; i++) { - context.moveTo(lines[i].p0.x, lines[i].p0.y); - context.lineTo(lines[i].p1.x, lines[i].p1.y); - } - context.stroke(); - } - - function segmentIntersect(p0, p1, p2, p3) { - var A1 = p1.y - p0.y, - B1 = p0.x - p1.x, - C1 = A1 * p0.x + B1 * p0.y, - A2 = p3.y - p2.y, - B2 = p2.x - p3.x, - C2 = A2 * p2.x + B2 * p2.y, - denominator = A1 * B2 - A2 * B1; - - if(denominator == 0) { - return null; - } - - var intersectX = (B2 * C1 - B1 * C2) / denominator, - intersectY = (A1 * C2 - A2 * C1) / denominator, - rx0 = (intersectX - p0.x) / (p1.x - p0.x), - ry0 = (intersectY - p0.y) / (p1.y - p0.y), - rx1 = (intersectX - p2.x) / (p3.x - p2.x), - ry1 = (intersectY - p2.y) / (p3.y - p2.y); - - if(((rx0 >= 0 && rx0 <= 1) || (ry0 >= 0 && ry0 <= 1)) && - ((rx1 >= 0 && rx1 <= 1) || (ry1 >= 0 && ry1 <= 1))) { - return { - x: intersectX, - y: intersectY - }; - } - else { - return null; - } - } + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var particle = { + x: width / 2, + y: height / 2, + vx: Math.random() * 10 - 5, + vy: Math.random() * 10 - 5 + }, + + lines = []; + + for(var i = 0; i < 10; i++) { + lines[i] = { + p0: { + x: Math.random() * width, + y: Math.random() * height + }, + p1: { + x: Math.random() * width, + y: Math.random() * height + } + } + } + + update(); + + function update() { + context.clearRect(0, 0, width, height); + drawLines(); + + var p0 = { + x: particle.x, + y: particle.y + }; + particle.x += particle.vx; + particle.y += particle.vy; + context.fillRect(particle.x - 2, particle.y - 2, 4, 4); + + var p1 = { + x: particle.x, + y: particle.y + }; + + + for(var i = 0; i < lines.length; i++) { + var p2 = lines[i].p0, + p3 = lines[i].p1; + + var intersect = segmentIntersect(p0, p1, p2, p3); + if(intersect) { + context.beginPath(); + context.strokeStyle = "red"; + context.arc(intersect.x, intersect.y, 20, 0, Math.PI * 2, false); + context.stroke(); + return; + } + } + + + requestAnimationFrame(update); + } + + function drawLines() { + context.beginPath(); + for(var i = 0; i < lines.length; i++) { + context.moveTo(lines[i].p0.x, lines[i].p0.y); + context.lineTo(lines[i].p1.x, lines[i].p1.y); + } + context.stroke(); + } + + function segmentIntersect(p0, p1, p2, p3) { + var A1 = p1.y - p0.y, + B1 = p0.x - p1.x, + C1 = A1 * p0.x + B1 * p0.y, + A2 = p3.y - p2.y, + B2 = p2.x - p3.x, + C2 = A2 * p2.x + B2 * p2.y, + denominator = A1 * B2 - A2 * B1; + + if(denominator == 0) { + return null; + } + + var intersectX = (B2 * C1 - B1 * C2) / denominator, + intersectY = (A1 * C2 - A2 * C1) / denominator, + rx0 = (intersectX - p0.x) / (p1.x - p0.x), + ry0 = (intersectY - p0.y) / (p1.y - p0.y), + rx1 = (intersectX - p2.x) / (p3.x - p2.x), + ry1 = (intersectY - p2.y) / (p3.y - p2.y); + + if(((rx0 >= 0 && rx0 <= 1) || (ry0 >= 0 && ry0 <= 1)) && + ((rx1 >= 0 && rx1 <= 1) || (ry1 >= 0 && ry1 <= 1))) { + return { + x: intersectX, + y: intersectY + }; + } + else { + return null; + } + } }; \ No newline at end of file diff --git a/episode34/shapes.js b/episode34/shapes.js index 3109bf4..c20f073 100644 --- a/episode34/shapes.js +++ b/episode34/shapes.js @@ -1,149 +1,149 @@ - -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - - - var star0 = { - x: 200, - y: 200, - points: [ - {x: 0, y: 0 }, - {x: 0, y: 0 }, - {x: 0, y: 0 }, - {x: 0, y: 0 }, - {x: 0, y: 0 }, - {x: 0, y: 0 }, - {x: 0, y: 0 }, - {x: 0, y: 0 }, - {x: 0, y: 0 }, - {x: 0, y: 0 } - ], - offset: [ - { x: 100, y: 0}, - { x: 40, y: 29}, - { x: 31, y: 95}, - { x: -15, y: 48}, - { x: -81, y: 59}, - { x: -50, y: 0}, - { x: -81, y: -59}, - { x: -15, y: -48}, - { x: 31, y: -95}, - { x: 40, y: -29} - ] - }; - var star1 = { - x: 600, - y: 500, - points: [ - {x: 0, y: 0 }, - {x: 0, y: 0 }, - {x: 0, y: 0 }, - {x: 0, y: 0 }, - {x: 0, y: 0 }, - {x: 0, y: 0 }, - {x: 0, y: 0 }, - {x: 0, y: 0 }, - {x: 0, y: 0 }, - {x: 0, y: 0 } - ], - offset: [ - { x: 100, y: 0}, - { x: 40, y: 29}, - { x: 31, y: 95}, - { x: -15, y: 48}, - { x: -81, y: 59}, - { x: -50, y: 0}, - { x: -81, y: -59}, - { x: -15, y: -48}, - { x: 31, y: -95}, - { x: 40, y: -29} - ] - }; - - document.body.addEventListener("mousemove", function(event) { - context.clearRect(0, 0, width, height); - star0.x = event.clientX; - star0.y = event.clientY; - updateStar(star0); - updateStar(star1); - if(checkStarCollision(star0, star1)) { - context.fillStyle = "red"; - } - else { - context.fillStyle = "black"; - } - drawStar(star0); - drawStar(star1); - }); - - function checkStarCollision(starA, starB) { - for(var i = 0; i < starA.points.length; i++) { - var p0 = starA.points[i], - p1 = starA.points[(i + 1) % starA.points.length]; - - for(var j = 0; j < starB.points.length; j++) { - var p2 = starB.points[j], - p3 = starB.points[(j + 1) % starB.points.length]; - - if(segmentIntersect(p0, p1, p2, p3)) { - return true; - } - } - } - return false; - } - - - function updateStar(star) { - for(var i = 0; i < star.points.length; i++) { - star.points[i].x = star.x + star.offset[i].x; - star.points[i].y = star.y + star.offset[i].y; - } - } - - function drawStar(star) { - context.beginPath(); - context.moveTo(star.points[0].x, star.points[0].y); - for(var i = 1; i < star.points.length; i++) { - context.lineTo(star.points[i].x, star.points[i].y); - } - context.closePath(); - context.fill(); - } - - function segmentIntersect(p0, p1, p2, p3) { - var A1 = p1.y - p0.y, - B1 = p0.x - p1.x, - C1 = A1 * p0.x + B1 * p0.y, - A2 = p3.y - p2.y, - B2 = p2.x - p3.x, - C2 = A2 * p2.x + B2 * p2.y, - denominator = A1 * B2 - A2 * B1; - - if(denominator == 0) { - return null; - } - - var intersectX = (B2 * C1 - B1 * C2) / denominator, - intersectY = (A1 * C2 - A2 * C1) / denominator, - rx0 = (intersectX - p0.x) / (p1.x - p0.x), - ry0 = (intersectY - p0.y) / (p1.y - p0.y), - rx1 = (intersectX - p2.x) / (p3.x - p2.x), - ry1 = (intersectY - p2.y) / (p3.y - p2.y); - - if(((rx0 >= 0 && rx0 <= 1) || (ry0 >= 0 && ry0 <= 1)) && - ((rx1 >= 0 && rx1 <= 1) || (ry1 >= 0 && ry1 <= 1))) { - return { - x: intersectX, - y: intersectY - }; - } - else { - return null; - } - } + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + + + var star0 = { + x: 200, + y: 200, + points: [ + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 } + ], + offset: [ + { x: 100, y: 0}, + { x: 40, y: 29}, + { x: 31, y: 95}, + { x: -15, y: 48}, + { x: -81, y: 59}, + { x: -50, y: 0}, + { x: -81, y: -59}, + { x: -15, y: -48}, + { x: 31, y: -95}, + { x: 40, y: -29} + ] + }; + var star1 = { + x: 600, + y: 500, + points: [ + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 }, + {x: 0, y: 0 } + ], + offset: [ + { x: 100, y: 0}, + { x: 40, y: 29}, + { x: 31, y: 95}, + { x: -15, y: 48}, + { x: -81, y: 59}, + { x: -50, y: 0}, + { x: -81, y: -59}, + { x: -15, y: -48}, + { x: 31, y: -95}, + { x: 40, y: -29} + ] + }; + + document.body.addEventListener("mousemove", function(event) { + context.clearRect(0, 0, width, height); + star0.x = event.clientX; + star0.y = event.clientY; + updateStar(star0); + updateStar(star1); + if(checkStarCollision(star0, star1)) { + context.fillStyle = "red"; + } + else { + context.fillStyle = "black"; + } + drawStar(star0); + drawStar(star1); + }); + + function checkStarCollision(starA, starB) { + for(var i = 0; i < starA.points.length; i++) { + var p0 = starA.points[i], + p1 = starA.points[(i + 1) % starA.points.length]; + + for(var j = 0; j < starB.points.length; j++) { + var p2 = starB.points[j], + p3 = starB.points[(j + 1) % starB.points.length]; + + if(segmentIntersect(p0, p1, p2, p3)) { + return true; + } + } + } + return false; + } + + + function updateStar(star) { + for(var i = 0; i < star.points.length; i++) { + star.points[i].x = star.x + star.offset[i].x; + star.points[i].y = star.y + star.offset[i].y; + } + } + + function drawStar(star) { + context.beginPath(); + context.moveTo(star.points[0].x, star.points[0].y); + for(var i = 1; i < star.points.length; i++) { + context.lineTo(star.points[i].x, star.points[i].y); + } + context.closePath(); + context.fill(); + } + + function segmentIntersect(p0, p1, p2, p3) { + var A1 = p1.y - p0.y, + B1 = p0.x - p1.x, + C1 = A1 * p0.x + B1 * p0.y, + A2 = p3.y - p2.y, + B2 = p2.x - p3.x, + C2 = A2 * p2.x + B2 * p2.y, + denominator = A1 * B2 - A2 * B1; + + if(denominator == 0) { + return null; + } + + var intersectX = (B2 * C1 - B1 * C2) / denominator, + intersectY = (A1 * C2 - A2 * C1) / denominator, + rx0 = (intersectX - p0.x) / (p1.x - p0.x), + ry0 = (intersectY - p0.y) / (p1.y - p0.y), + rx1 = (intersectX - p2.x) / (p3.x - p2.x), + ry1 = (intersectY - p2.y) / (p3.y - p2.y); + + if(((rx0 >= 0 && rx0 <= 1) || (ry0 >= 0 && ry0 <= 1)) && + ((rx1 >= 0 && rx1 <= 1) || (ry1 >= 0 && ry1 <= 1))) { + return { + x: intersectX, + y: intersectY + }; + } + else { + return null; + } + } }; \ No newline at end of file diff --git a/episode35/index.html b/episode35/index.html index 6a8460a..53e9646 100644 --- a/episode35/index.html +++ b/episode35/index.html @@ -1,23 +1,23 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/episode35/koch.js b/episode35/koch.js index 938491c..f4552b9 100644 --- a/episode35/koch.js +++ b/episode35/koch.js @@ -1,62 +1,62 @@ - -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - var p0 = { - x: 0, - y: -321 - }, - p1 = { - x: 278, - y: 160 - }, - p2 = { - x: -278, - y: 160 - }; - context.translate(width / 2, height / 2); - - koch(p0, p1, 5); - koch(p1, p2, 5); - koch(p2, p0, 5); - - function koch(p0, p1, limit) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y, - dist = Math.sqrt(dx * dx + dy * dy), - unit = dist / 3, - angle = Math.atan2(dy, dx), - pA = { - x: p0.x + dx / 3, - y: p0.y + dy / 3 - }, - pC = { - x: p1.x - dx / 3, - y: p1.y - dy / 3 - }, - pB = { - x: pA.x + Math.cos(angle - Math.PI / 3) * unit, - y: pA.y + Math.sin(angle - Math.PI / 3) * unit - }; - - if(limit > 0) { - koch(p0, pA, limit - 1); - koch(pA, pB, limit - 1); - koch(pB, pC, limit - 1); - koch(pC, p1, limit - 1); - } - else { - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.lineTo(pA.x, pA.y); - context.lineTo(pB.x, pB.y); - context.lineTo(pC.x, pC.y); - context.lineTo(p1.x, p1.y); - context.stroke(); - } - } - + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var p0 = { + x: 0, + y: -321 + }, + p1 = { + x: 278, + y: 160 + }, + p2 = { + x: -278, + y: 160 + }; + context.translate(width / 2, height / 2); + + koch(p0, p1, 5); + koch(p1, p2, 5); + koch(p2, p0, 5); + + function koch(p0, p1, limit) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y, + dist = Math.sqrt(dx * dx + dy * dy), + unit = dist / 3, + angle = Math.atan2(dy, dx), + pA = { + x: p0.x + dx / 3, + y: p0.y + dy / 3 + }, + pC = { + x: p1.x - dx / 3, + y: p1.y - dy / 3 + }, + pB = { + x: pA.x + Math.cos(angle - Math.PI / 3) * unit, + y: pA.y + Math.sin(angle - Math.PI / 3) * unit + }; + + if(limit > 0) { + koch(p0, pA, limit - 1); + koch(pA, pB, limit - 1); + koch(pB, pC, limit - 1); + koch(pC, p1, limit - 1); + } + else { + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(pA.x, pA.y); + context.lineTo(pB.x, pB.y); + context.lineTo(pC.x, pC.y); + context.lineTo(p1.x, p1.y); + context.stroke(); + } + } + }; \ No newline at end of file diff --git a/episode35/kochanimated.js b/episode35/kochanimated.js index 3dbe089..2f0c938 100644 --- a/episode35/kochanimated.js +++ b/episode35/kochanimated.js @@ -1,78 +1,78 @@ - -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - - - var p0 = { - x: 0, - y: -321 - }, - p1 = { - x: 278, - y: 160 - }, - p2 = { - x: -278, - y: 160 - }; - - var a = 0, - t; - - draw(); - - function draw() { - t = 1 / 3 + Math.sin(a += 0.02) * 1/6; - context.clearRect(0, 0, width, height); - context.save(); - context.translate(width / 2, height / 2); - koch(p0, p1, 5); - koch(p1, p2, 5); - koch(p2, p0, 5); - context.restore(); - requestAnimationFrame(draw); - } - - function koch(p0, p1, limit) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y, - dist = Math.sqrt(dx * dx + dy * dy), - unit = dist * t, - angle = Math.atan2(dy, dx), - pA = { - x: p0.x + dx * t, - y: p0.y + dy * t - }, - pC = { - x: p1.x - dx * t, - y: p1.y - dy * t - }, - pB = { - x: pA.x + Math.cos(angle - Math.PI * t) * unit, - y: pA.y + Math.sin(angle - Math.PI * t) * unit - }; - - - if(limit > 0) { - koch(p0, pA, limit - 1); - koch(pA, pB, limit - 1); - koch(pB, pC, limit - 1); - koch(pC, p1, limit - 1); - } - else { - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.lineTo(pA.x, pA.y); - context.lineTo(pB.x, pB.y); - context.lineTo(pC.x, pC.y); - context.lineTo(p1.x, p1.y); - context.stroke(); - } - } - - + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + + + var p0 = { + x: 0, + y: -321 + }, + p1 = { + x: 278, + y: 160 + }, + p2 = { + x: -278, + y: 160 + }; + + var a = 0, + t; + + draw(); + + function draw() { + t = 1 / 3 + Math.sin(a += 0.02) * 1/6; + context.clearRect(0, 0, width, height); + context.save(); + context.translate(width / 2, height / 2); + koch(p0, p1, 5); + koch(p1, p2, 5); + koch(p2, p0, 5); + context.restore(); + requestAnimationFrame(draw); + } + + function koch(p0, p1, limit) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y, + dist = Math.sqrt(dx * dx + dy * dy), + unit = dist * t, + angle = Math.atan2(dy, dx), + pA = { + x: p0.x + dx * t, + y: p0.y + dy * t + }, + pC = { + x: p1.x - dx * t, + y: p1.y - dy * t + }, + pB = { + x: pA.x + Math.cos(angle - Math.PI * t) * unit, + y: pA.y + Math.sin(angle - Math.PI * t) * unit + }; + + + if(limit > 0) { + koch(p0, pA, limit - 1); + koch(pA, pB, limit - 1); + koch(pB, pC, limit - 1); + koch(pC, p1, limit - 1); + } + else { + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(pA.x, pA.y); + context.lineTo(pB.x, pB.y); + context.lineTo(pC.x, pC.y); + context.lineTo(p1.x, p1.y); + context.stroke(); + } + } + + }; \ No newline at end of file diff --git a/episode35/sierpinski.js b/episode35/sierpinski.js index 5dabe8f..581efa0 100644 --- a/episode35/sierpinski.js +++ b/episode35/sierpinski.js @@ -1,56 +1,56 @@ - -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - context.translate(width / 2, height / 2); - var p0 = { - x: 0, - y: -321 - }, - p1 = { - x: 278, - y: 160 - }, - p2 = { - x: -278, - y: 160 - }; - - sierpinski(p0, p1, p2, 8); - - function sierpinski(p0, p1, p2, limit) { - if(limit > 0) { - var pA = { - x: (p0.x + p1.x) / 2, - y: (p0.y + p1.y) / 2 - }, - pB = { - x: (p1.x + p2.x) / 2, - y: (p1.y + p2.y) / 2 - }, - pC = { - x: (p2.x + p0.x) / 2, - y: (p2.y + p0.y) / 2 - }; - - sierpinski(p0, pA, pC, limit - 1); - sierpinski(pA, p1, pB, limit - 1); - sierpinski(pC, pB, p2, limit - 1); - } - else { - drawTriangle(p0, p1, p2); - } - } - - function drawTriangle(p0, p1, p2) { - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.lineTo(p1.x, p1.y); - context.lineTo(p2.x, p2.y); - context.fill(); - } - + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + context.translate(width / 2, height / 2); + var p0 = { + x: 0, + y: -321 + }, + p1 = { + x: 278, + y: 160 + }, + p2 = { + x: -278, + y: 160 + }; + + sierpinski(p0, p1, p2, 8); + + function sierpinski(p0, p1, p2, limit) { + if(limit > 0) { + var pA = { + x: (p0.x + p1.x) / 2, + y: (p0.y + p1.y) / 2 + }, + pB = { + x: (p1.x + p2.x) / 2, + y: (p1.y + p2.y) / 2 + }, + pC = { + x: (p2.x + p0.x) / 2, + y: (p2.y + p0.y) / 2 + }; + + sierpinski(p0, pA, pC, limit - 1); + sierpinski(pA, p1, pB, limit - 1); + sierpinski(pC, pB, p2, limit - 1); + } + else { + drawTriangle(p0, p1, p2); + } + } + + function drawTriangle(p0, p1, p2) { + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.lineTo(p2.x, p2.y); + context.fill(); + } + }; \ No newline at end of file diff --git a/episode35/twist.js b/episode35/twist.js index d2be611..ee43ef0 100644 --- a/episode35/twist.js +++ b/episode35/twist.js @@ -1,71 +1,71 @@ - -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - - - var p0 = { - x: 0, - y: -321 - }, - p1 = { - x: 278, - y: 160 - }, - p2 = { - x: -278, - y: 160 - }; - var a = 0, - b = 0, - r = 0, - tx, ty; - - draw(); - function draw() { - context.clearRect(0, 0, width, height); - context.save(); - context.translate(width / 2, height / 2); - context.rotate(r += 0.01); - tx = .5 + Math.sin(a += .045) * .25; - ty = .5 + Math.sin(b += .045) * .25; - sierpinski(p0, p1, p2, 7); - context.restore(); - requestAnimationFrame(draw); - } - - function sierpinski(p0, p1, p2, limit) { - if(limit > 0) { - var pA = { - x: p0.x + (p1.x - p0.x) * tx, - y: p0.y + (p1.y - p0.y) * ty - }, - pB = { - x: p1.x + (p2.x - p1.x) * tx, - y: p1.y + (p2.y - p1.y) * ty - }, - pC = { - x: p2.x + (p0.x - p2.x) * tx, - y: p2.y + (p0.y - p2.y) * ty - }; - sierpinski(p0, pA, pC, limit - 1); - sierpinski(pA, p1, pB, limit - 1); - sierpinski(pC, pB, p2, limit - 1); - } - else { - drawTriangle(p0, p1, p2); - } - } - - function drawTriangle(p0, p1, p2) { - context.beginPath(); - context.moveTo(p0.x, p0.y); - context.lineTo(p1.x, p1.y); - context.lineTo(p2.x, p2.y); - context.fill(); - } - + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + + + var p0 = { + x: 0, + y: -321 + }, + p1 = { + x: 278, + y: 160 + }, + p2 = { + x: -278, + y: 160 + }; + var a = 0, + b = 0, + r = 0, + tx, ty; + + draw(); + function draw() { + context.clearRect(0, 0, width, height); + context.save(); + context.translate(width / 2, height / 2); + context.rotate(r += 0.01); + tx = .5 + Math.sin(a += .045) * .25; + ty = .5 + Math.sin(b += .045) * .25; + sierpinski(p0, p1, p2, 7); + context.restore(); + requestAnimationFrame(draw); + } + + function sierpinski(p0, p1, p2, limit) { + if(limit > 0) { + var pA = { + x: p0.x + (p1.x - p0.x) * tx, + y: p0.y + (p1.y - p0.y) * ty + }, + pB = { + x: p1.x + (p2.x - p1.x) * tx, + y: p1.y + (p2.y - p1.y) * ty + }, + pC = { + x: p2.x + (p0.x - p2.x) * tx, + y: p2.y + (p0.y - p2.y) * ty + }; + sierpinski(p0, pA, pC, limit - 1); + sierpinski(pA, p1, pB, limit - 1); + sierpinski(pC, pB, p2, limit - 1); + } + else { + drawTriangle(p0, p1, p2); + } + } + + function drawTriangle(p0, p1, p2) { + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(p1.x, p1.y); + context.lineTo(p2.x, p2.y); + context.fill(); + } + }; \ No newline at end of file diff --git a/episode36/index.html b/episode36/index.html index 5989d5a..b211694 100644 --- a/episode36/index.html +++ b/episode36/index.html @@ -1,23 +1,23 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/episode36/main.js b/episode36/main.js index dd2b98c..b0b9c6d 100644 --- a/episode36/main.js +++ b/episode36/main.js @@ -1,70 +1,70 @@ - -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - var points = [], - bounce = 0.9, - gravity = 0.5, - friction = 0.999; - - points.push({ - x: 100, - y: 100, - oldx: 95, - oldy: 95 - }); - - - - update(); - - function update() { - updatePoints(); - renderPoints(); - requestAnimationFrame(update); - } - - function updatePoints() { - for(var i = 0; i < points.length; i++) { - var p = points[i], - vx = (p.x - p.oldx) * friction; - vy = (p.y - p.oldy) * friction; - - p.oldx = p.x; - p.oldy = p.y; - p.x += vx; - p.y += vy; - p.y += gravity; - - if(p.x > width) { - p.x = width; - p.oldx = p.x + vx * bounce; - } - else if(p.x < 0) { - p.x = 0; - p.oldx = p.x + vx * bounce; - } - if(p.y > height) { - p.y = height; - p.oldy = p.y + vy * bounce; - } - else if(p.y < 0) { - p.y = 0; - p.oldy = p.y + vy * bounce; - } - } - } - - function renderPoints() { - context.clearRect(0, 0, width, height); - for(var i = 0; i < points.length; i++) { - var p = points[i]; - context.beginPath(); - context.arc(p.x, p.y, 5, 0, Math.PI * 2); - context.fill(); - } - } + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var points = [], + bounce = 0.9, + gravity = 0.5, + friction = 0.999; + + points.push({ + x: 100, + y: 100, + oldx: 95, + oldy: 95 + }); + + + + update(); + + function update() { + updatePoints(); + renderPoints(); + requestAnimationFrame(update); + } + + function updatePoints() { + for(var i = 0; i < points.length; i++) { + var p = points[i], + vx = (p.x - p.oldx) * friction; + vy = (p.y - p.oldy) * friction; + + p.oldx = p.x; + p.oldy = p.y; + p.x += vx; + p.y += vy; + p.y += gravity; + + if(p.x > width) { + p.x = width; + p.oldx = p.x + vx * bounce; + } + else if(p.x < 0) { + p.x = 0; + p.oldx = p.x + vx * bounce; + } + if(p.y > height) { + p.y = height; + p.oldy = p.y + vy * bounce; + } + else if(p.y < 0) { + p.y = 0; + p.oldy = p.y + vy * bounce; + } + } + } + + function renderPoints() { + context.clearRect(0, 0, width, height); + for(var i = 0; i < points.length; i++) { + var p = points[i]; + context.beginPath(); + context.arc(p.x, p.y, 5, 0, Math.PI * 2); + context.fill(); + } + } }; \ No newline at end of file diff --git a/episode38/cat.jpg b/episode38/cat.jpg new file mode 100644 index 0000000000000000000000000000000000000000..140642815ad6a508f9fc3f697d32a77287502cbf GIT binary patch literal 46674 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

(3DQ)sU9J01=cAwqpYq)7C9Lx)-iJU+ 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 width) { + p.x = width; + p.oldx = p.x + vx * bounce; + } + else if(p.x < 0) { + p.x = 0; + p.oldx = p.x + vx * bounce; + } + if(p.y > height) { + p.y = height; + p.oldy = p.y + vy * bounce; + } + else if(p.y < 0) { + p.y = 0; + p.oldy = p.y + vy * bounce; + } + } + } + + function updateSticks() { + for(var i = 0; i < sticks.length; i++) { + var s = sticks[i], + dx = s.p1.x - s.p0.x, + dy = s.p1.y - s.p0.y, + distance = Math.sqrt(dx * dx + dy * dy), + difference = s.length - distance, + percent = difference / distance / 2, + offsetX = dx * percent, + offsetY = dy * percent; + + s.p0.x -= offsetX; + s.p0.y -= offsetY; + s.p1.x += offsetX; + s.p1.y += offsetY; + } + } + + function renderPoints() { + for(var i = 0; i < points.length; i++) { + var p = points[i]; + context.beginPath(); + context.arc(p.x, p.y, 5, 0, Math.PI * 2); + context.fill(); + } + } + + function renderSticks() { + for(var i = 0; i < sticks.length; i++) { + var s = sticks[i]; + if(!s.hidden) { + context.beginPath(); + context.strokeStyle = s.color ? s.color : "black"; + context.lineWidth = s.width ? s.width : 1; + context.moveTo(s.p0.x, s.p0.y); + context.lineTo(s.p1.x, s.p1.y); + context.stroke(); + } + } + } + + function renderForms() { + for(var i = 0; i < forms.length; i++) { + var f = forms[i]; + context.beginPath(); + context.fillStyle = f.color; + context.moveTo(f.path[0].x, f.path[0].y); + for(var j = 1; j < f.path.length; j++) { + context.lineTo(f.path[j].x, f.path[j].y); + } + context.fill(); + } + } + + function renderImages() { + for(var i = 0; i < images.length; i++) { + var img = images[i]; + if(img.img) { + context.save(); + context.translate(img.path[0].x, img.path[0].y); + + var w = distance(img.path[1], img.path[0]), + h = distance(img.path[3], img.path[0]), + dx = img.path[1].x - img.path[0].x, + dy = img.path[1].y - img.path[0].y, + angle = Math.atan2(dy, dx); + + context.rotate(angle); + context.drawImage(img.img, 0, 0, w, h); + context.restore(); + } + } + } + +}; \ No newline at end of file diff --git a/episode38/index.html b/episode38/index.html new file mode 100644 index 0000000..b211694 --- /dev/null +++ b/episode38/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/episode38/main.js b/episode38/main.js new file mode 100644 index 0000000..ae47f31 --- /dev/null +++ b/episode38/main.js @@ -0,0 +1,227 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var points = [], + sticks = [], + forms = [], + images = [], + bounce = 0.9, + gravity = 0.5, + friction = 0.999; + + points.push({ + x: 100, + y: 100, + oldx: 100 + Math.random() * 50 - 25, + oldy: 100 + Math.random() * 50 - 25 + }); + points.push({ + x: 200, + y: 100, + oldx: 200, + oldy: 100 + }); + points.push({ + x: 200, + y: 200, + oldx: 200, + oldy: 200 + }); + points.push({ + x: 100, + y: 200, + oldx: 100, + oldy: 200 + }); + + sticks.push({ + p0: points[0], + p1: points[1], + length: distance(points[0], points[1]), + color: "red", + width: 5 + }); + sticks.push({ + p0: points[1], + p1: points[2], + length: distance(points[1], points[2]) + }); + sticks.push({ + p0: points[2], + p1: points[3], + length: distance(points[2], points[3]) + }); + sticks.push({ + p0: points[3], + p1: points[0], + length: distance(points[3], points[0]) + }); + sticks.push({ + p0: points[0], + p1: points[2], + length: distance(points[0], points[2]), + hidden: true + }); + + forms.push({ + path: [ + points[0], + points[1], + points[2], + points[3] + ], + color: "green" + }); + + images.push({ + path: [ + points[0], + points[1], + points[2], + points[3] + ], + img: loadImage("cat.jpg") + }); + + function loadImage(url) { + var img = document.createElement("img"); + img.src = url; + return img; + } + + function distance(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + } + + update(); + + function update() { + updatePoints(); + for(var i = 0; i < 5; i++) { + updateSticks(); + constrainPoints(); + } + context.clearRect(0, 0, width, height); + // renderPoints(); + // renderSticks(); + renderForms(); + // renderImages(); + requestAnimationFrame(update); + } + + function updatePoints() { + for(var i = 0; i < points.length; i++) { + var p = points[i], + vx = (p.x - p.oldx) * friction; + vy = (p.y - p.oldy) * friction; + + p.oldx = p.x; + p.oldy = p.y; + p.x += vx; + p.y += vy; + p.y += gravity; + } + } + + function constrainPoints() { + for(var i = 0; i < points.length; i++) { + var p = points[i], + vx = (p.x - p.oldx) * friction; + vy = (p.y - p.oldy) * friction; + + if(p.x > width) { + p.x = width; + p.oldx = p.x + vx * bounce; + } + else if(p.x < 0) { + p.x = 0; + p.oldx = p.x + vx * bounce; + } + if(p.y > height) { + p.y = height; + p.oldy = p.y + vy * bounce; + } + else if(p.y < 0) { + p.y = 0; + p.oldy = p.y + vy * bounce; + } + } + } + + function updateSticks() { + for(var i = 0; i < sticks.length; i++) { + var s = sticks[i], + dx = s.p1.x - s.p0.x, + dy = s.p1.y - s.p0.y, + distance = Math.sqrt(dx * dx + dy * dy), + difference = s.length - distance, + percent = difference / distance / 2, + offsetX = dx * percent, + offsetY = dy * percent; + + s.p0.x -= offsetX; + s.p0.y -= offsetY; + s.p1.x += offsetX; + s.p1.y += offsetY; + } + } + + function renderPoints() { + for(var i = 0; i < points.length; i++) { + var p = points[i]; + context.beginPath(); + context.arc(p.x, p.y, 5, 0, Math.PI * 2); + context.fill(); + } + } + + function renderSticks() { + for(var i = 0; i < sticks.length; i++) { + var s = sticks[i]; + if(!s.hidden) { + context.beginPath(); + context.strokeStyle = s.color ? s.color : "black"; + context.lineWidth = s.width ? s.width : 1; + context.moveTo(s.p0.x, s.p0.y); + context.lineTo(s.p1.x, s.p1.y); + context.stroke(); + } + } + } + + function renderForms() { + for(var i = 0; i < forms.length; i++) { + var f = forms[i]; + context.beginPath(); + context.fillStyle = f.color; + context.moveTo(f.path[0].x, f.path[0].y); + for(var j = 1; j < f.path.length; j++) { + context.lineTo(f.path[j].x, f.path[j].y); + } + context.fill(); + } + } + + function renderImages() { + for(var i = 0; i < images.length; i++) { + var image = images[i], + w = distance(image.path[0], image.path[1]), + h = distance(image.path[0], image.path[3]), + dx = image.path[1].x - image.path[0].x, + dy = image.path[1].y - image.path[0].y, + angle = Math.atan2(dy, dx); + + context.save(); + context.translate(image.path[0].x, image.path[0].y); + context.rotate(angle); + context.drawImage(image.img, 0, 0, w, h); + context.restore(); + } + } +}; \ No newline at end of file diff --git a/episode38/ragdoll.js b/episode38/ragdoll.js new file mode 100644 index 0000000..42b312b --- /dev/null +++ b/episode38/ragdoll.js @@ -0,0 +1,262 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + var count = 0; + + var points = [], + sticks = []; + gravity = 0.25, + bounce = 0.9, + friction = 0.999; + + points.push({ + x: 90, + y: 100, + oldx: 90 + Math.random() * 20 - 10, + oldy: 100 + }); + points.push({ + x: 210, + y: 100, + oldx: 210, + oldy: 100 + }); + points.push({ + x: 200, + y: 300, + oldx: 200, + oldy: 300 + }); + points.push({ + x: 100, + y: 300, + oldx: 100, + oldy: 300 + }); + // arms + points.push({ + x: 10, + y: 170, + oldx: 10, + oldy: 170 + }); + points.push({ + x: 290, + y: 170, + oldx: 290, + oldy: 170 + }); + // legs + points.push({ + x: 70, + y: 400, + oldx: 70, + oldy: 400 + }); + points.push({ + x: 230, + y: 400, + oldx: 230, + oldy: 400 + }); + // hands + points.push({ + x: 10, + y: 230, + oldx: 10, + oldy: 230 + }); + points.push({ + x: 290, + y: 230, + oldx: 290, + oldy: 230 + }); + + sticks.push({ + p0: points[0], + p1: points[1], + length: distance(points[0], points[1]), + visible: true + }); + sticks.push({ + p0: points[1], + p1: points[2], + length: distance(points[1], points[2]), + visible: true + }); + sticks.push({ + p0: points[2], + p1: points[3], + length: distance(points[2], points[3]), + visible: true + }); + sticks.push({ + p0: points[3], + p1: points[0], + length: distance(points[3], points[0]), + visible: true + }); + sticks.push({ + p0: points[0], + p1: points[2], + length: distance(points[0], points[2]), + visible: false + }); + // arms + sticks.push({ + p0: points[0], + p1: points[4], + length: distance(points[0], points[4]), + visible: true + }); + // sticks.push({ + // p0: points[4], + // p1: points[1], + // length: distance(points[4], points[1]), + // visible: false + // }); + sticks.push({ + p0: points[1], + p1: points[5], + length: distance(points[1], points[5]), + visible: true + }); + // sticks.push({ + // p0: points[5], + // p1: points[0], + // length: distance(points[5], points[0]), + // visible: false + // }); + // legs + sticks.push({ + p0: points[3], + p1: points[6], + length: distance(points[3], points[6]), + visible: true + }); + sticks.push({ + p0: points[6], + p1: points[2], + length: distance(points[6], points[2]), + visible: false + }); + sticks.push({ + p0: points[2], + p1: points[7], + length: distance(points[2], points[7]), + visible: true + }); + sticks.push({ + p0: points[7], + p1: points[3], + length: distance(points[7], points[3]), + visible: false + }); + // arms + sticks.push({ + p0: points[4], + p1: points[8], + length: distance(points[4], points[8]), + visible: true + }); + sticks.push({ + p0: points[5], + p1: points[9], + length: distance(points[5], points[9]), + visible: true + }); + + + function distance(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + } + + + update(); + + function update() { + updatePoints(); + + for(var i = 0; i < 3; i++) { + updateSticks(); + constrainPoints(); + } + render(); + requestAnimationFrame(update); + } + + function updatePoints() { + for(var i = 0; i < points.length; i++) { + var p = points[i], + vx = (p.x - p.oldx) * friction; + vy = (p.y - p.oldy) * friction; + p.oldx = p.x; + p.oldy = p.y; + p.x += vx; + p.y += vy; + p.y += gravity; + } + } + + function constrainPoints() { + + for(var i = 0; i < points.length; i++) { + var p = points[i]; + if(p.x > width) { + p.x = width; + p.oldx = p.x + (p.x - p.oldx) * bounce; + } + else if(p.x < 0) { + p.x = 0; + p.oldx = p.x + (p.x - p.oldx) * bounce; + } + if(p.y > height) { + p.y = height; + p.oldy = p.y + (p.y - p.oldy) * bounce; + } + if(p.y < 0) { + p.y = 0; + p.oldy = p.y + (p.y - p.oldy) * bounce; + } + } + } + + function updateSticks() { + for(var i = 0; i < sticks.length; i++) { + var s = sticks[i], + dx = s.p1.x - s.p0.x, + dy = s.p1.y - s.p0.y, + dist = Math.sqrt(dx * dx + dy * dy); + ratio = s.length / dist, + midx = s.p0.x + dx / 2, + midy = s.p0.y + dy / 2, + offsetx = dx / 2 * ratio, + offsety = dy / 2 * ratio; + + s.p0.x = midx - offsetx; + s.p0.y = midy - offsety; + s.p1.x = midx + offsetx; + s.p1.y = midy + offsety; + } + } + + function render() { + context.clearRect(0, 0, width, height); + context.beginPath(); + for(var i = 0; i < sticks.length; i++) { + var s = sticks[i]; + if(s.visible) { + context.moveTo(s.p0.x, s.p0.y); + context.lineTo(s.p1.x, s.p1.y); + } + } + context.stroke(); + } + +}; \ No newline at end of file diff --git a/episode4/bees.js b/episode4/bees.js index fe75757..1a8d557 100644 --- a/episode4/bees.js +++ b/episode4/bees.js @@ -1,53 +1,53 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - bees = [], - numBees = 50; - - var bee = { - create: function() { - var obj = Object.create(this); - obj.init.apply(obj, arguments); - return obj; - }, - - init: function(foo, bar) { - console.log(foo, bar); - this.angleX = Math.random() * Math.PI * 2; - this.angleY = Math.random() * Math.PI * 2; - this.speedX = Math.random() * .1 - .05; - this.speedY = Math.random() * .1 - .05; - this.radius = 100 + Math.random() * 100; - }, - - update: function() { - var x = Math.cos(this.angleX) * this.radius, - y = Math.sin(this.angleY) * this.radius; - this.angleX += this.speedX; - this.angleY += this.speedY; - - context.beginPath(); - context.arc(width / 2 + x, height / 2 + y, 2, 0, Math.PI * 2, false); - context.fill(); - } - } - - for(var i = 0; i < numBees; i += 1) { - bees.push(bee.create("foo", "bar")); - } - - - draw(); - - function draw() { - context.clearRect(0, 0, width, height); - for(var i = 0; i < numBees; i += 1) { - bees[i].update(); - } - requestAnimationFrame(draw); - } - - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + bees = [], + numBees = 50; + + var bee = { + create: function() { + var obj = Object.create(this); + obj.init.apply(obj, arguments); + return obj; + }, + + init: function(foo, bar) { + console.log(foo, bar); + this.angleX = Math.random() * Math.PI * 2; + this.angleY = Math.random() * Math.PI * 2; + this.speedX = Math.random() * .1 - .05; + this.speedY = Math.random() * .1 - .05; + this.radius = 100 + Math.random() * 100; + }, + + update: function() { + var x = Math.cos(this.angleX) * this.radius, + y = Math.sin(this.angleY) * this.radius; + this.angleX += this.speedX; + this.angleY += this.speedY; + + context.beginPath(); + context.arc(width / 2 + x, height / 2 + y, 2, 0, Math.PI * 2, false); + context.fill(); + } + } + + for(var i = 0; i < numBees; i += 1) { + bees.push(bee.create("foo", "bar")); + } + + + draw(); + + function draw() { + context.clearRect(0, 0, width, height); + for(var i = 0; i < numBees; i += 1) { + bees[i].update(); + } + requestAnimationFrame(draw); + } + + } \ No newline at end of file diff --git a/episode4/circle.js b/episode4/circle.js index 538472c..1d63a86 100644 --- a/episode4/circle.js +++ b/episode4/circle.js @@ -1,25 +1,25 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - - centerX = width / 2, - centerY = height / 2, - radius = 200, - angle = 0, - numObjects = 20, - slice = Math.PI * 2 / numObjects, - x, y; - - for(var i = 0; i < numObjects; i += 1) { - angle = i * slice; - x = centerX + Math.cos(angle) * radius; - y = centerY + Math.sin(angle) * radius; - context.beginPath(); - context.arc(x, y, 10, 0, Math.PI * 2, false); - context.fill(); - } - - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + + centerX = width / 2, + centerY = height / 2, + radius = 200, + angle = 0, + numObjects = 20, + slice = Math.PI * 2 / numObjects, + x, y; + + for(var i = 0; i < numObjects; i += 1) { + angle = i * slice; + x = centerX + Math.cos(angle) * radius; + y = centerY + Math.sin(angle) * radius; + context.beginPath(); + context.arc(x, y, 10, 0, Math.PI * 2, false); + context.fill(); + } + + }; \ No newline at end of file diff --git a/episode4/code.js b/episode4/code.js index f59e09f..1ee936a 100644 --- a/episode4/code.js +++ b/episode4/code.js @@ -1,24 +1,24 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - xres = 10, - yres = 11; - - context.fillStyle = "black"; - context.fillRect(0, 0, width, height); - context.fillStyle = "green"; - context.font = "12px Courier"; - context.translate(width / 2, height / 2); - // context.scale(1.5, 1.5); - // context.rotate(.1); - context.transform(1.5, .3, 0.1, 1.5, 0, 0); - - for(var y = -height / 2; y < height / 2; y += yres) { - for(var x = -width / 2; x < width / 2; x += xres) { - var char = Math.random() < .5 ? "0" : "1"; - context.fillText(char, x, y); - } - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + xres = 10, + yres = 11; + + context.fillStyle = "black"; + context.fillRect(0, 0, width, height); + context.fillStyle = "green"; + context.font = "12px Courier"; + context.translate(width / 2, height / 2); + // context.scale(1.5, 1.5); + // context.rotate(.1); + context.transform(1.5, .3, 0.1, 1.5, 0, 0); + + for(var y = -height / 2; y < height / 2; y += yres) { + for(var x = -width / 2; x < width / 2; x += xres) { + var char = Math.random() < .5 ? "0" : "1"; + context.fillText(char, x, y); + } + } }; \ No newline at end of file diff --git a/episode4/index.html b/episode4/index.html index 5673050..fbd073d 100644 --- a/episode4/index.html +++ b/episode4/index.html @@ -1,18 +1,18 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/episode5/arctangent.js b/episode5/arctangent.js index 5983af2..2c9ed95 100644 --- a/episode5/arctangent.js +++ b/episode5/arctangent.js @@ -1,44 +1,44 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - arrowX = width / 2, - arrowY = height / 2, - dx, dy, - angle = 0, - a = 0; - - render(); - - function render() { - arrowX = width / 2 + Math.cos(a) * height * .4; - arrowY = height / 2 + Math.sin(a) * height * .4; - a += .01; - context.clearRect(0, 0, width, height); - - context.save(); - context.translate(arrowX, arrowY); - context.rotate(angle); - - context.beginPath(); - context.moveTo(20, 0); - context.lineTo(-20, 0); - context.moveTo(20, 0); - context.lineTo(10, -10); - context.moveTo(20, 0); - context.lineTo(10, 10); - context.stroke(); - - context.restore(); - requestAnimationFrame(render); - } - - document.body.addEventListener("mousemove", function(event) { - dx = event.clientX - arrowX; - dy = event.clientY - arrowY; - angle = Math.atan2(dy, dx); - }); - - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + arrowX = width / 2, + arrowY = height / 2, + dx, dy, + angle = 0, + a = 0; + + render(); + + function render() { + arrowX = width / 2 + Math.cos(a) * height * .4; + arrowY = height / 2 + Math.sin(a) * height * .4; + a += .01; + context.clearRect(0, 0, width, height); + + context.save(); + context.translate(arrowX, arrowY); + context.rotate(angle); + + context.beginPath(); + context.moveTo(20, 0); + context.lineTo(-20, 0); + context.moveTo(20, 0); + context.lineTo(10, -10); + context.moveTo(20, 0); + context.lineTo(10, 10); + context.stroke(); + + context.restore(); + requestAnimationFrame(render); + } + + document.body.addEventListener("mousemove", function(event) { + dx = event.clientX - arrowX; + dy = event.clientY - arrowY; + angle = Math.atan2(dy, dx); + }); + + }; \ No newline at end of file diff --git a/episode5/index.html b/episode5/index.html index 8dcf207..6252fb0 100644 --- a/episode5/index.html +++ b/episode5/index.html @@ -1,18 +1,18 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/episode7/vector.js b/episode7/vector.js index 609f6d5..4d66796 100644 --- a/episode7/vector.js +++ b/episode7/vector.js @@ -1,83 +1,83 @@ -var vector = { - _x: 1, - _y: 0, - - create: function(x, y) { - var obj = Object.create(this); - obj.setX(x); - obj.setY(y); - return obj; - }, - - setX: function(value) { - this._x = value; - }, - - getX: function() { - return this._x; - }, - - setY: function(value) { - this._y = value; - }, - - getY: function() { - return this._y; - }, - - setAngle: function(angle) { - var length = this.getLength(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getAngle: function() { - return Math.atan2(this._y, this._x); - }, - - setLength: function(length) { - var angle = this.getAngle(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getLength: function() { - return Math.sqrt(this._x * this._x + this._y * this._y); - }, - - add: function(v2) { - return vector.create(this._x + v2.getX(), this._y + v2.getY()); - }, - - subtract: function(v2) { - return vector.create(this._x - v2.getX(), this._y - v2.getY()); - }, - - multiply: function(val) { - return vector.create(this._x * val, this._y * val); - }, - - divide: function(val) { - return vector.create(this._x / val, this._y / val); - }, - - addTo: function(v2) { - this._x += v2.getX(); - this._y += v2.getY(); - }, - - subtractFrom: function(v2) { - this._x -= v2.getX(); - this._y -= v2.getY(); - }, - - multiplyBy: function(val) { - this._x *= val; - this._y *= val; - }, - - divideBy: function(val) { - this._x /= val; - this._y /= val; - } +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } }; \ No newline at end of file diff --git a/episode8/index.html b/episode8/index.html index f6702d7..532a094 100644 --- a/episode8/index.html +++ b/episode8/index.html @@ -1,22 +1,22 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/episode8/main.js b/episode8/main.js index f1ab22d..58e0e8f 100644 --- a/episode8/main.js +++ b/episode8/main.js @@ -1,28 +1,28 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - particles = [], - numParticles = 100; - - for(var i = 0; i < numParticles; i += 1) { - particles.push(particle.create(width / 2, height / 2, Math.random() * 4 + 1, Math.random() * Math.PI * 2)); - } - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - for(var i = 0; i < numParticles; i += 1) { - var p = particles[i]; - p.update(); - - context.beginPath(); - context.arc(p.position.getX(), p.position.getY(), 10, 0, Math.PI * 2, false); - context.fill(); - } - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + particles = [], + numParticles = 100; + + for(var i = 0; i < numParticles; i += 1) { + particles.push(particle.create(width / 2, height / 2, Math.random() * 4 + 1, Math.random() * Math.PI * 2)); + } + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + for(var i = 0; i < numParticles; i += 1) { + var p = particles[i]; + p.update(); + + context.beginPath(); + context.arc(p.position.getX(), p.position.getY(), 10, 0, Math.PI * 2, false); + context.fill(); + } + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/episode8/particle.js b/episode8/particle.js index b6e43f9..d2c89f4 100644 --- a/episode8/particle.js +++ b/episode8/particle.js @@ -1,17 +1,17 @@ -var particle = { - position: null, - velocity: null, - - create: function(x, y, speed, direction) { - var obj = Object.create(this); - obj.position = vector.create(x, y); - obj.velocity = vector.create(0, 0); - obj.velocity.setLength(speed); - obj.velocity.setAngle(direction); - return obj; - }, - - update: function() { - this.position.addTo(this.velocity); - } +var particle = { + position: null, + velocity: null, + + create: function(x, y, speed, direction) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + return obj; + }, + + update: function() { + this.position.addTo(this.velocity); + } }; \ No newline at end of file diff --git a/episode8/vector.js b/episode8/vector.js index 609f6d5..4d66796 100644 --- a/episode8/vector.js +++ b/episode8/vector.js @@ -1,83 +1,83 @@ -var vector = { - _x: 1, - _y: 0, - - create: function(x, y) { - var obj = Object.create(this); - obj.setX(x); - obj.setY(y); - return obj; - }, - - setX: function(value) { - this._x = value; - }, - - getX: function() { - return this._x; - }, - - setY: function(value) { - this._y = value; - }, - - getY: function() { - return this._y; - }, - - setAngle: function(angle) { - var length = this.getLength(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getAngle: function() { - return Math.atan2(this._y, this._x); - }, - - setLength: function(length) { - var angle = this.getAngle(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getLength: function() { - return Math.sqrt(this._x * this._x + this._y * this._y); - }, - - add: function(v2) { - return vector.create(this._x + v2.getX(), this._y + v2.getY()); - }, - - subtract: function(v2) { - return vector.create(this._x - v2.getX(), this._y - v2.getY()); - }, - - multiply: function(val) { - return vector.create(this._x * val, this._y * val); - }, - - divide: function(val) { - return vector.create(this._x / val, this._y / val); - }, - - addTo: function(v2) { - this._x += v2.getX(); - this._y += v2.getY(); - }, - - subtractFrom: function(v2) { - this._x -= v2.getX(); - this._y -= v2.getY(); - }, - - multiplyBy: function(val) { - this._x *= val; - this._y *= val; - }, - - divideBy: function(val) { - this._x /= val; - this._y /= val; - } +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } }; \ No newline at end of file diff --git a/episode9/fireworks.js b/episode9/fireworks.js index 0f52ea1..7db8e65 100644 --- a/episode9/fireworks.js +++ b/episode9/fireworks.js @@ -1,29 +1,29 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - particles = [], - numParticles = 100; - - for(var i = 0; i < numParticles; i += 1) { - particles.push(particle.create(width / 2, height / 3, Math.random() * 5 + 2, Math.random() * Math.PI * 2, 0.1)); - } - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - for(var i = 0; i < numParticles; i += 1) { - var p = particles[i]; - - p.update(); - - context.beginPath(); - context.arc(p.position.getX(), p.position.getY(), 4, 0, Math.PI * 2, false); - context.fill(); - } - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + particles = [], + numParticles = 100; + + for(var i = 0; i < numParticles; i += 1) { + particles.push(particle.create(width / 2, height / 3, Math.random() * 5 + 2, Math.random() * Math.PI * 2, 0.1)); + } + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + for(var i = 0; i < numParticles; i += 1) { + var p = particles[i]; + + p.update(); + + context.beginPath(); + context.arc(p.position.getX(), p.position.getY(), 4, 0, Math.PI * 2, false); + context.fill(); + } + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/episode9/index.html b/episode9/index.html index 5f54d38..14b7b02 100644 --- a/episode9/index.html +++ b/episode9/index.html @@ -1,22 +1,22 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/episode9/main.js b/episode9/main.js index 9b75232..bda0879 100644 --- a/episode9/main.js +++ b/episode9/main.js @@ -1,24 +1,24 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - p = particle.create(100, height, 10, -Math.PI / 2), - accel = vector.create(0.1, 0.1); - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - p.accelerate(accel); - - p.update(); - - context.beginPath(); - context.arc(p.position.getX(), p.position.getY(), 10, 0, Math.PI * 2, false); - context.fill(); - - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + p = particle.create(100, height, 10, -Math.PI / 2), + accel = vector.create(0.1, 0.1); + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + p.accelerate(accel); + + p.update(); + + context.beginPath(); + context.arc(p.position.getX(), p.position.getY(), 10, 0, Math.PI * 2, false); + context.fill(); + + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/episode9/particle.js b/episode9/particle.js index 3abf240..490b906 100644 --- a/episode9/particle.js +++ b/episode9/particle.js @@ -1,24 +1,24 @@ -var particle = { - position: null, - velocity: null, - gravity: null, - - create: function(x, y, speed, direction, grav) { - var obj = Object.create(this); - obj.position = vector.create(x, y); - obj.velocity = vector.create(0, 0); - obj.velocity.setLength(speed); - obj.velocity.setAngle(direction); - obj.gravity = vector.create(0, grav || 0); - return obj; - }, - - accelerate: function(accel) { - this.velocity.addTo(accel); - }, - - update: function() { - this.velocity.addTo(this.gravity); - this.position.addTo(this.velocity); - } +var particle = { + position: null, + velocity: null, + gravity: null, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.position = vector.create(x, y); + obj.velocity = vector.create(0, 0); + obj.velocity.setLength(speed); + obj.velocity.setAngle(direction); + obj.gravity = vector.create(0, grav || 0); + return obj; + }, + + accelerate: function(accel) { + this.velocity.addTo(accel); + }, + + update: function() { + this.velocity.addTo(this.gravity); + this.position.addTo(this.velocity); + } }; \ No newline at end of file diff --git a/episode9/vector.js b/episode9/vector.js index 609f6d5..4d66796 100644 --- a/episode9/vector.js +++ b/episode9/vector.js @@ -1,83 +1,83 @@ -var vector = { - _x: 1, - _y: 0, - - create: function(x, y) { - var obj = Object.create(this); - obj.setX(x); - obj.setY(y); - return obj; - }, - - setX: function(value) { - this._x = value; - }, - - getX: function() { - return this._x; - }, - - setY: function(value) { - this._y = value; - }, - - getY: function() { - return this._y; - }, - - setAngle: function(angle) { - var length = this.getLength(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getAngle: function() { - return Math.atan2(this._y, this._x); - }, - - setLength: function(length) { - var angle = this.getAngle(); - this._x = Math.cos(angle) * length; - this._y = Math.sin(angle) * length; - }, - - getLength: function() { - return Math.sqrt(this._x * this._x + this._y * this._y); - }, - - add: function(v2) { - return vector.create(this._x + v2.getX(), this._y + v2.getY()); - }, - - subtract: function(v2) { - return vector.create(this._x - v2.getX(), this._y - v2.getY()); - }, - - multiply: function(val) { - return vector.create(this._x * val, this._y * val); - }, - - divide: function(val) { - return vector.create(this._x / val, this._y / val); - }, - - addTo: function(v2) { - this._x += v2.getX(); - this._y += v2.getY(); - }, - - subtractFrom: function(v2) { - this._x -= v2.getX(); - this._y -= v2.getY(); - }, - - multiplyBy: function(val) { - this._x *= val; - this._y *= val; - }, - - divideBy: function(val) { - this._x /= val; - this._y /= val; - } +var vector = { + _x: 1, + _y: 0, + + create: function(x, y) { + var obj = Object.create(this); + obj.setX(x); + obj.setY(y); + return obj; + }, + + setX: function(value) { + this._x = value; + }, + + getX: function() { + return this._x; + }, + + setY: function(value) { + this._y = value; + }, + + getY: function() { + return this._y; + }, + + setAngle: function(angle) { + var length = this.getLength(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getAngle: function() { + return Math.atan2(this._y, this._x); + }, + + setLength: function(length) { + var angle = this.getAngle(); + this._x = Math.cos(angle) * length; + this._y = Math.sin(angle) * length; + }, + + getLength: function() { + return Math.sqrt(this._x * this._x + this._y * this._y); + }, + + add: function(v2) { + return vector.create(this._x + v2.getX(), this._y + v2.getY()); + }, + + subtract: function(v2) { + return vector.create(this._x - v2.getX(), this._y - v2.getY()); + }, + + multiply: function(val) { + return vector.create(this._x * val, this._y * val); + }, + + divide: function(val) { + return vector.create(this._x / val, this._y / val); + }, + + addTo: function(v2) { + this._x += v2.getX(); + this._y += v2.getY(); + }, + + subtractFrom: function(v2) { + this._x -= v2.getX(); + this._y -= v2.getY(); + }, + + multiplyBy: function(val) { + this._x *= val; + this._y *= val; + }, + + divideBy: function(val) { + this._x /= val; + this._y /= val; + } }; \ No newline at end of file diff --git a/mini1/index.html b/mini1/index.html index 719fb94..dfde07f 100644 --- a/mini1/index.html +++ b/mini1/index.html @@ -1,20 +1,20 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/mini1/main.js b/mini1/main.js index 79e5286..b1c8708 100644 --- a/mini1/main.js +++ b/mini1/main.js @@ -1,42 +1,42 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - - values = [7, 5, 21, 18, 33, 12, 27, 18, 9, 23, 14, 6, 31, 25, 17, 13, 29], - min = Math.min.apply(null, values), - max = Math.max.apply(null, values); - - function norm(value, min, max) { - return (value - min) / (max - min); - } - - context.beginPath(); - - for(var i = 0; i < values.length; i += 1) { - var normValue = norm(values[i], min, max), - x = width / (values.length - 1) * i, - y = height - height * normValue; - - if(i == 0) { - context.moveTo(x, y); - } - else { - context.lineTo(x, y); - } - } - - context.stroke(); - - // bonus material! you can also plot the points - - for(var i = 0; i < values.length; i += 1) { - var normValue = norm(values[i], min, max), - x = width / (values.length - 1) * i, - y = height - height * normValue; - context.beginPath(); - context.arc(x, y, 4, 0, Math.PI * 2, false); - context.fill(); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + + values = [7, 5, 21, 18, 33, 12, 27, 18, 9, 23, 14, 6, 31, 25, 17, 13, 29], + min = Math.min.apply(null, values), + max = Math.max.apply(null, values); + + function norm(value, min, max) { + return (value - min) / (max - min); + } + + context.beginPath(); + + for(var i = 0; i < values.length; i += 1) { + var normValue = norm(values[i], min, max), + x = width / (values.length - 1) * i, + y = height - height * normValue; + + if(i == 0) { + context.moveTo(x, y); + } + else { + context.lineTo(x, y); + } + } + + context.stroke(); + + // bonus material! you can also plot the points + + for(var i = 0; i < values.length; i += 1) { + var normValue = norm(values[i], min, max), + x = width / (values.length - 1) * i, + y = height - height * normValue; + context.beginPath(); + context.arc(x, y, 4, 0, Math.PI * 2, false); + context.fill(); + } }; \ No newline at end of file diff --git a/mini10/circle.js b/mini10/circle.js index 897247f..eea0db9 100644 --- a/mini10/circle.js +++ b/mini10/circle.js @@ -1,28 +1,28 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - centerX = width / 2, - centerY = height / 2, - maxRadius = 100; - - for (var i = 0; i < 10; i += 1) { - var radius = 20, - angle = Math.PI * 2 / 10 * i, - x = centerX + Math.cos(angle) * radius, - y = centerY + Math.sin(angle) * radius; - context.beginPath(); - context.arc(x, y, 5, 0, Math.PI * 2, false); - context.fill(); - } - for (var i = 0; i < 10; i += 1) { - var radius = 100, - angle = Math.PI * 2 / 10 * i, - x = centerX + Math.cos(angle) * radius, - y = centerY + Math.sin(angle) * radius; - context.beginPath(); - context.arc(x, y, 5, 0, Math.PI * 2, false); - context.fill(); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + centerX = width / 2, + centerY = height / 2, + maxRadius = 100; + + for (var i = 0; i < 10; i += 1) { + var radius = 20, + angle = Math.PI * 2 / 10 * i, + x = centerX + Math.cos(angle) * radius, + y = centerY + Math.sin(angle) * radius; + context.beginPath(); + context.arc(x, y, 5, 0, Math.PI * 2, false); + context.fill(); + } + for (var i = 0; i < 10; i += 1) { + var radius = 100, + angle = Math.PI * 2 / 10 * i, + x = centerX + Math.cos(angle) * radius, + y = centerY + Math.sin(angle) * radius; + context.beginPath(); + context.arc(x, y, 5, 0, Math.PI * 2, false); + context.fill(); + } }; \ No newline at end of file diff --git a/mini10/index.html b/mini10/index.html index 4ded490..25cb3be 100644 --- a/mini10/index.html +++ b/mini10/index.html @@ -1,22 +1,22 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/mini10/main.js b/mini10/main.js index 536954f..bb0af1c 100644 --- a/mini10/main.js +++ b/mini10/main.js @@ -1,19 +1,19 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - centerX = width / 2, - centerY = height / 2, - maxRadius = 100; - - for (var i = 0; i < 1000; i += 1) { - var radius = Math.sqrt(Math.random()) * maxRadius, - angle = utils.randomRange(0, Math.PI * 2), - x = centerX + Math.cos(angle) * radius, - y = centerY + Math.sin(angle) * radius; - context.beginPath(); - context.arc(x, y, 1, 0, Math.PI * 2, false); - context.fill(); - }; +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + centerX = width / 2, + centerY = height / 2, + maxRadius = 100; + + for (var i = 0; i < 1000; i += 1) { + var radius = Math.sqrt(Math.random()) * maxRadius, + angle = utils.randomRange(0, Math.PI * 2), + x = centerX + Math.cos(angle) * radius, + y = centerY + Math.sin(angle) * radius; + context.beginPath(); + context.arc(x, y, 1, 0, Math.PI * 2, false); + context.fill(); + }; }; \ No newline at end of file diff --git a/mini10/main2.js b/mini10/main2.js index 1b3639f..1e800c7 100644 --- a/mini10/main2.js +++ b/mini10/main2.js @@ -1,28 +1,28 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - particles = []; - - for (var i = 0; i < 200; i += 1) { - var p = particle.create(width / 2, height / 2, 0, 0); - p.vx = utils.randomRange(-1, 1); - p.vy = utils.randomRange(-1, 1); - particles.push(p); - }; - - update(); - - function update() { - context.clearRect(0, 0, width, height); - for(var i = 0; i < 200; i += 1) { - var p = particles[i]; - p.update(); - context.beginPath(); - context.arc(p.x, p.y, 3, 0, Math.PI * 2, false); - context.fill(); - } - requestAnimationFrame(update); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + particles = []; + + for (var i = 0; i < 200; i += 1) { + var p = particle.create(width / 2, height / 2, 0, 0); + p.vx = utils.randomRange(-1, 1); + p.vy = utils.randomRange(-1, 1); + particles.push(p); + }; + + update(); + + function update() { + context.clearRect(0, 0, width, height); + for(var i = 0; i < 200; i += 1) { + var p = particles[i]; + p.update(); + context.beginPath(); + context.arc(p.x, p.y, 3, 0, Math.PI * 2, false); + context.fill(); + } + requestAnimationFrame(update); + } }; \ No newline at end of file diff --git a/mini10/particle.js b/mini10/particle.js index b6ef621..948e47a 100644 --- a/mini10/particle.js +++ b/mini10/particle.js @@ -1,138 +1,138 @@ -var particle = { - x: 0, - y: 0, - vx: 0, - vy: 0, - mass: 1, - radius: 0, - bounce: -1, - friction: 1, - gravity: 0, - springs: null, - gravitations: null, - - create: function(x, y, speed, direction, grav) { - var obj = Object.create(this); - obj.x = x; - obj.y = y; - obj.vx = Math.cos(direction) * speed; - obj.vy = Math.sin(direction) * speed; - obj.gravity = grav || 0; - obj.springs = []; - obj.gravitations = []; - return obj; - }, - - addGravitation: function(p) { - this.removeGravitation(p); - this.gravitations.push(p); - }, - - removeGravitation: function(p) { - for(var i = 0; i < this.gravitations.length; i += 1) { - if(p === this.gravitations[i]) { - this.gravitations.splice(i, 1); - return; - } - } - }, - - addSpring: function(point, k, length) { - this.removeSpring(point); - this.springs.push({ - point: point, - k: k, - length: length || 0 - }); - }, - - removeSpring: function(point) { - for(var i = 0; i < this.springs.length; i += 1) { - if(point === this.springs[i].point) { - this.springs.splice(i, 1); - return; - } - } - }, - - getSpeed: function() { - return Math.sqrt(this.vx * this.vx + this.vy * this.vy); - }, - - setSpeed: function(speed) { - var heading = this.getHeading(); - this.vx = Math.cos(heading) * speed; - this.vy = Math.sin(heading) * speed; - }, - - getHeading: function() { - return Math.atan2(this.vy, this.vx); - }, - - setHeading: function(heading) { - var speed = this.getSpeed(); - this.vx = Math.cos(heading) * speed; - this.vy = Math.sin(heading) * speed; - }, - - accelerate: function(ax, ay) { - this.vx += ax; - this.vy += ay; - }, - - update: function() { - this.handleSprings(); - this.handleGravitations(); - this.vx *= this.friction; - this.vy *= this.friction; - this.vy += this.gravity; - this.x += this.vx; - this.y += this.vy; - }, - - handleGravitations: function() { - for(var i = 0; i < this.gravitations.length; i += 1) { - this.gravitateTo(this.gravitations[i]); - } - }, - - handleSprings: function() { - for(var i = 0; i < this.springs.length; i += 1) { - var spring = this.springs[i]; - this.springTo(spring.point, spring.k, spring.length); - } - }, - - angleTo: function(p2) { - return Math.atan2(p2.y - this.y, p2.x - this.x); - }, - - distanceTo: function(p2) { - var dx = p2.x - this.x, - dy = p2.y - this.y; - - return Math.sqrt(dx * dx + dy * dy); - }, - - gravitateTo: function(p2) { - var dx = p2.x - this.x, - dy = p2.y - this.y, - distSQ = dx * dx + dy * dy, - dist = Math.sqrt(distSQ), - force = p2.mass / distSQ, - ax = dx / dist * force, - ay = dy / dist * force; - - this.vx += ax; - this.vy += ay; - }, - - springTo: function(point, k, length) { - var dx = point.x - this.x, - dy = point.y - this.y, - distance = Math.sqrt(dx * dx + dy * dy), - springForce = (distance - length || 0) * k; - this.vx += dx / distance * springForce, - this.vy += dy / distance * springForce; - } +var particle = { + x: 0, + y: 0, + vx: 0, + vy: 0, + mass: 1, + radius: 0, + bounce: -1, + friction: 1, + gravity: 0, + springs: null, + gravitations: null, + + create: function(x, y, speed, direction, grav) { + var obj = Object.create(this); + obj.x = x; + obj.y = y; + obj.vx = Math.cos(direction) * speed; + obj.vy = Math.sin(direction) * speed; + obj.gravity = grav || 0; + obj.springs = []; + obj.gravitations = []; + return obj; + }, + + addGravitation: function(p) { + this.removeGravitation(p); + this.gravitations.push(p); + }, + + removeGravitation: function(p) { + for(var i = 0; i < this.gravitations.length; i += 1) { + if(p === this.gravitations[i]) { + this.gravitations.splice(i, 1); + return; + } + } + }, + + addSpring: function(point, k, length) { + this.removeSpring(point); + this.springs.push({ + point: point, + k: k, + length: length || 0 + }); + }, + + removeSpring: function(point) { + for(var i = 0; i < this.springs.length; i += 1) { + if(point === this.springs[i].point) { + this.springs.splice(i, 1); + return; + } + } + }, + + getSpeed: function() { + return Math.sqrt(this.vx * this.vx + this.vy * this.vy); + }, + + setSpeed: function(speed) { + var heading = this.getHeading(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + getHeading: function() { + return Math.atan2(this.vy, this.vx); + }, + + setHeading: function(heading) { + var speed = this.getSpeed(); + this.vx = Math.cos(heading) * speed; + this.vy = Math.sin(heading) * speed; + }, + + accelerate: function(ax, ay) { + this.vx += ax; + this.vy += ay; + }, + + update: function() { + this.handleSprings(); + this.handleGravitations(); + this.vx *= this.friction; + this.vy *= this.friction; + this.vy += this.gravity; + this.x += this.vx; + this.y += this.vy; + }, + + handleGravitations: function() { + for(var i = 0; i < this.gravitations.length; i += 1) { + this.gravitateTo(this.gravitations[i]); + } + }, + + handleSprings: function() { + for(var i = 0; i < this.springs.length; i += 1) { + var spring = this.springs[i]; + this.springTo(spring.point, spring.k, spring.length); + } + }, + + angleTo: function(p2) { + return Math.atan2(p2.y - this.y, p2.x - this.x); + }, + + distanceTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y; + + return Math.sqrt(dx * dx + dy * dy); + }, + + gravitateTo: function(p2) { + var dx = p2.x - this.x, + dy = p2.y - this.y, + distSQ = dx * dx + dy * dy, + dist = Math.sqrt(distSQ), + force = p2.mass / distSQ, + ax = dx / dist * force, + ay = dy / dist * force; + + this.vx += ax; + this.vy += ay; + }, + + springTo: function(point, k, length) { + var dx = point.x - this.x, + dy = point.y - this.y, + distance = Math.sqrt(dx * dx + dy * dy), + springForce = (distance - length || 0) * k; + this.vx += dx / distance * springForce, + this.vy += dy / distance * springForce; + } }; \ No newline at end of file diff --git a/mini10/utils.js b/mini10/utils.js index 7c659e4..25aa5da 100644 --- a/mini10/utils.js +++ b/mini10/utils.js @@ -1,106 +1,106 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - }, - - degreesToRads: function(degrees) { - return degrees / 180 * Math.PI; - }, - - radsToDegrees: function(radians) { - return radians * 180 / Math.PI; - }, - - randomRange: function(min, max) { - return min + Math.random() * (max - min); - }, - - randomInt: function(min, max) { - return Math.floor(min + Math.random() * (max - min + 1)); - }, - - roundToPlaces: function(value, places) { - var mult = Math.pow(10, places); - return Math.round(value * mult) / mult; - }, - - roundNearest: function(value, nearest) { - return Math.round(value / nearest) * nearest; - }, - - quadraticBezier: function(p0, p1, p2, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 2) * p0.x + - (1 - t) * 2 * t * p1.x + - t * t * p2.x; - pFinal.y = Math.pow(1 - t, 2) * p0.y + - (1 - t) * 2 * t * p1.y + - t * t * p2.y; - return pFinal; - }, - - cubicBezier: function(p0, p1, p2, p3, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 3) * p0.x + - Math.pow(1 - t, 2) * 3 * t * p1.x + - (1 - t) * 3 * t * t * p2.x + - t * t * t * p3.x; - pFinal.y = Math.pow(1 - t, 3) * p0.y + - Math.pow(1 - t, 2) * 3 * t * p1.y + - (1 - t) * 3 * t * t * p2.y + - t * t * t * p3.y; - return pFinal; - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + } + } \ No newline at end of file diff --git a/mini11/bezier.js b/mini11/bezier.js index 441d912..4056883 100644 --- a/mini11/bezier.js +++ b/mini11/bezier.js @@ -1,90 +1,90 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - handle0 = { - x: 100, - y: 100, - radius: 15 - }, - handle1 = { - x: 400, - y: 400, - radius: 15 - }, - handle2 = { - x: 700, - y: 100, - radius: 15 - }, - handle3 = { - x: 1000, - y: 500, - radius: 15 - }, - handles = [handle0, handle1, handle2, handle3], - offset = {}, - isDragging = false, - dragHandle; - - draw(); - - function draw() { - context.clearRect(0, 0, width, height); - - context.beginPath(); - context.moveTo(handle0.x, handle0.y); - context.bezierCurveTo(handle1.x, handle1.y, - handle2.x, handle2.y, - handle3.x, handle3.y); - context.stroke(); - - context.fillStyle = "gray"; - for(var i = 0; i < 4; i += 1) { - var handle = handles[i]; - if(isDragging && handle === dragHandle) { - context.shadowColor = "black"; - context.shadowOffsetX = 4; - context.shadowOffsetY = 4; - context.shadowBlur = 8; - } - context.beginPath(); - context.arc(handle.x, handle.y, handle.radius, 0, Math.PI * 2, false); - context.fill(); - - context.shadowColor = null; - context.shadowOffsetX = null; - context.shadowOffsetY = null; - context.shadowBlur = null; - } - } - - document.body.addEventListener("mousedown", function(event) { - for(var i = 0; i < 4; i += 1) { - var handle = handles[i]; - if(utils.circlePointCollision(event.clientX, event.clientY, handle)) { - isDragging = true; - document.body.addEventListener("mousemove", onMouseMove); - document.body.addEventListener("mouseup", onMouseUp); - dragHandle = handle; - offset.x = event.clientX - handle.x; - offset.y = event.clientY - handle.y; - draw(); - } - } - }); - - function onMouseMove(event) { - dragHandle.x = event.clientX - offset.x; - dragHandle.y = event.clientY - offset.y; - draw(); - } - - function onMouseUp(event) { - document.body.removeEventListener("mousemove", onMouseMove); - document.body.removeEventListener("mouseup", onMouseUp); - isDragging = false; - draw(); - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + handle0 = { + x: 100, + y: 100, + radius: 15 + }, + handle1 = { + x: 400, + y: 400, + radius: 15 + }, + handle2 = { + x: 700, + y: 100, + radius: 15 + }, + handle3 = { + x: 1000, + y: 500, + radius: 15 + }, + handles = [handle0, handle1, handle2, handle3], + offset = {}, + isDragging = false, + dragHandle; + + draw(); + + function draw() { + context.clearRect(0, 0, width, height); + + context.beginPath(); + context.moveTo(handle0.x, handle0.y); + context.bezierCurveTo(handle1.x, handle1.y, + handle2.x, handle2.y, + handle3.x, handle3.y); + context.stroke(); + + context.fillStyle = "gray"; + for(var i = 0; i < 4; i += 1) { + var handle = handles[i]; + if(isDragging && handle === dragHandle) { + context.shadowColor = "black"; + context.shadowOffsetX = 4; + context.shadowOffsetY = 4; + context.shadowBlur = 8; + } + context.beginPath(); + context.arc(handle.x, handle.y, handle.radius, 0, Math.PI * 2, false); + context.fill(); + + context.shadowColor = null; + context.shadowOffsetX = null; + context.shadowOffsetY = null; + context.shadowBlur = null; + } + } + + document.body.addEventListener("mousedown", function(event) { + for(var i = 0; i < 4; i += 1) { + var handle = handles[i]; + if(utils.circlePointCollision(event.clientX, event.clientY, handle)) { + isDragging = true; + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + dragHandle = handle; + offset.x = event.clientX - handle.x; + offset.y = event.clientY - handle.y; + draw(); + } + } + }); + + function onMouseMove(event) { + dragHandle.x = event.clientX - offset.x; + dragHandle.y = event.clientY - offset.y; + draw(); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + isDragging = false; + draw(); + } }; \ No newline at end of file diff --git a/mini11/index.html b/mini11/index.html index e74c311..f47500b 100644 --- a/mini11/index.html +++ b/mini11/index.html @@ -1,21 +1,21 @@ - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/mini11/main.js b/mini11/main.js index 1c6b685..c01bba5 100644 --- a/mini11/main.js +++ b/mini11/main.js @@ -1,45 +1,45 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - handle = { - x: width / 2, - y: height / 2, - radius: 20 - }, - offset = {}; - - draw(); - - function draw() { - context.clearRect(0, 0, width, height); - - context.fillStyle = "gray"; - context.beginPath(); - context.arc(handle.x, handle.y, handle.radius, 0, Math.PI * 2, false); - context.fill(); - } - - document.body.addEventListener("mousedown", function(event) { - if(utils.circlePointCollision(event.clientX, event.clientY, handle)) { - document.body.addEventListener("mousemove", onMouseMove); - document.body.addEventListener("mouseup", onMouseUp); - offset.x = event.clientX - handle.x; - offset.y = event.clientY - handle.y; - } - }); - - function onMouseMove(event) { - handle.x = event.clientX;// - offset.x; - handle.y = event.clientY;// - offset.y; - draw(); - } - - function onMouseUp(event) { - document.body.removeEventListener("mousemove", onMouseMove); - document.body.removeEventListener("mouseup", onMouseUp); - } - - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + handle = { + x: width / 2, + y: height / 2, + radius: 20 + }, + offset = {}; + + draw(); + + function draw() { + context.clearRect(0, 0, width, height); + + context.fillStyle = "gray"; + context.beginPath(); + context.arc(handle.x, handle.y, handle.radius, 0, Math.PI * 2, false); + context.fill(); + } + + document.body.addEventListener("mousedown", function(event) { + if(utils.circlePointCollision(event.clientX, event.clientY, handle)) { + document.body.addEventListener("mousemove", onMouseMove); + document.body.addEventListener("mouseup", onMouseUp); + offset.x = event.clientX - handle.x; + offset.y = event.clientY - handle.y; + } + }); + + function onMouseMove(event) { + handle.x = event.clientX;// - offset.x; + handle.y = event.clientY;// - offset.y; + draw(); + } + + function onMouseUp(event) { + document.body.removeEventListener("mousemove", onMouseMove); + document.body.removeEventListener("mouseup", onMouseUp); + } + + }; \ No newline at end of file diff --git a/mini11/utils.js b/mini11/utils.js index 7c659e4..25aa5da 100644 --- a/mini11/utils.js +++ b/mini11/utils.js @@ -1,106 +1,106 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - }, - - degreesToRads: function(degrees) { - return degrees / 180 * Math.PI; - }, - - radsToDegrees: function(radians) { - return radians * 180 / Math.PI; - }, - - randomRange: function(min, max) { - return min + Math.random() * (max - min); - }, - - randomInt: function(min, max) { - return Math.floor(min + Math.random() * (max - min + 1)); - }, - - roundToPlaces: function(value, places) { - var mult = Math.pow(10, places); - return Math.round(value * mult) / mult; - }, - - roundNearest: function(value, nearest) { - return Math.round(value / nearest) * nearest; - }, - - quadraticBezier: function(p0, p1, p2, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 2) * p0.x + - (1 - t) * 2 * t * p1.x + - t * t * p2.x; - pFinal.y = Math.pow(1 - t, 2) * p0.y + - (1 - t) * 2 * t * p1.y + - t * t * p2.y; - return pFinal; - }, - - cubicBezier: function(p0, p1, p2, p3, t, pFinal) { - pFinal = pFinal || {}; - pFinal.x = Math.pow(1 - t, 3) * p0.x + - Math.pow(1 - t, 2) * 3 * t * p1.x + - (1 - t) * 3 * t * t * p2.x + - t * t * t * p3.x; - pFinal.y = Math.pow(1 - t, 3) * p0.y + - Math.pow(1 - t, 2) * 3 * t * p1.y + - (1 - t) * 3 * t * t * p2.y + - t * t * t * p3.y; - return pFinal; - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + }, + + quadraticBezier: function(p0, p1, p2, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 2) * p0.x + + (1 - t) * 2 * t * p1.x + + t * t * p2.x; + pFinal.y = Math.pow(1 - t, 2) * p0.y + + (1 - t) * 2 * t * p1.y + + t * t * p2.y; + return pFinal; + }, + + cubicBezier: function(p0, p1, p2, p3, t, pFinal) { + pFinal = pFinal || {}; + pFinal.x = Math.pow(1 - t, 3) * p0.x + + Math.pow(1 - t, 2) * 3 * t * p1.x + + (1 - t) * 3 * t * t * p2.x + + t * t * t * p3.x; + pFinal.y = Math.pow(1 - t, 3) * p0.y + + Math.pow(1 - t, 2) * 3 * t * p1.y + + (1 - t) * 3 * t * t * p2.y + + t * t * t * p3.y; + return pFinal; + } + } \ No newline at end of file diff --git a/mini2/index.html b/mini2/index.html index 719fb94..dfde07f 100644 --- a/mini2/index.html +++ b/mini2/index.html @@ -1,20 +1,20 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/mini2/main.js b/mini2/main.js index 798d2b9..64f7a03 100644 --- a/mini2/main.js +++ b/mini2/main.js @@ -1,42 +1,42 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - minX = 50, - maxX = width - 50, - minY = 100, - maxY = height - 100, - minAlpha = 0, - maxAlpha = 1, - minRadius = 10, - maxRadius = 400, - t = 0; - - - function lerp(norm, min, max) { - return (max - min) * norm + min; - } - - update(); - - function update() { - context.clearRect(0, 0, width, height); - - context.globalAlpha = lerp(t, maxAlpha, minAlpha); - context.beginPath(); - context.arc(lerp(t, minX, maxX), - lerp(t, minY, maxY), - lerp(t, minRadius, maxRadius), - 0, Math.PI * 2, false); - context.fill(); - - t += .005; - if(t > 1) { - t = 0; - } - - requestAnimationFrame(update); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + minX = 50, + maxX = width - 50, + minY = 100, + maxY = height - 100, + minAlpha = 0, + maxAlpha = 1, + minRadius = 10, + maxRadius = 400, + t = 0; + + + function lerp(norm, min, max) { + return (max - min) * norm + min; + } + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + context.globalAlpha = lerp(t, maxAlpha, minAlpha); + context.beginPath(); + context.arc(lerp(t, minX, maxX), + lerp(t, minY, maxY), + lerp(t, minRadius, maxRadius), + 0, Math.PI * 2, false); + context.fill(); + + t += .005; + if(t > 1) { + t = 0; + } + + requestAnimationFrame(update); + } + }; \ No newline at end of file diff --git a/mini3/index.html b/mini3/index.html index 719fb94..dfde07f 100644 --- a/mini3/index.html +++ b/mini3/index.html @@ -1,20 +1,20 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/mini3/main.js b/mini3/main.js index 5df9c40..b564d06 100644 --- a/mini3/main.js +++ b/mini3/main.js @@ -1,30 +1,30 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - function norm(value, min, max) { - return (value - min) / (max - min); - } - - function lerp(norm, min, max) { - return (max - min) * norm + min; - } - - function map(value, sourceMin, sourceMax, destMin, destMax) { - return lerp(norm(value, sourceMin, sourceMax), destMin, destMax); - } - - document.body.addEventListener("mousemove", function(event) { - var radius = map(event.clientY, - 0, height, - 20, 340); - - context.clearRect(0, 0, width, height); - context.beginPath(); - context.arc(width / 2, height / 2, radius, 0, Math.PI * 2, false); - context.fill(); - }); - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + function norm(value, min, max) { + return (value - min) / (max - min); + } + + function lerp(norm, min, max) { + return (max - min) * norm + min; + } + + function map(value, sourceMin, sourceMax, destMin, destMax) { + return lerp(norm(value, sourceMin, sourceMax), destMin, destMax); + } + + document.body.addEventListener("mousemove", function(event) { + var radius = map(event.clientY, + 0, height, + 20, 340); + + context.clearRect(0, 0, width, height); + context.beginPath(); + context.arc(width / 2, height / 2, radius, 0, Math.PI * 2, false); + context.fill(); + }); + }; \ No newline at end of file diff --git a/mini4/index.html b/mini4/index.html index 719fb94..dfde07f 100644 --- a/mini4/index.html +++ b/mini4/index.html @@ -1,20 +1,20 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/mini4/main.js b/mini4/main.js index 32ad592..ec5d04d 100644 --- a/mini4/main.js +++ b/mini4/main.js @@ -1,31 +1,31 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - rect = { - x: width / 2 - 200, - y: height / 2 - 150, - width: 400, - height: 300 - }; - - function clamp(value, min, max) { - return Math.min(Math.max(value, min), max); - } - - document.body.addEventListener("mousemove", function(event) { - var x = clamp(event.clientX, rect.x + 10, rect.x + rect.width - 10), - y = clamp(event.clientY, rect.y + 10, rect.y + rect.height - 10); - - context.clearRect(0, 0, width, height); - context.fillStyle = "#cccccc"; - context.fillRect(rect.x, rect.y, rect.width, rect.height); - - context.fillStyle = "#000000"; - context.beginPath(); - context.arc(x, y, 10, 0, Math.PI * 2, false); - context.fill(); - }); - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + rect = { + x: width / 2 - 200, + y: height / 2 - 150, + width: 400, + height: 300 + }; + + function clamp(value, min, max) { + return Math.min(Math.max(value, min), max); + } + + document.body.addEventListener("mousemove", function(event) { + var x = clamp(event.clientX, rect.x + 10, rect.x + rect.width - 10), + y = clamp(event.clientY, rect.y + 10, rect.y + rect.height - 10); + + context.clearRect(0, 0, width, height); + context.fillStyle = "#cccccc"; + context.fillRect(rect.x, rect.y, rect.width, rect.height); + + context.fillStyle = "#000000"; + context.beginPath(); + context.arc(x, y, 10, 0, Math.PI * 2, false); + context.fill(); + }); + }; \ No newline at end of file diff --git a/mini6/index.html b/mini6/index.html index 719fb94..dfde07f 100644 --- a/mini6/index.html +++ b/mini6/index.html @@ -1,20 +1,20 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/mini6/main.js b/mini6/main.js index 778165f..8bb6f11 100644 --- a/mini6/main.js +++ b/mini6/main.js @@ -1,30 +1,30 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - centerX = width / 2, - centerY = height / 2; - - function distanceXY(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - } - - document.body.addEventListener("mousemove", function(event) { - context.clearRect(0, 0, width, height); - - var dist = distanceXY(centerX, centerY, event.clientX, event.clientY); - if(dist < 100) { - context.fillStyle = "#ff6666"; - } - else { - context.fillStyle = "#cccccc"; - } - - context.beginPath(); - context.arc(centerX, centerY, 100, 0, Math.PI * 360, false); - context.fill(); - }); +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + centerX = width / 2, + centerY = height / 2; + + function distanceXY(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + } + + document.body.addEventListener("mousemove", function(event) { + context.clearRect(0, 0, width, height); + + var dist = distanceXY(centerX, centerY, event.clientX, event.clientY); + if(dist < 100) { + context.fillStyle = "#ff6666"; + } + else { + context.fillStyle = "#cccccc"; + } + + context.beginPath(); + context.arc(centerX, centerY, 100, 0, Math.PI * 360, false); + context.fill(); + }); }; \ No newline at end of file diff --git a/mini7/index.html b/mini7/index.html index e74c311..f47500b 100644 --- a/mini7/index.html +++ b/mini7/index.html @@ -1,21 +1,21 @@ - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/mini7/main.js b/mini7/main.js index e378341..44abafb 100644 --- a/mini7/main.js +++ b/mini7/main.js @@ -1,21 +1,21 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - var angle = Math.PI / 4; - - context.translate(width / 2, height / 2); - context.rotate(angle); - - context.beginPath(); - context.arc(0, 0, 20, 0, Math.PI * 2, 0); - context.fill(); - - context.lineWidth = 10; - context.beginPath(); - context.moveTo(0, 0); - context.lineTo(50, 0); - context.stroke(); +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var angle = Math.PI / 4; + + context.translate(width / 2, height / 2); + context.rotate(angle); + + context.beginPath(); + context.arc(0, 0, 20, 0, Math.PI * 2, 0); + context.fill(); + + context.lineWidth = 10; + context.beginPath(); + context.moveTo(0, 0); + context.lineTo(50, 0); + context.stroke(); }; \ No newline at end of file diff --git a/mini7/utils.js b/mini7/utils.js index 5372d1f..fecc898 100644 --- a/mini7/utils.js +++ b/mini7/utils.js @@ -1,65 +1,65 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - }, - - degreesToRads: function(degrees) { - return degrees / 180 * Math.PI; - }, - - radsToDegrees: function(radians) { - return radians * 180 / Math.PI; - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + } + } \ No newline at end of file diff --git a/mini8/index.html b/mini8/index.html index e74c311..f47500b 100644 --- a/mini8/index.html +++ b/mini8/index.html @@ -1,21 +1,21 @@ - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/mini8/main.js b/mini8/main.js index 0696243..bbca9f3 100644 --- a/mini8/main.js +++ b/mini8/main.js @@ -1,36 +1,36 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - gridSize = 40; - - drawGrid(); - - document.body.addEventListener("mousemove", function(event) { - context.clearRect(0, 0, width, height); - drawGrid(); - - var x = utils.roundNearest(event.clientX, gridSize), - y = utils.roundNearest(event.clientY, gridSize); - - context.beginPath(); - context.arc(x, y, 20, 0, Math.PI * 2, false); - context.fill(); - }); - - function drawGrid() { - context.beginPath(); - context.strokeStyle = "#ccc"; - for(var x = 0; x <= width; x += gridSize) { - context.moveTo(x, 0); - context.lineTo(x, height); - } - for(var y = 0; y <= height; y += gridSize) { - context.moveTo(0, y); - context.lineTo(width, y); - } - context.stroke(); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + gridSize = 40; + + drawGrid(); + + document.body.addEventListener("mousemove", function(event) { + context.clearRect(0, 0, width, height); + drawGrid(); + + var x = utils.roundNearest(event.clientX, gridSize), + y = utils.roundNearest(event.clientY, gridSize); + + context.beginPath(); + context.arc(x, y, 20, 0, Math.PI * 2, false); + context.fill(); + }); + + function drawGrid() { + context.beginPath(); + context.strokeStyle = "#ccc"; + for(var x = 0; x <= width; x += gridSize) { + context.moveTo(x, 0); + context.lineTo(x, height); + } + for(var y = 0; y <= height; y += gridSize) { + context.moveTo(0, y); + context.lineTo(width, y); + } + context.stroke(); + } + }; \ No newline at end of file diff --git a/mini8/test1.js b/mini8/test1.js index e8f3ee3..bfdca97 100644 --- a/mini8/test1.js +++ b/mini8/test1.js @@ -1,7 +1,7 @@ -window.onload = function() { - - console.log(utils.roundToPlaces(Math.PI, 1)); - console.log(utils.roundToPlaces(Math.PI, 3)); - console.log(utils.roundToPlaces(Math.PI, 5)); - +window.onload = function() { + + console.log(utils.roundToPlaces(Math.PI, 1)); + console.log(utils.roundToPlaces(Math.PI, 3)); + console.log(utils.roundToPlaces(Math.PI, 5)); + }; \ No newline at end of file diff --git a/mini8/test2.js b/mini8/test2.js index db9e1c2..18b743c 100644 --- a/mini8/test2.js +++ b/mini8/test2.js @@ -1,7 +1,7 @@ -window.onload = function() { - - console.log(utils.roundToPlaces(123456789, -1)); - console.log(utils.roundToPlaces(123456789, -2)); - console.log(utils.roundToPlaces(123456789, -3)); - +window.onload = function() { + + console.log(utils.roundToPlaces(123456789, -1)); + console.log(utils.roundToPlaces(123456789, -2)); + console.log(utils.roundToPlaces(123456789, -3)); + }; \ No newline at end of file diff --git a/mini8/utils.js b/mini8/utils.js index f31970f..1a22d0f 100644 --- a/mini8/utils.js +++ b/mini8/utils.js @@ -1,74 +1,74 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - }, - - degreesToRads: function(degrees) { - return degrees / 180 * Math.PI; - }, - - radsToDegrees: function(radians) { - return radians * 180 / Math.PI; - }, - - roundToPlaces: function(value, places) { - var mult = Math.pow(10, places); - return Math.round(value * mult) / mult; - }, - - roundNearest: function(value, nearest) { - return Math.round(value / nearest) * nearest; - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + roundToPlaces: function(value, places) { + var mult = Math.pow(10, places); + return Math.round(value * mult) / mult; + }, + + roundNearest: function(value, nearest) { + return Math.round(value / nearest) * nearest; + } + } \ No newline at end of file diff --git a/mini9/highres.js b/mini9/highres.js index 746b944..ae1826d 100644 --- a/mini9/highres.js +++ b/mini9/highres.js @@ -1,45 +1,45 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - results = [], - running = true; - - document.body.addEventListener("click", function() { - running = !running; - }); - - for(var i = 0; i < width; i += 1) { - results[i] = 0; - } - - update(); - - function update() { - - for(var n = 0; n < 1000; n += 1) { - addResult(); - } - for(var i = 0; i < width; i += 1) { - var h = -results[i]; - context.fillRect(i, height, 1, h ); - } - if(running) { - requestAnimationFrame(update); - } - } - - function addResult() { - var iterations = 2, - total = 0; - - for(var i = 0; i < iterations; i += 1) { - total += utils.randomRange(0, width); - } - result = Math.floor(total / iterations); - - results[result] += 1; - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + results = [], + running = true; + + document.body.addEventListener("click", function() { + running = !running; + }); + + for(var i = 0; i < width; i += 1) { + results[i] = 0; + } + + update(); + + function update() { + + for(var n = 0; n < 1000; n += 1) { + addResult(); + } + for(var i = 0; i < width; i += 1) { + var h = -results[i]; + context.fillRect(i, height, 1, h ); + } + if(running) { + requestAnimationFrame(update); + } + } + + function addResult() { + var iterations = 2, + total = 0; + + for(var i = 0; i < iterations; i += 1) { + total += utils.randomRange(0, width); + } + result = Math.floor(total / iterations); + + results[result] += 1; + } + }; \ No newline at end of file diff --git a/mini9/index.html b/mini9/index.html index ec278a5..30c3a9a 100644 --- a/mini9/index.html +++ b/mini9/index.html @@ -1,21 +1,21 @@ - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/mini9/main.js b/mini9/main.js index 51b87a1..d085334 100644 --- a/mini9/main.js +++ b/mini9/main.js @@ -1,35 +1,35 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - results = []; - - for(var i = 0; i < 100; i += 1) { - results[i] = 0; - } - - update(); - - function update() { - addResult(); - draw(); - requestAnimationFrame(update); - } - - function addResult() { - var r0 = utils.randomRange(0, 100), - r1 = utils.randomRange(0, 100), - result = Math.floor((r0 + r1) / 2); - - results[result] += 1; - } - - function draw() { - var w = width / 100; - for(var i = 0; i < 100; i += 1) { - var h = results[i] * -10; - context.fillRect(w * i, height, w, h); - } - } +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + results = []; + + for(var i = 0; i < 100; i += 1) { + results[i] = 0; + } + + update(); + + function update() { + addResult(); + draw(); + requestAnimationFrame(update); + } + + function addResult() { + var r0 = utils.randomRange(0, 100), + r1 = utils.randomRange(0, 100), + result = Math.floor((r0 + r1) / 2); + + results[result] += 1; + } + + function draw() { + var w = width / 100; + for(var i = 0; i < 100; i += 1) { + var h = results[i] * -10; + context.fillRect(w * i, height, w, h); + } + } }; \ No newline at end of file diff --git a/mini9/main2.js b/mini9/main2.js index c448558..7000f9b 100644 --- a/mini9/main2.js +++ b/mini9/main2.js @@ -1,38 +1,38 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight, - results = []; - - for(var i = 0; i < 100; i += 1) { - results[i] = 0; - } - - update(); - - function update() { - addResult(); - draw(); - requestAnimationFrame(update); - } - - function addResult() { - var iterations = 3, - total = 0; - for(var i = 0; i < iterations; i += 1) { - total += utils.randomRange(0, 100); - } - result = Math.floor(total / iterations); - results[result] += 1; - } - - function draw() { - var w = width / 100; - for(var i = 0; i < 100; i += 1) { - var h = results[i] * -10; - context.fillRect(w * i, height, w, h); - } - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + results = []; + + for(var i = 0; i < 100; i += 1) { + results[i] = 0; + } + + update(); + + function update() { + addResult(); + draw(); + requestAnimationFrame(update); + } + + function addResult() { + var iterations = 3, + total = 0; + for(var i = 0; i < iterations; i += 1) { + total += utils.randomRange(0, 100); + } + result = Math.floor(total / iterations); + results[result] += 1; + } + + function draw() { + var w = width / 100; + for(var i = 0; i < 100; i += 1) { + var h = results[i] * -10; + context.fillRect(w * i, height, w, h); + } + } + }; \ No newline at end of file diff --git a/mini9/main3.js b/mini9/main3.js index e220e64..e54bcb0 100644 --- a/mini9/main3.js +++ b/mini9/main3.js @@ -1,14 +1,14 @@ -window.onload = function() { - var canvas = document.getElementById("canvas"), - context = canvas.getContext("2d"), - width = canvas.width = window.innerWidth, - height = canvas.height = window.innerHeight; - - for(var i = 0; i < 100000; i += 1) { - var x = utils.randomDist(0, width, 5), - y = utils.randomDist(0, height, 5); - - context.fillRect(x, y, 1, 1); - } - +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + for(var i = 0; i < 100000; i += 1) { + var x = utils.randomDist(0, width, 5), + y = utils.randomDist(0, height, 5); + + context.fillRect(x, y, 1, 1); + } + }; \ No newline at end of file diff --git a/mini9/utils.js b/mini9/utils.js index 4d85a81..5fab762 100644 --- a/mini9/utils.js +++ b/mini9/utils.js @@ -1,82 +1,82 @@ -var utils = { - norm: function(value, min, max) { - return (value - min) / (max - min); - }, - - lerp: function(norm, min, max) { - return (max - min) * norm + min; - }, - - map: function(value, sourceMin, sourceMax, destMin, destMax) { - return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); - }, - - clamp: function(value, min, max) { - return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); - }, - - distance: function(p0, p1) { - var dx = p1.x - p0.x, - dy = p1.y - p0.y; - return Math.sqrt(dx * dx + dy * dy); - }, - - distanceXY: function(x0, y0, x1, y1) { - var dx = x1 - x0, - dy = y1 - y0; - return Math.sqrt(dx * dx + dy * dy); - }, - - circleCollision: function(c0, c1) { - return utils.distance(c0, c1) <= c0.radius + c1.radius; - }, - - circlePointCollision: function(x, y, circle) { - return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; - }, - - pointInRect: function(x, y, rect) { - return utils.inRange(x, rect.x, rect.x + rect.width) && - utils.inRange(y, rect.y, rect.y + rect.height); - }, - - inRange: function(value, min, max) { - return value >= Math.min(min, max) && value <= Math.max(min, max); - }, - - rangeIntersect: function(min0, max0, min1, max1) { - return Math.max(min0, max0) >= Math.min(min1, max1) && - Math.min(min0, max0) <= Math.max(min1, max1); - }, - - rectIntersect: function(r0, r1) { - return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && - utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); - }, - - degreesToRads: function(degrees) { - return degrees / 180 * Math.PI; - }, - - radsToDegrees: function(radians) { - return radians * 180 / Math.PI; - }, - - randomRange: function(min, max) { - return min + Math.random() * (max - min); - }, - - randomInt: function(min, max) { - return Math.floor(min + Math.random() * (max - min + 1)); - }, - - randomDist: function(min, max, iterations) { - var total = 0; - - for(var i = 0; i < iterations; i += 1) { - total += utils.randomRange(min, max); - } - return total / iterations; - } - +var utils = { + norm: function(value, min, max) { + return (value - min) / (max - min); + }, + + lerp: function(norm, min, max) { + return (max - min) * norm + min; + }, + + map: function(value, sourceMin, sourceMax, destMin, destMax) { + return utils.lerp(utils.norm(value, sourceMin, sourceMax), destMin, destMax); + }, + + clamp: function(value, min, max) { + return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max)); + }, + + distance: function(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + distanceXY: function(x0, y0, x1, y1) { + var dx = x1 - x0, + dy = y1 - y0; + return Math.sqrt(dx * dx + dy * dy); + }, + + circleCollision: function(c0, c1) { + return utils.distance(c0, c1) <= c0.radius + c1.radius; + }, + + circlePointCollision: function(x, y, circle) { + return utils.distanceXY(x, y, circle.x, circle.y) < circle.radius; + }, + + pointInRect: function(x, y, rect) { + return utils.inRange(x, rect.x, rect.x + rect.width) && + utils.inRange(y, rect.y, rect.y + rect.height); + }, + + inRange: function(value, min, max) { + return value >= Math.min(min, max) && value <= Math.max(min, max); + }, + + rangeIntersect: function(min0, max0, min1, max1) { + return Math.max(min0, max0) >= Math.min(min1, max1) && + Math.min(min0, max0) <= Math.max(min1, max1); + }, + + rectIntersect: function(r0, r1) { + return utils.rangeIntersect(r0.x, r0.x + r0.width, r1.x, r1.x + r1.width) && + utils.rangeIntersect(r0.y, r0.y + r0.height, r1.y, r1.y + r1.height); + }, + + degreesToRads: function(degrees) { + return degrees / 180 * Math.PI; + }, + + radsToDegrees: function(radians) { + return radians * 180 / Math.PI; + }, + + randomRange: function(min, max) { + return min + Math.random() * (max - min); + }, + + randomInt: function(min, max) { + return Math.floor(min + Math.random() * (max - min + 1)); + }, + + randomDist: function(min, max, iterations) { + var total = 0; + + for(var i = 0; i < iterations; i += 1) { + total += utils.randomRange(min, max); + } + return total / iterations; + } + } \ No newline at end of file From f2ddaa9bdb26eac8a1465941ddb7d3863869173a Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Wed, 18 Mar 2015 08:20:51 -0400 Subject: [PATCH 30/39] episode 37 --- episode37/index.html | 23 +++++++ episode37/main.js | 160 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 episode37/index.html create mode 100644 episode37/main.js diff --git a/episode37/index.html b/episode37/index.html new file mode 100644 index 0000000..b211694 --- /dev/null +++ b/episode37/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/episode37/main.js b/episode37/main.js new file mode 100644 index 0000000..f423441 --- /dev/null +++ b/episode37/main.js @@ -0,0 +1,160 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var points = [], + sticks = [], + bounce = 0.9, + gravity = 0.5, + friction = 0.999; + + points.push({ + x: 100, + y: 100, + oldx: 100 + Math.random() * 30 - 15, + oldy: 100 + Math.random() * 30 - 15 + }); + points.push({ + x: 200, + y: 100, + oldx: 200, + oldy: 100 + }); + points.push({ + x: 200, + y: 200, + oldx: 200, + oldy: 200 + }); + points.push({ + x: 100, + y: 200, + oldx: 100, + oldy: 200 + }); + + sticks.push({ + p0: points[0], + p1: points[1], + length: distance(points[0], points[1]) + }); + sticks.push({ + p0: points[1], + p1: points[2], + length: distance(points[1], points[2]) + }); + sticks.push({ + p0: points[2], + p1: points[3], + length: distance(points[2], points[3]) + }); + sticks.push({ + p0: points[3], + p1: points[0], + length: distance(points[3], points[0]) + }); + // sticks.push({ + // p0: points[0], + // p1: points[2], + // length: distance(points[0], points[2]) + // }); + + function distance(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + } + + update(); + + function update() { + updatePoints(); + constrainPoints(); + // for(var i = 0; i < 5; i++) { + updateSticks(); + // } + renderPoints(); + renderSticks(); + requestAnimationFrame(update); + } + + function updatePoints() { + for(var i = 0; i < points.length; i++) { + var p = points[i], + vx = (p.x - p.oldx) * friction; + vy = (p.y - p.oldy) * friction; + + p.oldx = p.x; + p.oldy = p.y; + p.x += vx; + p.y += vy; + p.y += gravity; + } + } + + function constrainPoints() { + for(var i = 0; i < points.length; i++) { + var p = points[i], + vx = (p.x - p.oldx) * friction; + vy = (p.y - p.oldy) * friction; + + if(p.x > width) { + p.x = width; + p.oldx = p.x + vx * bounce; + } + else if(p.x < 0) { + p.x = 0; + p.oldx = p.x + vx * bounce; + } + if(p.y > height) { + p.y = height; + p.oldy = p.y + vy * bounce; + } + else if(p.y < 0) { + p.y = 0; + p.oldy = p.y + vy * bounce; + } + } + } + + function updateSticks() { + for(var i = 0; i < sticks.length; i++) { + var s = sticks[i], + dx = s.p1.x - s.p0.x, + dy = s.p1.y - s.p0.y, + distance = Math.sqrt(dx * dx + dy * dy), + difference = s.length - distance, + percent = difference / distance / 2, + offsetX = dx * percent, + offsetY = dy * percent; + + s.p0.x -= offsetX; + s.p0.y -= offsetY; + s.p1.x += offsetX; + s.p1.y += offsetY; + } + } + + function renderPoints() { + context.clearRect(0, 0, width, height); + for(var i = 0; i < points.length; i++) { + var p = points[i]; + context.beginPath(); + context.arc(p.x, p.y, 5, 0, Math.PI * 2); + context.fill(); + } + } + + function renderSticks() { + context.beginPath(); + for(var i = 0; i < sticks.length; i++) { + var s = sticks[i]; + context.moveTo(s.p0.x, s.p0.y); + context.lineTo(s.p1.x, s.p1.y); + } + context.stroke(); + } +}; \ No newline at end of file From 6c5f562b6fdf9b3e1b727b72f739c71b6ba2d963 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Sun, 22 Mar 2015 16:41:22 -0400 Subject: [PATCH 31/39] episode39 --- episode39/index.html | 24 +++++ episode39/json.js | 143 ++++++++++++++++++++++++++ episode39/main.js | 236 +++++++++++++++++++++++++++++++++++++++++++ episode39/model.json | 83 +++++++++++++++ 4 files changed, 486 insertions(+) create mode 100644 episode39/index.html create mode 100644 episode39/json.js create mode 100644 episode39/main.js create mode 100644 episode39/model.json diff --git a/episode39/index.html b/episode39/index.html new file mode 100644 index 0000000..74959d5 --- /dev/null +++ b/episode39/index.html @@ -0,0 +1,24 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/episode39/json.js b/episode39/json.js new file mode 100644 index 0000000..87afaa5 --- /dev/null +++ b/episode39/json.js @@ -0,0 +1,143 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var points = [], + sticks = [], + bounce = 0.9, + gravity = 0.5, + friction = 0.999; + + $.getJSON("model.json", function(data) { + parseModel(data); + }); + + function parseModel(data) { + for(var i = 0; i < data.points.length; i++) { + points[i] = data.points[i]; + } + for(i = 0; i < data.sticks.length; i++) { + var s = data.sticks[i]; + s.p0 = points[s.p0]; + s.p1 = points[s.p1]; + s.length = distance(s.p0, s.p1); + sticks[i] = s; + } + update(); + } + + function distance(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + } + + function update() { + updatePoints(); + for(var i = 0; i < 5; i++) { + updateSticks(); + constrainPoints(); + } + context.clearRect(0, 0, width, height); + // renderPoints(); + renderSticks(); + requestAnimationFrame(update); + } + + function updateEngine() { + engine.x = engine.baseX + Math.cos(engine.angle) * engine.range; + engine.y = engine.baseY + Math.sin(engine.angle) * engine.range; + engine.angle += engine.speed; + } + + function updatePoints() { + for(var i = 0; i < points.length; i++) { + var p = points[i]; + if(!p.pinned) { + var vx = (p.x - p.oldx) * friction, + vy = (p.y - p.oldy) * friction; + + p.oldx = p.x; + p.oldy = p.y; + p.x += vx; + p.y += vy; + p.y += gravity; + } + } + } + + function constrainPoints() { + for(var i = 0; i < points.length; i++) { + var p = points[i]; + if(!p.pinned) { + var vx = (p.x - p.oldx) * friction, + vy = (p.y - p.oldy) * friction; + + if(p.x > width) { + p.x = width; + p.oldx = p.x + vx * bounce; + } + else if(p.x < 0) { + p.x = 0; + p.oldx = p.x + vx * bounce; + } + if(p.y > height) { + p.y = height; + p.oldy = p.y + vy * bounce; + } + else if(p.y < 0) { + p.y = 0; + p.oldy = p.y + vy * bounce; + } + } + } + } + + function updateSticks() { + for(var i = 0; i < sticks.length; i++) { + var s = sticks[i], + dx = s.p1.x - s.p0.x, + dy = s.p1.y - s.p0.y, + distance = Math.sqrt(dx * dx + dy * dy), + difference = s.length - distance, + percent = difference / distance / 2, + offsetX = dx * percent, + offsetY = dy * percent; + + if(!s.p0.pinned) { + s.p0.x -= offsetX; + s.p0.y -= offsetY; + } + if(!s.p1.pinned) { + s.p1.x += offsetX; + s.p1.y += offsetY; + } + } + } + + function renderPoints() { + for(var i = 0; i < points.length; i++) { + var p = points[i]; + context.beginPath(); + context.arc(p.x, p.y, 5, 0, Math.PI * 2); + context.fill(); + } + } + + function renderSticks() { + for(var i = 0; i < sticks.length; i++) { + var s = sticks[i]; + if(!s.hidden) { + context.beginPath(); + context.strokeStyle = s.color ? s.color : "black"; + context.lineWidth = s.width ? s.width : 1; + context.moveTo(s.p0.x, s.p0.y); + context.lineTo(s.p1.x, s.p1.y); + context.stroke(); + } + } + } +}; \ No newline at end of file diff --git a/episode39/main.js b/episode39/main.js new file mode 100644 index 0000000..47a7c2d --- /dev/null +++ b/episode39/main.js @@ -0,0 +1,236 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var points = [], + sticks = [], + bounce = 0.9, + gravity = 0.5, + friction = 0.999, + angle = 0, + speed = 0.1, + engine = { + baseX: 450, + baseY: 100, + range: 100, + angle: 0, + speed: 0.05, + x: 550, + y: 100, + pinned: true + }; + + points.push({ + x: 100, + y: 100, + oldx: 100 + Math.random() * 50 - 25, + oldy: 100 + Math.random() * 50 - 25 + }); + points.push({ + x: 200, + y: 100, + oldx: 200, + oldy: 100 + }); + points.push({ + x: 200, + y: 200, + oldx: 200, + oldy: 200 + }); + points.push({ + x: 100, + y: 200, + oldx: 100, + oldy: 200 + }); + + points.push({ + x: 400, + y: 100, + oldx: 400, + oldy: 100 + }); + points.push({ + x: 250, + y: 100, + oldx: 250, + oldy: 100 + }); + + sticks.push({ + p0: points[0], + p1: points[1], + length: distance(points[0], points[1]) + }); + sticks.push({ + p0: points[1], + p1: points[2], + length: distance(points[1], points[2]) + }); + sticks.push({ + p0: points[2], + p1: points[3], + length: distance(points[2], points[3]) + }); + sticks.push({ + p0: points[3], + p1: points[0], + length: distance(points[3], points[0]) + }); + sticks.push({ + p0: points[0], + p1: points[2], + length: distance(points[0], points[2]), + hidden: true + }); + + sticks.push({ + p0: engine, + p1: points[4], + length: distance(engine, points[4]) + }); + sticks.push({ + p0: points[4], + p1: points[5], + length: distance(points[4], points[5]) + }); + sticks.push({ + p0: points[5], + p1: points[0], + length: distance(points[5], points[0]) + }); + + function distance(p0, p1) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y; + return Math.sqrt(dx * dx + dy * dy); + } + + update(); + + function update() { + updateEngine(); + updatePoints(); + for(var i = 0; i < 5; i++) { + updateSticks(); + constrainPoints(); + } + context.clearRect(0, 0, width, height); + // renderPoints(); + renderSticks(); + renderEngine(); + requestAnimationFrame(update); + } + + function updateEngine() { + engine.x = engine.baseX + Math.cos(engine.angle) * engine.range; + engine.y = engine.baseY + Math.sin(engine.angle) * engine.range; + engine.angle += engine.speed; + } + + function updatePoints() { + for(var i = 0; i < points.length; i++) { + var p = points[i]; + if(!p.pinned) { + var vx = (p.x - p.oldx) * friction, + vy = (p.y - p.oldy) * friction; + + p.oldx = p.x; + p.oldy = p.y; + p.x += vx; + p.y += vy; + p.y += gravity; + } + } + } + + function constrainPoints() { + for(var i = 0; i < points.length; i++) { + var p = points[i]; + if(!p.pinned) { + var vx = (p.x - p.oldx) * friction, + vy = (p.y - p.oldy) * friction; + + if(p.x > width) { + p.x = width; + p.oldx = p.x + vx * bounce; + } + else if(p.x < 0) { + p.x = 0; + p.oldx = p.x + vx * bounce; + } + if(p.y > height) { + p.y = height; + p.oldy = p.y + vy * bounce; + } + else if(p.y < 0) { + p.y = 0; + p.oldy = p.y + vy * bounce; + } + } + } + } + + function updateSticks() { + for(var i = 0; i < sticks.length; i++) { + var s = sticks[i], + dx = s.p1.x - s.p0.x, + dy = s.p1.y - s.p0.y, + distance = Math.sqrt(dx * dx + dy * dy), + difference = s.length - distance, + percent = difference / distance / 2, + offsetX = dx * percent, + offsetY = dy * percent; + + if(!s.p0.pinned) { + s.p0.x -= offsetX; + s.p0.y -= offsetY; + } + if(!s.p1.pinned) { + s.p1.x += offsetX; + s.p1.y += offsetY; + } + } + } + + function renderPoints() { + for(var i = 0; i < points.length; i++) { + var p = points[i]; + context.beginPath(); + context.arc(p.x, p.y, 5, 0, Math.PI * 2); + context.fill(); + } + } + + function renderSticks() { + for(var i = 0; i < sticks.length; i++) { + var s = sticks[i]; + if(!s.hidden) { + context.beginPath(); + context.strokeStyle = s.color ? s.color : "black"; + context.lineWidth = s.width ? s.width : 1; + context.moveTo(s.p0.x, s.p0.y); + context.lineTo(s.p1.x, s.p1.y); + context.stroke(); + } + } + } + + function renderEngine() { + context.beginPath(); + // context.rect(engine.baseX - engine.range, engine.baseY - 5, engine.range * 2, 10); + context.arc(engine.baseX, engine.baseY, engine.range, 0, Math.PI * 2); + context.stroke(); + context.beginPath(); + context.arc(engine.x, engine.y, 5, 0, Math.PI * 2); + context.fill(); + } + + // document.body.addEventListener("click", function(event) { + // points[4].pinned = !points[4].pinned; + // }); +}; \ No newline at end of file diff --git a/episode39/model.json b/episode39/model.json new file mode 100644 index 0000000..be3e49f --- /dev/null +++ b/episode39/model.json @@ -0,0 +1,83 @@ +{ + "points": [ + { + "x": 100, + "y": 100, + "oldx": 50, + "oldy": 150 + }, + { + "x": 200, + "y": 100, + "oldx": 200, + "oldy": 100 + }, + { + "x": 200, + "y": 200, + "oldx": 200, + "oldy": 200 + }, + { + "x": 100, + "y": 200, + "oldx": 100, + "oldy": 200 + }, + { + "x": 550, + "y": 100, + "oldx": 550, + "oldy": 100, + "pinned": true + }, + { + "x": 400, + "y": 100, + "oldx": 400, + "oldy": 100 + }, + { + "x": 250, + "y": 100, + "oldx": 250, + "oldy": 100 + } + ], + + "sticks": [ + { + "p0": 0, + "p1": 1 + }, + { + "p0": 1, + "p1": 2 + }, + { + "p0": 2, + "p1": 3 + }, + { + "p0": 3, + "p1": 0 + }, + { + "p0": 0, + "p1": 2, + "hidden": true + }, + { + "p0": 4, + "p1": 5 + }, + { + "p0": 5, + "p1": 6 + }, + { + "p0": 6, + "p1": 0 + } + ] +} \ No newline at end of file From 5cfbe93e1fc8a176421c1455a9d3ce3486034982 Mon Sep 17 00:00:00 2001 From: sroucheray Date: Mon, 30 Mar 2015 22:30:30 +0200 Subject: [PATCH 32/39] combined variable declarations are separated by commas --- episode36/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/episode36/main.js b/episode36/main.js index b0b9c6d..32f9e3d 100644 --- a/episode36/main.js +++ b/episode36/main.js @@ -30,7 +30,7 @@ window.onload = function() { function updatePoints() { for(var i = 0; i < points.length; i++) { var p = points[i], - vx = (p.x - p.oldx) * friction; + vx = (p.x - p.oldx) * friction, vy = (p.y - p.oldy) * friction; p.oldx = p.x; From a7ab2700e87dc91693b2aac83aae21cd3af83257 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Sun, 12 Apr 2015 19:17:17 -0400 Subject: [PATCH 33/39] episode 40 files --- episode40/index.html | 24 +++++++++++++ episode40/main.js | 65 ++++++++++++++++++++++++++++++++++ episode40/pytree.js | 59 +++++++++++++++++++++++++++++++ episode40/pytreeanim.js | 68 ++++++++++++++++++++++++++++++++++++ episode40/treeanim.js | 77 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 293 insertions(+) create mode 100644 episode40/index.html create mode 100644 episode40/main.js create mode 100644 episode40/pytree.js create mode 100644 episode40/pytreeanim.js create mode 100644 episode40/treeanim.js diff --git a/episode40/index.html b/episode40/index.html new file mode 100644 index 0000000..833fe25 --- /dev/null +++ b/episode40/index.html @@ -0,0 +1,24 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/episode40/main.js b/episode40/main.js new file mode 100644 index 0000000..3b1d6db --- /dev/null +++ b/episode40/main.js @@ -0,0 +1,65 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var p0 = { + x: width / 2, + y: height - 50 + }, + p1 = { + x: width / 2, + y: 50 + }, + branchAngleA = randomRange(-Math.PI / 2, Math.PI / 2), + branchAngleB = randomRange(-Math.PI / 2, Math.PI / 2), + trunkRatio = randomRange(0.25, 0.75); + + function randomRange(min, max) { + return min + Math.random() * (max - min); + } + + tree(p0, p1, 8); + + function tree(p0, p1, limit) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y, + dist = Math.sqrt(dx * dx + dy * dy), + angle = Math.atan2(dy, dx), + branchLength = dist * (1 - trunkRatio), + pA = { + x: p0.x + dx * trunkRatio, + y: p0.y + dy * trunkRatio + }, + pB = { + x: pA.x + Math.cos(angle + branchAngleA) * branchLength, + y: pA.y + Math.sin(angle + branchAngleA) * branchLength, + }, + pC = { + x: pA.x + Math.cos(angle + branchAngleB) * branchLength, + y: pA.y + Math.sin(angle + branchAngleB) * branchLength, + }; + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(pA.x, pA.y); + context.stroke(); + + if(limit > 0) { + tree(pA, pC, limit - 1); + tree(pA, pB, limit - 1); + } + else { + context.beginPath(); + context.moveTo(pB.x, pB.y); + context.lineTo(pA.x, pA.y); + context.lineTo(pC.x, pC.y); + context.stroke(); + } + branchAngleA += randomRange(-0.02, 0.02); + branchAngleB += randomRange(-0.02, 0.02); + trunkRatio += randomRange(-0.02, 0.02); + } +}; \ No newline at end of file diff --git a/episode40/pytree.js b/episode40/pytree.js new file mode 100644 index 0000000..4b2296f --- /dev/null +++ b/episode40/pytree.js @@ -0,0 +1,59 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var branchAngleA = randomRange(0, -Math.PI / 2); + + tree(width / 2 - 75, height, 150, 0, 12); + + function randomRange(min, max) { + return min + Math.random() * (max - min); + } + + function tree(x, y, size, angle, limit) { + context.save(); + context.translate(x, y); + context.rotate(angle); + context.fillRect(0, 0, size, -size); + + // left branch + var x0 = 0, + y0 = -size, + size0 = Math.abs(Math.cos(branchAngleA) * size), + angle0 = branchAngleA; + + if(limit > 0) { + tree(x0, y0, size0, angle0, limit - 1); + } + else { + context.save(); + context.translate(x0, y0); + context.rotate(angle0); + context.fillRect(0, 0, size0, -size0); + context.restore(); + } + + // right branch + var x1 = x0 + Math.cos(angle0) * size0, + y1 = y0 + Math.sin(angle0) * size0, + size1 = Math.abs(Math.sin(branchAngleA) * size) + angle1 = angle0 + Math.PI / 2; + + if(limit > 0) { + tree(x1, y1, size1, angle1, limit - 1); + } + else { + context.save(); + context.translate(x1, y1); + context.rotate(angle1); + context.fillRect(0, 0, size1, -size1); + context.restore(); + } + + + context.restore(); + } +}; \ No newline at end of file diff --git a/episode40/pytreeanim.js b/episode40/pytreeanim.js new file mode 100644 index 0000000..0d1f65a --- /dev/null +++ b/episode40/pytreeanim.js @@ -0,0 +1,68 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var branchAngleA = 0, + t = 0; + + draw(); + + function draw() { + context.clearRect(0, 0, width, height); + branchAngleA = -Math.PI / 4 + Math.sin(t += 0.01) * Math.PI / 4; + tree(width / 2 - 75, height, 150, 0, 8); + requestAnimationFrame(draw); + } + + + function randomRange(min, max) { + return min + Math.random() * (max - min); + } + + function tree(x, y, size, angle, limit) { + context.save(); + context.translate(x, y); + context.rotate(angle); + context.fillRect(0, 0, size, -size); + + // left branch + var x0 = 0, + y0 = -size, + size0 = Math.abs(Math.cos(branchAngleA) * size), + angle0 = branchAngleA; + + if(limit > 0) { + tree(x0, y0, size0, angle0, limit - 1); + } + else { + context.save(); + context.translate(x0, y0); + context.rotate(angle0); + context.fillRect(0, 0, size0, -size0); + context.restore(); + } + + // right branch + var x1 = x0 + Math.cos(angle0) * size0, + y1 = y0 + Math.sin(angle0) * size0, + size1 = Math.abs(Math.sin(branchAngleA) * size) + angle1 = angle0 + Math.PI / 2; + + if(limit > 0) { + tree(x1, y1, size1, angle1, limit - 1); + } + else { + context.save(); + context.translate(x1, y1); + context.rotate(angle1); + context.fillRect(0, 0, size1, -size1); + context.restore(); + } + + + context.restore(); + } +}; \ No newline at end of file diff --git a/episode40/treeanim.js b/episode40/treeanim.js new file mode 100644 index 0000000..c1b7ac2 --- /dev/null +++ b/episode40/treeanim.js @@ -0,0 +1,77 @@ + +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var p0 = { + x: width / 2, + y: height - 50 + }, + p1 = { + x: width / 2, + y: 50 + }, + branchAngleA, + branchAngleB, + trunkRatio = 0.35, + tA = Math.PI, + tAS = 0.01, + tB = 0, + tBS = 0.01437; + + + function randomRange(min, max) { + return min + Math.random() * (max - min); + } + + + draw(); + + function draw() { + context.clearRect(0, 0, width, height); + branchAngleA = Math.cos(tA += tAS) * Math.PI / 2; + branchAngleB = Math.cos(tB += tBS) * Math.PI / 2; + + tree(p0, p1, 8); + requestAnimationFrame(draw); + } + + function tree(p0, p1, limit) { + var dx = p1.x - p0.x, + dy = p1.y - p0.y, + dist = Math.sqrt(dx * dx + dy * dy), + angle = Math.atan2(dy, dx), + branchLength = dist * (1 - trunkRatio), + pA = { + x: p0.x + dx * trunkRatio, + y: p0.y + dy * trunkRatio + }, + pB = { + x: pA.x + Math.cos(angle + branchAngleA) * branchLength, + y: pA.y + Math.sin(angle + branchAngleA) * branchLength, + }, + pC = { + x: pA.x + Math.cos(angle + branchAngleB) * branchLength, + y: pA.y + Math.sin(angle + branchAngleB) * branchLength, + }; + + context.beginPath(); + context.moveTo(p0.x, p0.y); + context.lineTo(pA.x, pA.y); + context.stroke(); + + if(limit > 0) { + tree(pA, pC, limit - 1); + tree(pA, pB, limit - 1); + } + else { + context.beginPath(); + context.moveTo(pB.x, pB.y); + context.lineTo(pA.x, pA.y); + context.lineTo(pC.x, pC.y); + context.stroke(); + } + } +}; \ No newline at end of file From 7a7b549789a6711b28299cd2ad161f7e99b57ab5 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Wed, 22 Apr 2015 09:04:08 -0400 Subject: [PATCH 34/39] episode 41 files --- episode41/index.html | 24 ++++++++++ episode41/main.js | 101 +++++++++++++++++++++++++++++++++++++++++++ episode41/math.js | 86 ++++++++++++++++++++++++++++++++++++ 3 files changed, 211 insertions(+) create mode 100644 episode41/index.html create mode 100644 episode41/main.js create mode 100644 episode41/math.js diff --git a/episode41/index.html b/episode41/index.html new file mode 100644 index 0000000..7b8999d --- /dev/null +++ b/episode41/index.html @@ -0,0 +1,24 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/episode41/main.js b/episode41/main.js new file mode 100644 index 0000000..1ad2a69 --- /dev/null +++ b/episode41/main.js @@ -0,0 +1,101 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + tileWidth = 60, + tileHeight = 30; + + context.translate(width / 2, 50); + + var img = document.createElement("img"); + img.addEventListener("load", function() { + draw(); + }); + img.src = "tileset.png"; + + function draw() { + for(var x = 0; x < 25; x++) { + for(var y = 0; y < 25; y++) { + drawImageTile(x, y, Math.floor(Math.random() * 16)); + // drawBlock(x, y, Math.random() * 4, randomColor()); + } + } + } + + function drawImageTile(x, y, index) { + context.save(); + context.translate((x - y) * tileWidth / 2, (x + y) * tileHeight / 2 + (index < 4 ? 5 : 0)); + + context.drawImage(img, index * tileWidth, 0, tileWidth, img.height, + -tileWidth / 2, 0, tileWidth, img.height); + + context.restore(); + } + + function drawBlock(x, y, z) { + var top = "#eeeeee", + right = "#cccccc", + left = "#999999"; + + context.save(); + context.translate((x - y) * tileWidth / 2, (x + y) * tileHeight / 2); + + // draw top + context.beginPath(); + context.moveTo(0, -z * tileHeight); + context.lineTo(tileWidth / 2, tileHeight / 2 - z * tileHeight); + context.lineTo(0, tileHeight - z * tileHeight); + context.lineTo(-tileWidth / 2, tileHeight / 2 - z * tileHeight); + context.closePath(); + context.fillStyle = top; + context.fill(); + + // draw left + context.beginPath(); + context.moveTo(-tileWidth / 2, tileHeight / 2 - z * tileHeight); + context.lineTo(0, tileHeight - z * tileHeight); + context.lineTo(0, tileHeight); + context.lineTo(-tileWidth / 2, tileHeight / 2); + context.closePath(); + context.fillStyle = left; + context.fill(); + + // // draw right + context.beginPath(); + context.moveTo(tileWidth / 2, tileHeight / 2 - z * tileHeight); + context.lineTo(0, tileHeight - z * tileHeight); + context.lineTo(0, tileHeight); + context.lineTo(tileWidth / 2, tileHeight / 2); + context.closePath(); + context.fillStyle = right; + context.fill(); + + + context.restore(); + } + + function randomColor() { + var r = Math.floor(Math.random() * 255); + var g = Math.floor(Math.random() * 255); + var b = Math.floor(Math.random() * 255); + return "rgb(" + r + "," + g + "," + b + ")"; + } + + + function drawTile(x, y, color) { + context.save(); + context.translate((x - y) * tileWidth / 2, (x + y) * tileHeight / 2); + + context.beginPath(); + context.moveTo(0, 0); + context.lineTo(tileWidth / 2, tileHeight / 2); + context.lineTo(0, tileHeight); + context.lineTo(-tileWidth / 2, tileHeight / 2); + context.closePath(); + context.fillStyle = color; + context.fill(); + + context.restore(); + } +} \ No newline at end of file diff --git a/episode41/math.js b/episode41/math.js new file mode 100644 index 0000000..48710a3 --- /dev/null +++ b/episode41/math.js @@ -0,0 +1,86 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight, + tileWidth = 50, + tileHeight = 25; + + context.translate(width / 2, 50); + + for(var x = 0; x < 30; x++) { + for(var y = 0; y < 30; y++) { + var dx = 15 - x, + dy = 15 - y, + dist = Math.sqrt(dx * dx + dy * dy), + z = Math.cos(dist * 0.75) * 2 + 2; + drawBlock(x, y, z, randomColor()); + } + } + + function drawBlock(x, y, z) { + var top = "#eeeeee", + right = "#cccccc", + left = "#999999"; + + context.save(); + context.translate((x - y) * tileWidth / 2, (x + y) * tileHeight / 2); + + // draw top + context.beginPath(); + context.moveTo(0, -z * tileHeight); + context.lineTo(tileWidth / 2, tileHeight / 2 - z * tileHeight); + context.lineTo(0, tileHeight - z * tileHeight); + context.lineTo(-tileWidth / 2, tileHeight / 2 - z * tileHeight); + context.closePath(); + context.fillStyle = top; + context.fill(); + + // draw left + context.beginPath(); + context.moveTo(-tileWidth / 2, tileHeight / 2 - z * tileHeight); + context.lineTo(0, tileHeight - z * tileHeight); + context.lineTo(0, tileHeight); + context.lineTo(-tileWidth / 2, tileHeight / 2); + context.closePath(); + context.fillStyle = left; + context.fill(); + + // draw right + context.beginPath(); + context.moveTo(tileWidth / 2, tileHeight / 2 - z * tileHeight); + context.lineTo(0, tileHeight - z * tileHeight); + context.lineTo(0, tileHeight); + context.lineTo(tileWidth / 2, tileHeight / 2); + context.closePath(); + context.fillStyle = right; + context.fill(); + + + context.restore(); + } + + function randomColor() { + var r = Math.floor(Math.random() * 255); + var g = Math.floor(Math.random() * 255); + var b = Math.floor(Math.random() * 255); + return "rgb(" + r + "," + g + "," + b + ")"; + } + + + function drawTile(x, y, color) { + context.save(); + context.translate((x - y) * tileWidth / 2, (x + y) * tileHeight / 2); + + context.beginPath(); + context.moveTo(0, 0); + context.lineTo(tileWidth / 2, tileHeight / 2); + context.lineTo(0, tileHeight); + context.lineTo(-tileWidth / 2, tileHeight / 2); + context.closePath(); + context.fillStyle = color; + context.fill(); + + context.restore(); + } +} \ No newline at end of file From 196ac750bf9c8b194185885ddd66cae85feca0de Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Mon, 4 May 2015 07:19:53 -0400 Subject: [PATCH 35/39] episode 42 --- episode42/ball.png | Bin 0 -> 2227 bytes episode42/index.html | 24 ++++++ episode42/main.js | 182 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+) create mode 100644 episode42/ball.png create mode 100644 episode42/index.html create mode 100644 episode42/main.js diff --git a/episode42/ball.png b/episode42/ball.png new file mode 100644 index 0000000000000000000000000000000000000000..15507cb9e821789b59c9a744b10e151063e3146f GIT binary patch literal 2227 zcmV;k2u$~hP)fA4bd{cqD*?UWg&drOIe2ndBPrUgxi5+v~hpov5iH$X%PU}R|; zp-@qpkf5IwjENz90a-K(LP`Y+v_)HJJ8dabW`@qz+5Ypt+q?MTP8*aCrJ&ObO_pVxapp>voOU+lYBQmhFHm_Iz^JE)EhBzlH#o+%~R6cAcHDR%^ge(_u^dMgb-IOT-4Kap!e`UuKM;@*uA^& zqZx0$@7|ZXd*-if>*yj31D2k4Hr*W|&IyLc6DFn_G#Uw6o+0okB{8{WvL2J2-4iZOzEefrs_pZeFuAIW&*#yftuX8k4KT)BEZ3l{XSc;Nz?s~Rl?N`gaT zEjYk?k8_aa7Go_+N&uYmsG!6t^Ur2tw2#U0A(RdmFI}>r*4z8mKTiU_<(3<+T($1v zO{-V0rWQy_TA~HW_vEA$2viV&04XHpQiK$O+&GN$I4@?CD3B_kXX&}vyusi*Z=rN> z;i5$gcOE?WRxf})9`u5>7j604`iqetqeN>hFFf}Y{R91^X~NQFUtr;qFOr*x-Z%bD zBTlF`cOq3pb4L%LShQj#Z@&HlNs^+JdJuTx1mhcje$Aa%UiICt*UIIOZLO_apW?+A zw=p_8#K_1nZy!EL=e!|mg8Fa3Rc=;}G0a~*I9~^WUiEh0 zA*?azKp;M1md(_sNaGnMCnkxL1Y;V+NlX-mnA~EWLkKX|A-rUIYLfAhcPIy*TD67N za+!JUZ5$aohQP1V2(fH>s*bUiq2XaB#|CI_?;(lnY~Q|>?s;7_8Z+$KyN^m}7#^LZ z993wY+rr@RQAWqcu-0O&#{+mtDTYw196VU-@E)X;OxNp# zp{71FLy{FUT`Eu#DpgG-&@DO&v?-TDVqx(fhDJtt?1{f)jUh9(2A7O>kLEBaTVZm^902sz!JZN-CsO;62V+ymtsu1g?fv zA`_CDgv6v6ELg~0jz^)SLI_EugFRZqbIQ4^$EWIy*M>31VV%R;KQoiDsrDU=X|QleCVcMhcl_uW2n0gNg0;0sA@Sbfd?6C=iu8N$v99Rd4+1mm)yCvl=Mh4nwI+%}%B6^@ zMtT`gxZqE3yZ0sG{VP&Pq!6gtnt{jT$+C<*x8%m+T)`4wJaw~&0fBR_P`EKT$87zJ zjFqC0KnL4yzx%hlPXGgyl)BV8gLM{x2O%)V6m^?rtfW9Ig_Hs*1xgB}60-~q=J>&^ z15sp8N<|Q8s^zkaD$Ug zrB0~d+M*PAfmRZ&G*KAP+Ek-bE}i#-8}EGiy;$!9-h9Um+`RGr=LPN@g`2`#q!i%6 zSX)@0F&JY=)0jL<3lSLuKp1GkP!og!wMs;LOKq%Lj?VniO&ebQ{e2rg-3R?$xBgf= z^j~u8F8AIm>wGa#jKz9ah|4)VMXxJWh$zsSN-4^#<>=AtFZE|_g{I + + + + + + + + + + + \ No newline at end of file diff --git a/episode42/main.js b/episode42/main.js new file mode 100644 index 0000000..3a7d204 --- /dev/null +++ b/episode42/main.js @@ -0,0 +1,182 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + characterCanvas = document.getElementById("characterCanvas"), + characterContext = characterCanvas.getContext("2d"), + width = canvas.width = characterCanvas.width = window.innerWidth, + height = canvas.height = characterCanvas.height = window.innerHeight, + tileWidth = 60, + tileHeight = 30, + charX = 0.5, + charY = 9.5; + + context.translate(width / 2, 50); + characterContext.translate(width / 2, 50); + + var grid = [ + [15, 15, 15, 14, 13, 10, 3, 2, 1, 0], + [15, 15, 14, 13, 10, 10, 3, 2, 1, 0], + [15, 14, 13, 10, 10, 3, 3, 2, 1, 0], + [14, 13, 10, 9, 3, 3, 2, 1, 0, 0], + [13, 10, 9, 7, 3, 2, 1, 0, 0, 0], + [10, 9, 7, 6, 3, 2, 1, 0, 0, 0], + [9, 7, 6, 5, 3, 2, 1, 1, 1, 1], + [7, 6, 5, 3, 3, 2, 2, 2, 2, 2], + [6, 5, 5, 3, 3, 3, 3, 3, 3, 3], + [5, 5, 5, 5, 5, 5, 5, 5, 5, 3] + ]; + + var img = document.createElement("img"); + img.addEventListener("load", function() { + draw(); + }); + img.src = "tileset.png"; + + var character = document.createElement("img"); + character.addEventListener("load", function() { + drawCharacter(character, charX, charY); + document.body.addEventListener("keydown", moveCharacter); + }); + character.src = "ball.png"; + + function drawCharacter(image, x, y) { + characterContext.clearRect(-width / 2, -50, width, height); + characterContext.save(); + characterContext.translate((x - y) * tileWidth / 2, (x + y) * tileHeight / 2); + + characterContext.drawImage(image, -image.width / 2, -image.height); + + characterContext.restore(); + } + + function moveCharacter(event) { + switch(event.keyCode) { + case 37: // left + if(canMove(charX - 1, charY)) { + charX--; + drawCharacter(character, charX, charY); + } + break; + case 38: // up + if(canMove(charX, charY - 1)) { + charY--; + drawCharacter(character, charX, charY); + } + break; + case 39: // right + if(canMove(charX + 1, charY)) { + charX++; + drawCharacter(character, charX, charY); + } + break; + case 40: // down + if(canMove(charX, charY + 1)) { + charY++; + drawCharacter(character, charX, charY); + } + break; + + } + } + + function canMove(x, y) { + x = Math.floor(x); + y = Math.floor(y); + if(y < 0 || y >= grid.length) { + return false; + } + if(x < 0 || x >= grid[y].length) { + return false; + } + var tile = grid[y][x]; + if(tile < 4 || tile > 14) { + return false; + } + return true; + } + + function draw() { + for(var y = 0; y < grid.length; y++) { + var row = grid[y]; + for(var x = 0; x < row.length; x++) { + drawImageTile(x, y, row[x]); + } + } + } + + function drawImageTile(x, y, index) { + context.save(); + context.translate((x - y) * tileWidth / 2, (x + y) * tileHeight / 2 - 11 + (index < 4 ? 5 : 0)); + + context.drawImage(img, index * tileWidth, 0, tileWidth, img.height, + -tileWidth / 2, 0, tileWidth, img.height); + + context.restore(); + } + + function drawBlock(x, y, z) { + var top = "#eeeeee", + right = "#cccccc", + left = "#999999"; + + context.save(); + context.translate((x - y) * tileWidth / 2, (x + y) * tileHeight / 2); + + // draw top + context.beginPath(); + context.moveTo(0, -z * tileHeight); + context.lineTo(tileWidth / 2, tileHeight / 2 - z * tileHeight); + context.lineTo(0, tileHeight - z * tileHeight); + context.lineTo(-tileWidth / 2, tileHeight / 2 - z * tileHeight); + context.closePath(); + context.fillStyle = top; + context.fill(); + + // draw left + context.beginPath(); + context.moveTo(-tileWidth / 2, tileHeight / 2 - z * tileHeight); + context.lineTo(0, tileHeight - z * tileHeight); + context.lineTo(0, tileHeight); + context.lineTo(-tileWidth / 2, tileHeight / 2); + context.closePath(); + context.fillStyle = left; + context.fill(); + + // // draw right + context.beginPath(); + context.moveTo(tileWidth / 2, tileHeight / 2 - z * tileHeight); + context.lineTo(0, tileHeight - z * tileHeight); + context.lineTo(0, tileHeight); + context.lineTo(tileWidth / 2, tileHeight / 2); + context.closePath(); + context.fillStyle = right; + context.fill(); + + + context.restore(); + } + + function randomColor() { + var r = Math.floor(Math.random() * 255); + var g = Math.floor(Math.random() * 255); + var b = Math.floor(Math.random() * 255); + return "rgb(" + r + "," + g + "," + b + ")"; + } + + + function drawTile(x, y, color) { + context.save(); + context.translate((x - y) * tileWidth / 2, (x + y) * tileHeight / 2); + + context.beginPath(); + context.moveTo(0, 0); + context.lineTo(tileWidth / 2, tileHeight / 2); + context.lineTo(0, tileHeight); + context.lineTo(-tileWidth / 2, tileHeight / 2); + context.closePath(); + context.fillStyle = color; + context.fill(); + + context.restore(); + } +} \ No newline at end of file From 43e91d7f12eada99f8bf2857e5049af8da314857 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Mon, 5 Oct 2015 08:27:27 -0400 Subject: [PATCH 36/39] episode 43 files --- episode43/arm.js | 51 ++++++++++++++++++++++++++++++++++++++++++++ episode43/index.html | 24 +++++++++++++++++++++ episode43/main.js | 33 ++++++++++++++++++++++++++++ episode43/main2.js | 50 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+) create mode 100644 episode43/arm.js create mode 100644 episode43/index.html create mode 100644 episode43/main.js create mode 100644 episode43/main2.js diff --git a/episode43/arm.js b/episode43/arm.js new file mode 100644 index 0000000..bb1f839 --- /dev/null +++ b/episode43/arm.js @@ -0,0 +1,51 @@ +var Arm = Arm || { + x: 0, + y: 0, + length: 100, + angle: 0, + parent: null, + + create: function(x, y, length, angle) { + var obj = Object.create(this); + obj.init(x, y, length, angle); + return obj; + }, + + init: function(x, y, length, angle) { + this.x = x; + this.y = y; + this.length = length; + this.angle = angle; + }, + + getEndX: function() { + var angle = this.angle, + parent = this.parent; + while(parent) { + angle += parent.angle; + parent = parent.parent; + } + return this.x + Math.cos(angle) * this.length; + }, + + getEndY: function() { + var angle = this.angle, + parent = this.parent; + while(parent) { + angle += parent.angle; + parent = parent.parent; + } + return this.y + Math.sin(angle) * this.length; + }, + + render: function(context) { + context.strokeStyle = "#000000"; + context.lineWidth = 5; + context.beginPath(); + context.moveTo(this.x, this.y); + context.lineTo(this.getEndX(), this.getEndY()); + context.stroke(); + } + + +}; \ No newline at end of file diff --git a/episode43/index.html b/episode43/index.html new file mode 100644 index 0000000..1c0c1e9 --- /dev/null +++ b/episode43/index.html @@ -0,0 +1,24 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/episode43/main.js b/episode43/main.js new file mode 100644 index 0000000..f9beabe --- /dev/null +++ b/episode43/main.js @@ -0,0 +1,33 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + + var arm = Arm.create(width / 2, height / 2, 100, 0), + angle = 0, + arm2 = Arm.create(arm.getEndX(), arm.getEndY(), 100, 1.3), + arm3 = Arm.create(arm2.getEndX(), arm2.getEndY(), 100, 1.3) + + arm2.parent = arm; + arm3.parent = arm2; + + update(); + + function update() { + context.clearRect(0, 0, width, height); + arm.angle = Math.sin(angle) * 1.2; + arm2.angle = Math.cos(angle * .5) * .92; + arm3.angle = Math.sin(angle * 1.5) * 1.34; + arm2.x = arm.getEndX(); + arm2.y = arm.getEndY(); + arm3.x = arm2.getEndX(); + arm3.y = arm2.getEndY(); + angle += 0.05; + arm.render(context); + arm2.render(context); + arm3.render(context); + requestAnimationFrame(update); + } +} \ No newline at end of file diff --git a/episode43/main2.js b/episode43/main2.js new file mode 100644 index 0000000..ef53b37 --- /dev/null +++ b/episode43/main2.js @@ -0,0 +1,50 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + canvas2 = document.getElementById("canvas2"), + context = canvas.getContext("2d"), + context2 = canvas2.getContext("2d"), + width = canvas.width = canvas2.width = window.innerWidth, + height = canvas.height = canvas2.height = window.innerHeight, + drawing = false; + + + var arm = Arm.create(width / 2, height / 2, 100, 0), + angle = 0, + arm2 = Arm.create(arm.getEndX(), arm.getEndY(), 100, 1.3), + arm3 = Arm.create(arm2.getEndX(), arm2.getEndY(), 100, 1.3) + + arm2.parent = arm; + arm3.parent = arm2; + context2.lineWidth = 0.25; + + update(); + document.body.addEventListener("click", function() { + drawing = true; + }) + + function update() { + if(drawing) { + context2.beginPath(); + context2.moveTo(arm3.getEndX(), arm3.getEndY()); + } + + context.clearRect(0, 0, width, height); + arm.angle = Math.sin(angle) * 2.476; + arm2.angle = Math.cos(angle * .502 + 2) * 2.92; + arm3.angle = Math.sin(angle * 1.498 - 0.5) * 2.34; + arm2.x = arm.getEndX(); + arm2.y = arm.getEndY(); + arm3.x = arm2.getEndX(); + arm3.y = arm2.getEndY(); + angle += 0.05; + arm.render(context); + arm2.render(context); + arm3.render(context); + + if(drawing) { + context2.lineTo(arm3.getEndX(), arm3.getEndY()); + context2.stroke(); + } + requestAnimationFrame(update); + } +} \ No newline at end of file From 7a38fb67291da63b2cea3424e9a979b93fd0b570 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Sun, 18 Oct 2015 06:09:48 -0400 Subject: [PATCH 37/39] episode 44 files --- episode44/arm.js | 58 +++++++++++++++++++++++++++++++++++++++++++ episode44/fksystem.js | 56 +++++++++++++++++++++++++++++++++++++++++ episode44/index.html | 25 +++++++++++++++++++ episode44/index2.html | 46 ++++++++++++++++++++++++++++++++++ episode44/main.js | 30 ++++++++++++++++++++++ episode44/main2.js | 51 +++++++++++++++++++++++++++++++++++++ 6 files changed, 266 insertions(+) create mode 100644 episode44/arm.js create mode 100644 episode44/fksystem.js create mode 100644 episode44/index.html create mode 100644 episode44/index2.html create mode 100644 episode44/main.js create mode 100644 episode44/main2.js diff --git a/episode44/arm.js b/episode44/arm.js new file mode 100644 index 0000000..9a9991f --- /dev/null +++ b/episode44/arm.js @@ -0,0 +1,58 @@ +var Arm = Arm || { + x: 0, + y: 0, + length: 100, + angle: 0, + centerAngle: 0, + rotationRange: Math.PI / 4, + parent: null, + phaseOffset: 0, + + create: function(length, centerAngle, rotationRange, phaseOffset) { + var obj = Object.create(this); + obj.init(length, centerAngle, rotationRange, phaseOffset); + return obj; + }, + + init: function(length, centerAngle, rotationRange, phaseOffset) { + this.length = length; + this.centerAngle = centerAngle; + this.rotationRange = rotationRange; + this.phaseOffset = phaseOffset; + }, + + setPhase: function(phase) { + this.angle = this.centerAngle + Math.sin(phase + this.phaseOffset) * this.rotationRange; + }, + + getEndX: function() { + var angle = this.angle, + parent = this.parent; + while(parent) { + angle += parent.angle; + parent = parent.parent; + } + return this.x + Math.cos(angle) * this.length; + }, + + getEndY: function() { + var angle = this.angle, + parent = this.parent; + while(parent) { + angle += parent.angle; + parent = parent.parent; + } + return this.y + Math.sin(angle) * this.length; + }, + + render: function(context) { + context.strokeStyle = "#000000"; + context.lineWidth = 5; + context.beginPath(); + context.moveTo(this.x, this.y); + context.lineTo(this.getEndX(), this.getEndY()); + context.stroke(); + } + + +}; \ No newline at end of file diff --git a/episode44/fksystem.js b/episode44/fksystem.js new file mode 100644 index 0000000..26837a8 --- /dev/null +++ b/episode44/fksystem.js @@ -0,0 +1,56 @@ +var FKSystem = FKSystem || { + arms: null, + lastArm: null, + x: 0, + y: 0, + phase: 0, + speed: 0.05, + + create: function(x, y) { + var obj = Object.create(this); + obj.init(x, y); + return obj; + }, + + init: function(x, y) { + this.x = x; + this.y = y; + this.arms = []; + }, + + addArm: function(length, centerAngle, rotationRange, phaseOffset) { + var arm = Arm.create(length, centerAngle, rotationRange, phaseOffset); + this.arms.push(arm); + if(this.lastArm) { + arm.parent = this.lastArm; + } + this.lastArm = arm; + this.update(); + }, + + update: function() { + for(var i = 0; i < this.arms.length; i++) { + var arm = this.arms[i]; + arm.setPhase(this.phase); + if(arm.parent) { + arm.x = arm.parent.getEndX(); + arm.y = arm.parent.getEndY(); + } + else { + arm.x = this.x; + arm.y = this.y; + } + } + this.phase += this.speed; + }, + + render: function(context) { + for(var i = 0; i < this.arms.length; i++) { + this.arms[i].render(context); + } + }, + + rotateArm: function(index, angle) { + this.arms[index].angle = angle; + } +}; \ No newline at end of file diff --git a/episode44/index.html b/episode44/index.html new file mode 100644 index 0000000..9a6aa01 --- /dev/null +++ b/episode44/index.html @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/episode44/index2.html b/episode44/index2.html new file mode 100644 index 0000000..e04e6d3 --- /dev/null +++ b/episode44/index2.html @@ -0,0 +1,46 @@ + + + + + + + + + + + +

+ + \ No newline at end of file diff --git a/episode44/main.js b/episode44/main.js new file mode 100644 index 0000000..c37118a --- /dev/null +++ b/episode44/main.js @@ -0,0 +1,30 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + + var leg0 = FKSystem.create(width / 2, height / 2); + var leg1 = FKSystem.create(width / 2, height / 2); + leg1.phase = Math.PI; + + leg0.addArm(200, Math.PI / 2, Math.PI / 4, 0); + leg0.addArm(180, 0.87, 0.87, -1.5); + leg1.addArm(200, Math.PI / 2, Math.PI / 4, 0); + leg1.addArm(180, 0.87, 0.87, -1.5); + + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + leg0.update(); + leg0.render(context); + leg1.update(); + leg1.render(context); + + requestAnimationFrame(update); + } +} \ No newline at end of file diff --git a/episode44/main2.js b/episode44/main2.js new file mode 100644 index 0000000..f081ca0 --- /dev/null +++ b/episode44/main2.js @@ -0,0 +1,51 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + + var leg0 = FKSystem.create(width / 2, height / 2); + var leg1 = FKSystem.create(width / 2, height / 2); + leg1.phase = Math.PI; + + leg0.addArm(200, Math.PI / 2, Math.PI / 4, 0); + leg0.addArm(180, 0.87, 0.87, -1.5); + leg1.addArm(200, Math.PI / 2, Math.PI / 4, 0); + leg1.addArm(180, 0.87, 0.87, -1.5); + + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + leg0.update(); + leg0.render(context); + leg1.update(); + leg1.render(context); + + requestAnimationFrame(update); + } + + document.getElementById("top_center").addEventListener("input", function(input) { + leg0.arms[0].centerAngle = parseFloat(this.value); + leg1.arms[0].centerAngle = parseFloat(this.value); + }); + document.getElementById("top_range").addEventListener("input", function(input) { + leg0.arms[0].rotationRange = parseFloat(this.value); + leg1.arms[0].rotationRange = parseFloat(this.value); + }); + document.getElementById("bottom_center").addEventListener("input", function(input) { + leg0.arms[1].centerAngle = parseFloat(this.value); + leg1.arms[1].centerAngle = parseFloat(this.value); + }); + document.getElementById("bottom_range").addEventListener("input", function(input) { + leg0.arms[1].rotationRange = parseFloat(this.value); + leg1.arms[1].rotationRange = parseFloat(this.value); + }); + document.getElementById("bottom_phase").addEventListener("input", function(input) { + leg0.arms[1].phaseOffset = parseFloat(this.value); + leg1.arms[1].phaseOffset = parseFloat(this.value); + }); +} \ No newline at end of file From 46f07bf0879625d88e075902f3b2962942491080 Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Mon, 26 Oct 2015 08:10:20 -0400 Subject: [PATCH 38/39] episode 45 files --- episode45/arm.js | 54 +++++++++++++++++++++++++++++++++++++++++++ episode45/iksystem.js | 45 ++++++++++++++++++++++++++++++++++++ episode45/index.html | 25 ++++++++++++++++++++ episode45/main.js | 27 ++++++++++++++++++++++ 4 files changed, 151 insertions(+) create mode 100644 episode45/arm.js create mode 100644 episode45/iksystem.js create mode 100644 episode45/index.html create mode 100644 episode45/main.js diff --git a/episode45/arm.js b/episode45/arm.js new file mode 100644 index 0000000..de989e2 --- /dev/null +++ b/episode45/arm.js @@ -0,0 +1,54 @@ +var Arm = Arm || { + x: 0, + y: 0, + length: 100, + angle: 0, + parent: null, + + create: function(x, y, length, angle) { + var obj = Object.create(this); + obj.init(x, y, length, angle); + return obj; + }, + + init: function(x, y, length, angle) { + this.x = x; + this.y = y; + this.length = length; + this.angle = angle; + }, + + getEndX: function() { + return this.x + Math.cos(this.angle) * this.length; + }, + + getEndY: function() { + return this.y + Math.sin(this.angle) * this.length; + }, + + render: function(context) { + context.strokeStyle = "#000000"; + context.lineWidth = 5; + context.beginPath(); + context.moveTo(this.x, this.y); + context.lineTo(this.getEndX(), this.getEndY()); + context.stroke(); + }, + + pointAt: function(x, y) { + var dx = x - this.x, + dy = y - this.y; + this.angle = Math.atan2(dy, dx); + }, + + drag: function(x, y) { + this.pointAt(x, y); + this.x = x - Math.cos(this.angle) * this.length; + this.y = y - Math.sin(this.angle) * this.length; + if(this.parent) { + this.parent.drag(this.x, this.y); + } + } + + +}; \ No newline at end of file diff --git a/episode45/iksystem.js b/episode45/iksystem.js new file mode 100644 index 0000000..421030c --- /dev/null +++ b/episode45/iksystem.js @@ -0,0 +1,45 @@ +var IKSystem = IKSystem || { + x: 0, + y: 0, + arms: null, + lastArm: null, + + + create: function(x, y) { + var obj = Object.create(this); + obj.init(x, y); + return obj; + }, + + init: function(x, y) { + this.x = x; + this.y = y; + this.arms = []; + }, + + addArm: function(length) { + var arm = Arm.create(0, 0, length, 0); + if(this.lastArm) { + arm.x = this.lastArm.getEndX(); + arm.y = this.lastArm.getEndY(); + arm.parent = this.lastArm; + } + else { + arm.x = this.x; + arm.y = this.y; + } + this.arms.push(arm); + this.lastArm = arm; + }, + + render: function(context) { + for(var i = 0; i < this.arms.length; i++) { + this.arms[i].render(context); + } + }, + + drag: function(x, y) { + this.lastArm.drag(x, y); + } + +}; \ No newline at end of file diff --git a/episode45/index.html b/episode45/index.html new file mode 100644 index 0000000..09db801 --- /dev/null +++ b/episode45/index.html @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/episode45/main.js b/episode45/main.js new file mode 100644 index 0000000..92fb22e --- /dev/null +++ b/episode45/main.js @@ -0,0 +1,27 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + + var iks = IKSystem.create(width / 2, height / 2); + for(var i = 0; i < 20; i++) { + iks.addArm(30); + } + + + document.body.addEventListener("mousemove", function(event) { + iks.drag(event.clientX, event.clientY); + }); + + update(); + + function update() { + context.clearRect(0, 0, width, height); + + iks.render(context); + + requestAnimationFrame(update); + } +} \ No newline at end of file From 793b665fa0eff6607ad6a11ad9dee8a371b3f4fe Mon Sep 17 00:00:00 2001 From: Keith Peters Date: Sun, 13 Mar 2016 19:26:16 -0400 Subject: [PATCH 39/39] episode 47 --- episode47/index.html | 23 +++++++++++++++++++ episode47/main.js | 53 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 episode47/index.html create mode 100644 episode47/main.js diff --git a/episode47/index.html b/episode47/index.html new file mode 100644 index 0000000..5989d5a --- /dev/null +++ b/episode47/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/episode47/main.js b/episode47/main.js new file mode 100644 index 0000000..30f2f73 --- /dev/null +++ b/episode47/main.js @@ -0,0 +1,53 @@ +window.onload = function() { + var canvas = document.getElementById("canvas"), + context = canvas.getContext("2d"), + width = canvas.width = window.innerWidth, + height = canvas.height = window.innerHeight; + + var prizes = [{ + prize: "nothing!", + chance: 8 + }, + { + prize: "a gold piece", + chance: 5 + }, + { + prize: "a treasure chest", + chance: 2 + }, + { + prize: "poison", + chance: 1 + }, + { + prize: "food", + chance: 3 + } + ]; + + document.body.addEventListener("click", function() { + var prize = getPrize(); + + console.log("You won " + prize); + + }); + + function getPrize(rand) { + var total = 0; + for(var i = 0; i < prizes.length; i++) { + total += prizes[i].chance; + } + + var rand = Math.random() * total; + + for(var i = 0; i < prizes.length; i++) { + var prize = prizes[i]; + if(rand < prize.chance) { + return prize.prize; + } + rand -= prize.chance; + } + + } +} \ No newline at end of file

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 RFV%W;EAC(l_wI1={{R#U;^hDU literal 0 HcmV?d00001 diff --git a/episode22/postcard1.jpg b/episode22/postcard1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5b5d7f10d7b2412a550275f76bbce57115ba0192 GIT binary patch literal 60833 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 z�VytUB_0U*ltqRGXNJ4O^~D@26NOEhK#E4k$P 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