230 lines
No EOL
6.3 KiB
JavaScript
230 lines
No EOL
6.3 KiB
JavaScript
let myFont;
|
|
function preload() {
|
|
myFont = loadFont('assets/fonts/nabla.ttf');
|
|
}
|
|
|
|
function setup() {
|
|
if (windowWidth <= 480) {
|
|
var canvas = createCanvas(windowWidth, 200);
|
|
} else {
|
|
var canvas = createCanvas(windowWidth, 300);
|
|
}
|
|
canvas.parent('shrinkin-sketch')
|
|
}
|
|
|
|
function windowResized() {
|
|
if (windowWidth <= 480) {
|
|
var canvas = resizeCanvas(windowWidth, 200);
|
|
} else {
|
|
var canvas = resizeCanvas(windowWidth, 300);
|
|
}
|
|
}
|
|
|
|
class Ball {
|
|
constructor(x, y, r) {
|
|
this.position = new p5.Vector(x, y);
|
|
this.velocity = p5.Vector.random2D();
|
|
this.velocity.mult(3);
|
|
this.r = r;
|
|
this.m = r * 0.1;
|
|
|
|
|
|
}
|
|
|
|
update() {
|
|
this.position.add(this.velocity);
|
|
}
|
|
|
|
checkBoundaryCollision() {
|
|
if (this.position.x > width - this.r) {
|
|
this.position.x = width - this.r;
|
|
this.velocity.x *= -1;
|
|
} else if (this.position.x < this.r) {
|
|
this.position.x = this.r;
|
|
this.velocity.x *= -1;
|
|
} else if (this.position.y > height - this.r) {
|
|
this.position.y = height - this.r;
|
|
this.velocity.y *= -1;
|
|
} else if (this.position.y < this.r) {
|
|
this.position.y = this.r;
|
|
this.velocity.y *= -1;
|
|
}
|
|
}
|
|
|
|
checkCollision(other) {
|
|
// Get distances between the balls components
|
|
let distanceVect = p5.Vector.sub(other.position, this.position);
|
|
|
|
// Calculate magnitude of the vector separating the balls
|
|
let distanceVectMag = distanceVect.mag();
|
|
|
|
// Minimum distance before they are touching
|
|
let minDistance = this.r + other.r;
|
|
|
|
if (distanceVectMag < minDistance) {
|
|
let distanceCorrection = (minDistance - distanceVectMag) / 2.0;
|
|
let d = distanceVect.copy();
|
|
let correctionVector = d.normalize().mult(distanceCorrection);
|
|
other.position.add(correctionVector);
|
|
this.position.sub(correctionVector);
|
|
|
|
// get angle of distanceVect
|
|
let theta = distanceVect.heading();
|
|
// precalculate trig values
|
|
let sine = sin(theta);
|
|
let cosine = cos(theta);
|
|
|
|
/* bTemp will hold rotated ball this.positions. You
|
|
just need to worry about bTemp[1] this.position*/
|
|
let bTemp = [new p5.Vector(), new p5.Vector()];
|
|
|
|
/* this ball's this.position is relative to the other
|
|
so you can use the vector between them (bVect) as the
|
|
reference point in the rotation expressions.
|
|
bTemp[0].this.position.x and bTemp[0].this.position.y will initialize
|
|
automatically to 0.0, which is what you want
|
|
since b[1] will rotate around b[0] */
|
|
bTemp[1].x = cosine * distanceVect.x + sine * distanceVect.y;
|
|
bTemp[1].y = cosine * distanceVect.y - sine * distanceVect.x;
|
|
|
|
// rotate Temporary velocities
|
|
let vTemp = [new p5.Vector(), new p5.Vector()];
|
|
|
|
vTemp[0].x = cosine * this.velocity.x + sine * this.velocity.y;
|
|
vTemp[0].y = cosine * this.velocity.y - sine * this.velocity.x;
|
|
vTemp[1].x = cosine * other.velocity.x + sine * other.velocity.y;
|
|
vTemp[1].y = cosine * other.velocity.y - sine * other.velocity.x;
|
|
|
|
/* Now that velocities are rotated, you can use 1D
|
|
conservation of momentum equations to calculate
|
|
the final this.velocity along the x-axis. */
|
|
let vFinal = [new p5.Vector(), new p5.Vector()];
|
|
|
|
// final rotated this.velocity for b[0]
|
|
vFinal[0].x =
|
|
((this.m - other.m) * vTemp[0].x + 2 * other.m * vTemp[1].x) /
|
|
(this.m + other.m);
|
|
vFinal[0].y = vTemp[0].y;
|
|
|
|
// final rotated this.velocity for b[0]
|
|
vFinal[1].x =
|
|
((other.m - this.m) * vTemp[1].x + 2 * this.m * vTemp[0].x) /
|
|
(this.m + other.m);
|
|
vFinal[1].y = vTemp[1].y;
|
|
|
|
// hack to avoid clumping
|
|
bTemp[0].x += vFinal[0].x;
|
|
bTemp[1].x += vFinal[1].x;
|
|
|
|
/* Rotate ball this.positions and velocities back
|
|
Reverse signs in trig expressions to rotate
|
|
in the opposite direction */
|
|
// rotate balls
|
|
let bFinal = [new p5.Vector(), new p5.Vector()];
|
|
|
|
bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y;
|
|
bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x;
|
|
bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y;
|
|
bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x;
|
|
|
|
// update balls to screen this.position
|
|
other.position.x = this.position.x + bFinal[1].x;
|
|
other.position.y = this.position.y + bFinal[1].y;
|
|
|
|
this.position.add(bFinal[0]);
|
|
|
|
// update velocities
|
|
this.velocity.x = cosine * vFinal[0].x - sine * vFinal[0].y;
|
|
this.velocity.y = cosine * vFinal[0].y + sine * vFinal[0].x;
|
|
other.velocity.x = cosine * vFinal[1].x - sine * vFinal[1].y;
|
|
other.velocity.y = cosine * vFinal[1].y + sine * vFinal[1].x;
|
|
}
|
|
}
|
|
|
|
display(friend1, friend2) {
|
|
this.update()
|
|
noStroke();
|
|
fill('#ff0000');
|
|
ellipse(this.position.x, this.position.y, this.r * 2, this.r * 2);
|
|
this.checkBoundaryCollision()
|
|
this.checkCollision(friend1)
|
|
this.checkCollision(friend2)
|
|
|
|
}
|
|
}
|
|
|
|
class Logo {
|
|
constructor() {
|
|
this.yOffset = 0
|
|
this.up = false
|
|
this.textSize = 36
|
|
this.bounceDepth = 10
|
|
this.speed = 0.2
|
|
}
|
|
|
|
display() {
|
|
fill('#20d582');
|
|
textFont(myFont);
|
|
|
|
if (windowWidth/6 > 120) {
|
|
textSize(120);
|
|
} else {
|
|
textSize(windowWidth/6)
|
|
}
|
|
|
|
if (windowWidth <= 480) {
|
|
text('shrinkin', width/2 - 120, 20 + 60 + this.yOffset);
|
|
text('-minkin', width/2 - 120, 100 + 60 + this.yOffset);
|
|
} else {
|
|
text('shrinkin', width/2 - 120, 50 + 90 + this.yOffset);
|
|
text('-minkin', width/2 - 120, 150 + 90 + this.yOffset);
|
|
}
|
|
|
|
this.bounce()
|
|
}
|
|
|
|
bounce() {
|
|
if (!this.up) {
|
|
if (this.yOffset <= this.bounceDepth) {
|
|
this.yOffset = this.yOffset + this.speed
|
|
}
|
|
if (this.yOffset > this.bounceDepth) {
|
|
this.up = true
|
|
}
|
|
} else {
|
|
if (this.yOffset > 0) {
|
|
this.yOffset = this.yOffset - this.speed
|
|
}
|
|
if (this.yOffset < 0) {
|
|
this.up = false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
let ball1 = new Ball(100, 400, 20)
|
|
let ball2 = new Ball(700, 400, 80)
|
|
let ball3 = new Ball(0, 200, 60)
|
|
let logo = new Logo()
|
|
|
|
|
|
function draw() {
|
|
background('#209bd0');
|
|
|
|
|
|
ball1.display(ball2, ball3)
|
|
ball2.display(ball1, ball3)
|
|
ball3.display(ball1, ball2)
|
|
|
|
if (windowWidth <= 480) {
|
|
ball2.r = 40;
|
|
ball3.r = 30;
|
|
} else {
|
|
ball2.r = 80;
|
|
ball3.r = 60;
|
|
}
|
|
|
|
logo.display()
|
|
|
|
} |