xxxxxxxxxx
260
let updraft;
let particles = [];
let gravity = 0.5;
let xSpeed = 1.0;
let WIDTH, HEIGHT;
function vectorTo(x1,y1,x2,y2) {
let dx = x1 - y2;
let dy = y1 - y2;
let m = max(abs(dx), abs(dy));
return [dx/m, dy/m];
}
class particle {
constructor(x, y, s) {
this.x = x;
this.y = y;
this.vx = random(-0.5, 0.5);
this.vy = random(-0.5, 0.5);
this.s = s;
this.col = random(30, 120);
this.budge = random(0.1, 0.3);
}
bounds() {
let friction = 0.9;
let ceiling = false;
if (this.x > WIDTH/2 - this.s / 2) {
this.x = WIDTH/2 - this.s / 2;
this.vx = 0;
this.vy *= friction;
}
if (this.x < -WIDTH/2 + this.s / 2) {
this.x = -WIDTH/2 + this.s / 2;
this.vx = 0;
this.vy *= friction;
}
if (this.y > height/2 - this.s / 2) {
this.y = height/2 - this.s / 2;
this.vy = 0;
this.vx *= friction;
}
if (this.y < -height/2 + this.s / 2 && ceiling) {
this.y = -height/2 + this.s / 2;
this.vy = 0;
this.vx *= friction;
}
}
wind() {
let dx = abs(this.x - updraft.x);
let dy = abs(this.y - height/2-20);
let VX = (this.x - updraft.x); VX /= abs(VX);
let VY = 1 * map(dx, 0, updraft.width, 1, 0) * map(dy, 0, updraft.height, 1, 0.55);
// Lessen x strength based on distance
VX *= min(pow(updraft.width, 2.6)/(pow(dx, 3)), 1);
// Closer to the top Shoot outwards
let effect = min(map(dy, 0, updraft.height, 0, 1), 1);
let VX1 = -VX * effect * effect;
VX += VX1;
// VX *= (map(dy, 0, height/2, 0.9, 1) * map(dy, 0, height, 1, 0.5));
let vx1 = VX * updraft.hStrength * this.budge;
let vy1 = VY * updraft.vStrength * this.budge;
return [-vx1, -vy1];
}
move(deltaT) {
deltaT = deltaT || 1;
this.budge = lerp(this.budge, 1, 0.01*deltaT);
// Gravity
this.vy += gravity * deltaT;
let windVel = this.wind();
let weightInfluence = map(this.s, 0, 16, 1.5, 0.8);
this.vx += windVel[0] * weightInfluence * deltaT;
this.vy += windVel[1] * (weightInfluence * 0.8) * deltaT;
this.x += this.vx * deltaT;
this.y += this.vy * deltaT;
this.bounds();
}
draw() {
fill(this.col);
// fill(255);
noStroke();
ellipse(this.x, this.y, this.s);
}
}
class Updraft {
constructor(x) {
this.x = x || 0;
this.X = this.x;
this.vx = 0;
this.width = 200;
this.height = 600;
this.center = height / 2;
this.hStrength = 0.8;
this.vStrength = 0.8;
this.t = 0;
}
move(deltaT) {
// this.t += deltaT * 0.25;
this.vx += random(-0.2, 0.2) * deltaT;
this.vx = min(max(this.vx, -5), 5);
this.x += this.vx * deltaT;
if (this.x < -WIDTH/2+this.width/2) {
this.x = -WIDTH/2+this.width/2;
this.vx = 0;
} else if (this.x > WIDTH/2-this.width/2) {
this.x = WIDTH/2-this.width/2;
this.vx = 0;
}
// this.x = min(max(this.x, -WIDTH/2+this.width/2), WIDTH/2-this.width/2);
// this.x = this.X + sin(this.t) * (width/2-this.width/2);
}
draw() {
noFill();
stroke(120, 60, 60);
rect(this.x-this.width/2, 10, this.width, this.height-20);
}
}
function initParticles() {
Volume = 0;
tornadoSound.setVolume(0);
let minscore = 6;
let maxscore = 20;
for (let i=0; i<400; i++) {
let size = floor(minscore+(maxscore-minscore)*pow(random(), 2));
particles.push(new particle(random(WIDTH)-WIDTH/2, height-size/2, size));
}
}
function runParticles() {
for (let i=0; i<particles.length; i++) {
let p = particles[i];
p.move(xSpeed);
p.draw();
}
}
class SoundLoop {
constructor(soundFunc, delay) {
this.sound = soundFunc;
this.delay = delay;
this.time = 0;
}
run(deltaT) {
deltaT = deltaT || 1;
this.time += deltaT / getFrameRate();
if (this.time >= this.delay) {
this.time = 0;
this.sound();
}
}
}
function onSoundLoop() {
tornadoSound.stop();
tornadoSound.play();
}
function preload() {
tornadoSound = loadSound("assets/tornadoSound.wav");
}
function setup() {
createCanvas(1600, 600);
WIDTH = width;
updraft = new Updraft();
initParticles();
background(20);
angleMode(DEGREES);
speedSlider = createSlider(1, 20, 10);
widthSlider = createSlider(1, width, 10);
heightSlider = createSlider(1, 20, 6);
hStrengthSlider = createSlider(1, 20, 9);
vStrengthSlider = createSlider(1, 20, 9);
scaleSlider = createSlider(1, 20, 20);
let speedTxt = createElement("h3", "speed");
speedTxt.style("color","white");
speedTxt.position(45, height-4);
let widthTxt = createElement("h3", "x size");
widthTxt.style("color","white");
widthTxt.position(175, height-4);
let heightTxt = createElement("h3", "y size");
heightTxt.style("color","white");
heightTxt.position(310, height-4);
let hStrengthTxt = createElement("h3", "x strength");
hStrengthTxt.style("color","white");
hStrengthTxt.position(420, height-4);
let vStrengthTxt = createElement("h3", "y strength");
vStrengthTxt.style("color","white");
vStrengthTxt.position(560, height-4);
let scaleTxt = createElement("h3", "scale");
scaleTxt.style("color","white");
scaleTxt.position(710, height-4);
// Tornado Sound
Volume = 0;
MaxVolume = 0.5;
VolumeLerpSpeed = 0.01;
tornadoSound.setVolume(0);
tornadoSound.play();
let intervalInSeconds = 16.5;
soundLoop = new SoundLoop(onSoundLoop, intervalInSeconds);
}
function keyPressed() {
if (keyCode == 32) {
particles = [];
initParticles();
}
}
function draw() {
// Sound
tornadoSound.rate(xSpeed);
MaxVolume = (widthSlider.value() / 20) * (hStrengthSlider.value() / 20);
Volume = lerp(Volume, MaxVolume, VolumeLerpSpeed);
tornadoSound.setVolume(Volume);
soundLoop.run(xSpeed);
xSpeed = speedSlider.value() / 10;
updraft.width = widthSlider.value() * 20;
updraft.height = heightSlider.value() * 100;
updraft.hStrength = hStrengthSlider.value() / 10;
updraft.vStrength = vStrengthSlider.value() / 10;
background(20, 30);
push();
let scl = scaleSlider.value() / 20;
WIDTH = width / scl;
HEIGHT = height;
translate(width/2, height - height/2*scl);
scale(scl);
// updraft.draw();
updraft.move(xSpeed);
runParticles();
pop();
}