xxxxxxxxxx
476
let canvasW = 400;
let canvasH = 400;
let hudHeight = 40;
let m = 20;
let x0;
let y0;
let x1;
let y1;
let x2;
let y2;
let a = 0;
let b = 0;
let minA = 2 * m;
let maxA = canvasH / 2 - 70;
let minB = 2 * m;
let maxB = canvasH / 2 - 70;
let backgroundColor;
let triangleFillColor;
let triangleStrokeColor;
let aSqFillColor;
let aSqStrokeColor;
let bSqFillColor;
let bSqStrokeColor;
let cSqFillColor;
let cSqStrokeColor;
let A = 0, B = 1, C = 2;
let currentlyAt = A;
let easing = false;
let triEasing = false;
let easeCounter = 0;
let easeFrames = 30;
let angleA = 0, angleB = 0, angleC;
let currentAngle = angleA;
let toAngle, fromAngle;
let currentX, currentY;
let toX, fromX, toY, fromY;
let toA, fromA, toB, fromB;
let ROOT_2 = 1.4142135623730950488016887242097;
function setup()
{
createCanvas(canvasW, canvasH);
backgroundColor = color(20);
triangleFillColor = color(255, 200);
triangleStrokeColor = color(255, 255);
aSqFillColor = color(250, 80, 120, 200);
aSqStrokeColor = color(255, 200, 215, 255);
bSqFillColor = color(50, 200, 100, 200);
bSqStrokeColor = color(200, 255, 215, 255);
cSqFillColor = color(50, 100, 200, 200);
cSqStrokeColor = color(200, 215, 255, 255);
Begin();
}
function draw()
{
background(backgroundColor);
if (easing)
Ease();
else if (triEasing)
EaseTriangle();
DrawGrid();
DrawTriangle();
DrawSquares();
PrintLetters();
}
function Begin()
{
fromA = a;
fromB = b;
toA = random(minA, maxA);
toB = random(minB, maxB);
x1 = canvasW - b - 10;
y1 = canvasH - a - 10;
x0 = x1 - a;
y0 = y1;
x2 = x1;
y2 = y1 - b;
currentX = x0;
currentY = y0 + a;
angleC = -atan2(b, a);
BeginEasingTriangle();
}
function DrawGrid()
{
let vertHalfCount = int(ROOT_2 * canvasW / m);
let horizHalfCount = int(ROOT_2 * canvasH / m);
let color0 = color(255, 180);
let color1 = color(255, 80);
push();
strokeWeight(1);
translate(currentX, currentY);
rotate(currentAngle);
for (let i = -vertHalfCount; i < vertHalfCount; ++i)
{
stroke(i % 2 === 0 ? color0 : color1);
line(i * m, -ROOT_2 * canvasH, i * m, ROOT_2 * canvasH);
}
for (let i = -horizHalfCount; i < horizHalfCount; ++i)
{
stroke(i % 2 === 0 ? color0 : color1);
line(-ROOT_2 * canvasW, i * m, ROOT_2 * canvasW, i * m);
}
strokeWeight(2);
stroke(color(250, 50, 50));
line(-ROOT_2 * canvasW, 0, ROOT_2 * canvasW, 0);
stroke(color(50, 250, 100));
line(0, -ROOT_2 * canvasH, 0, ROOT_2 * canvasH);
pop();
}
function DrawTriangle()
{
push();
fill(triangleFillColor);
noStroke();
triangle(x0, y0, x1, y1, x2, y2);
pop();
}
function DrawSquares()
{
let aY = y0 + a;
let bX = x1 + b;
let c0X = x0 - b;
let c0Y = y0 - a;
let c1X = x2 - b;
let c1Y = y2 - a;
push();
strokeWeight(1);
// square C
fill(cSqFillColor);
stroke(cSqStrokeColor);
quad(x2, y2, x0, y0, c0X, c0Y, c1X, c1Y);
// square A
fill(aSqFillColor);
stroke(aSqStrokeColor);
quad(x0, y0, x1, y1, x1, aY, x0, aY);
// square B
fill(bSqFillColor);
stroke(bSqStrokeColor);
quad(x1, y1, x2, y2, bX, y2, bX, y1);
pop();
}
function PrintLetters()
{
let aMidX = (x0 + x1) / 2;
let aMidY = y0;
let bMidX = x1;
let bMidY = (y1 + y2) / 2;
let cMidX = aMidX;
let cMidY = bMidY;
let aX = aMidX - 5;
let aY = aMidY + a / 2 + 7;
let bX = bMidX + b / 2 - 5;
let bY = bMidY + 7;
let cX = (x0 + (x2 - b)) / 2 - 5;
let cY = (y0 + (y2 - a)) / 2 + 7;
let letterSize = 1.25 * m;
let exponentSize = 0.8 * m;
let exponentOffsetX = letterSize / 2;
let exponentOffsetY = -letterSize * 3 / 5;
let currentColor = color(255, 255, 0);
let defaultColor = color(255, 200);
push();
{
stroke(color(0, 120));
strokeWeight(6);
textStyle(BOLD);
textAlign(CENTER, CENTER);
push();
{
fill(currentlyAt === A ? currentColor : defaultColor);
push();
{
translate(aX, aY);
textSize(letterSize);
text("a", 0, 0);
translate(exponentOffsetX, exponentOffsetY);
textSize(exponentSize);
text("2", 0, 0);
}
pop();
push();
{
if (currentlyAt === A)
{
push();
{
stroke(currentColor);
strokeWeight(4);
line(x0, y0, x1, y1);
}
pop();
}
translate(aMidX, aMidY);
textSize(exponentSize);
text("a", 0, 0);
}
pop();
fill(currentlyAt === B ? currentColor : defaultColor);
push();
{
translate(bX, bY);
textSize(letterSize)
text("b", 0, 0);
translate(exponentOffsetX, exponentOffsetY);
textSize(exponentSize);
text("2", 0, 0);
}
pop();
push();
{
if (currentlyAt === B)
{
push();
{
stroke(currentColor);
strokeWeight(4);
line(x1, y1, x2, y2);
}
pop();
}
translate(bMidX, bMidY);
textSize(exponentSize);
text("b", 0, 0);
}
pop();
fill(currentlyAt === C ? currentColor : defaultColor);
push();
{
translate(cX, cY);
textSize(letterSize)
text("c", 0, 0);
translate(exponentOffsetX, exponentOffsetY);
textSize(exponentSize);
text("2", 0, 0);
}
pop();
push();
{
if (currentlyAt === C)
{
push();
{
stroke(currentColor);
strokeWeight(4);
line(x0, y0, x2, y2);
}
pop();
}
translate(cMidX, cMidY);
textSize(exponentSize);
text("c", 0, 0);
}
pop();
}
pop();
}
pop();
}
function keyPressed()
{
if (easing || triEasing)
return;
if (keyCode === 32)
Begin();
else if (keyCode === 65)
AttemptEaseTo(A);
else if (keyCode === 66)
AttemptEaseTo(B);
else if (keyCode === 67)
AttemptEaseTo(C);
else if (keyCode === RIGHT_ARROW)
EaseToNext();
else if (keyCode === LEFT_ARROW)
EaseToPrev();
}
function AttemptEaseTo(destination)
{
if (currentlyAt === destination)
return;
EaseTo(destination);
}
function EaseToNext()
{
switch (currentlyAt)
{
default: // case A
EaseTo(B);
break;
case B:
EaseTo(C);
break;
case C:
EaseTo(A);
break;
}
}
function EaseToPrev()
{
switch (currentlyAt)
{
default: // case A
EaseTo(C);
break;
case B:
EaseTo(A);
break;
case C:
EaseTo(B);
break;
}
}
function EaseTo(destination)
{
fromAngle = currentAngle;
fromX = currentX;
fromY = currentY;
switch (destination)
{
default: // case A
toAngle = angleA;
toX = x0;
toY = y0 + a;
break;
case B:
toAngle = angleB;
toX = x1;
toY = y1;
break;
case C:
toAngle = angleC;
toX = x0;
toY = y0;
break;
}
easing = true;
easeCounter = 0;
currentlyAt = destination;
}
function Ease()
{
++easeCounter;
let t = easeCounter / easeFrames;
let interpolant = t < 0.5 ? EaseA(2 * t) / 2 : EaseB(2 * t - 1) / 2 + 0.5;
currentAngle = lerp(fromAngle, toAngle, interpolant);
currentX = lerp(fromX, toX, interpolant);
currentY = lerp(fromY, toY, interpolant);
if (easeCounter >= easeFrames)
EndEasing();
}
function EndEasing()
{
currentAngle = toAngle;
currentX = toX;
currentY = toY;
easing = false;
}
function BeginEasingTriangle()
{
triEasing = true;
easeCounter = 0;
}
function EaseTriangle()
{
++easeCounter;
let t = easeCounter / easeFrames;
let interpolant = t < 0.5 ? EaseA(2 * t) / 2 : EaseB(2 * t - 1) / 2 + 0.5;
a = lerp(fromA, toA, interpolant);
b = lerp(fromB, toB, interpolant);
x1 = canvasW - b - 10;
y1 = canvasH - a - 10;
x0 = x1 - a;
y0 = y1;
x2 = x1;
y2 = y1 - b;
angleC = -atan2(b, a);
switch (currentlyAt)
{
default: // case A
currentX = x0;
currentY = y0 + a;
currentAngle = angleA;
break;
case B:
currentX = x1;
currentY = y1;
currentAngle = angleB;
break;
case C:
currentX = x0;
currentY = y0;
currentAngle = angleC;
break;
}
if (easeCounter >= easeFrames)
EndEasingTriangle();
}
function EndEasingTriangle()
{
a = toA;
b = toB;
x1 = canvasW - b - 10;
y1 = canvasH - a - 10;
x0 = x1 - a;
y0 = y1;
x2 = x1;
y2 = y1 - b;
triEasing = false;
}
function EaseA(t) { return pow(t, 2.0); }
function EaseB(t) { return 1 - EaseA(1 - t); }