xxxxxxxxxx
138
//Just drag and release the block!
//Note: I made this simulation quickly,
//so the program may benefit from refactoring, etc.
//VARIABLES
let cnv; //canvas
let spring;
let block;
let ground;
let X0; //X-coordinate of equilibrium position
let dVelocities = []; //dragged velocities
let dVelocitiesSum; //sum of dragged velocities
let timeWindow = 10; //window for running average
let h = 0.1; //step size
let t = 0; //time
let released = true;
let tex; //used for typesetting
let slidingSound;
let soundLoop;
//CUSTOM FUNCTIONS
function xPrime(t, v) {
return v.y;
}
function yPrime(t, v) {
let m = block.mass;
let d = ground.damping;
let k = spring.stiffness;
return -(d / m) * v.y - (k / m) * v.x;
}
function vPrime(t, v) {
return createVector(xPrime(t, v), yPrime(t, v));
}
//PRELOAD, SETUP, AND DRAW
function preload() {
soundFormats('wav');
slidingSound = loadSound('sliding');
}
function setup() {
cnv = createCanvas(400, 400);
cursor('grab');
soundLoop = new p5.SoundLoop(onSoundLoop);
spring = createSpring(0, height - 75);
X0 = spring.X;
spring.stiffness = 2;
block = createBlock(spring); //attach block to spring
block.mass = 1;
ground = createGround(height - (block.Y + block.height));
ground.damping = 0.5;
//KaTeX (mathematical typesetting)
//For background, see:
//https://discourse.processing.org/t/latex-in-processing/19691/6
cnv.parent('canvas');
tex = createP();
tex.parent('canvas');
tex.style('font-size', '20px');
tex.style('color', 'rgb(50, 50, 50)');
tex.position(X0 - 30, 100);
katex.render('x = 0', tex.elt);
}
function draw() {
background(229, 255, 234);
stroke(100);
strokeWeight(1);
line(X0, 0, X0, height);
fill(229, 255, 234);
noStroke();
rect(X0-40, 115, 80, 40);
ground.draw();
spring.draw();
block.draw();
slidingSound.setVolume(abs(spring.velocity) / 30);
//update state based on diff eq if mouse is released
if (released) {
//update spring.v, i.e. <spring.position, spring.velocity>
spring.v = rk(t, spring.v, vPrime, h); //Runge-Kutta
t += h;
}
//update velocity based on mouse position
//when it's grabbing the block;
//use a running average to smooth out sudden changes,
//so that sound isn't choppy
else {
//store recent velocities
dVelocities.push(movedX / (deltaTime / 1000));
if (dVelocities.length > timeWindow) {
dVelocities.shift(); //remove old velocities
}
//update spring velocity to equal running average velocity
dVelocitiesSum = 0;
for (let i = 0; i < dVelocities.length; i++) {
dVelocitiesSum += dVelocities[i];
}
spring.velocity = dVelocitiesSum / dVelocities.length;
}
}
//INTERACTIVITY
function mousePressed() {
released = false;
cursor('grabbing');
soundLoop.start();
}
function mouseDragged() {
released = false;
spring.length = mouseX - spring.leftX - 2 * spring.endLength;
}
function mouseReleased() {
released = true;
cursor('grab');
t = 0;
spring.velocity = 0;
dVelocitiesSum = 0;
}
//SOUND LOOP CALLBACK
function onSoundLoop() {
slidingSound.play();
}