xxxxxxxxxx
561
// this is going to be the art project.
let osc;
// constants of nature
deltaT = 0.1;
m_BH = 20000;
G = 100;
m_item = 200*0;
radforce = 5000000;
//soundamp = 20000000;
soundamp = 5000000
//soundamp = 100000;
//soundfreq = 200000;
soundfreq = 150000;
origParticles = 20;
hawkingVelocity = 40;
// black hole coords
x = 0;
y = 0;
vx = 0;
vy = 0;
rad = 25;
soundrad = 100;
deltarad = 1;
deltaM = 10;
defaultOmega = 50;
// coords for other objects
/*var xs = [100, 100];
var ys = [100, 200];
// velocities for the other objects
var vxs = [0,0];
var vys = [100,-100];
// the relative angle for each object
var thetas = [0,0];
var omegas = [defaultOmega,defaultOmega];
var objColors = [[0,0,0],[1,1,1]];*/
var xs = [];
var ys = [];
// velocities for the other objects
var vxs = [];
var vys = [];
// the relative angle for each object
var thetas = [];
var omegas = [];
var objColors = [];
// the sound for each object
var oscs = [];
var reverbs = [];
num_stars = 1000;
// the stuff for the stars
var starsX = [];
var starsY = [];
var starSize = [];
starMaxSize = 10;
// the colors
var star_color;
var bg_color;
var bh_color;
var thing_color;
var thing_colors = [];
var eaten_colors = [];
var eaten_number = origParticles;
// and finally, the color splatters in the hawking phase
var splatterAngles = [];
var splatterColors = [];
// the numbers setting the size of the thing
radObj = 5;
strutObj = 5;
PHASE_CREATION = 0;
// in this phase you can make things.
PHASE_COLLAPSE = 1;
// in this phase I will artificially collapse everything into the BH;
PHASE_HAWKING = 2;
// in this phase the Hawking radiation comes out.
// time in the creation phase
//creation_time = 3600;
hawking_time = 1200;
var curr_time = 0;
creation_time = 60000
var delta_hawking_quanta = 0;
var circleRad;
var fourierN = 5;
var horizon_modes_cos = [];
var horizon_modes_sin = [];
// try at first without the collapse phase, see how it goes.
var curr_phase = PHASE_CREATION;
let song1
let song2
let masterGain
function preload() {
song1 = loadSound('https://nabiliqbal.github.io/BLACKHOLE-P1.mp3');
}
function setup() {
// can hopefully load the second sound in the background.
song2 = loadSound('https://nabiliqbal.github.io/BLACKHOLE-P2.mp3')
masterGain = new p5.Gain();
masterGain.connect();
song1.disconnect(); // diconnect from p5 output
song2.disconnect();
song1.connect(masterGain);
song2.connect(masterGain);
textFont("Courier");
frameRate(60);
createCanvas(700, 700);
// initialize each oscillator
/*for (var i = 0; i < xs.length; i++) {
oscs.push(new p5.Oscillator('sine'));
oscs[i].start();
oscs[i].amp(0);
}*/
/*var xs = [100, 100];
var ys = [100, 200];
// velocities for the other objects
var vxs = [0,0];
var vys = [100,-100];
// the relative angle for each object
var thetas = [0,0];
var omegas = [defaultOmega,defaultOmega];
var objColors = [[0,0,0],[1,1,1]];*/
createObj(100,100,0,100,[0,0,0]);
createObj(100,200,0,-100,[1,1,1]);
for (var i =0; i<num_stars; i++) {
starsX.push(random(-width,width));
starsY.push(random(-width, width));
starSize.push((random(0.5,1)*starMaxSize));
}
// set all the colors
bg_color = color(0,20,60);
bg_color = color(0,20,70);
bh_color = color(0,0,0);
thing_color = color(181,195,203);
thing_colors = [color(150,50,50), color(50,150,50), color(50,50,150)];
star_color = color(40,40,80);
// populate the eaten colors with a few random ones
for (var i = 0; i < origParticles; i++) {
for (var j = 0; j < 3; j++) {
eaten_colors.push(floor(random(3)));
}
}
circleRad = 0.8*(width/2);
// populate the horizon modes with a bunch of zeros
for (var i = 0; i < fourierN; i++) {
horizon_modes_cos.push(0);
horizon_modes_sin.push(0);
}
// start the music.
song1.setVolume(0.8);
song2.setVolume(0.8);
song1.play();
}
function draw() {
//print(curr_time);
background(bg_color);
// set the zero
translate(width/2,height/2);
// draw the stars
for (var i =0; i< num_stars; i++) {
fill(star_color);
noStroke();
circle(starsX[i], starsY[i], starSize[i]);
}
// draw the bh
fill(bh_color);
//circle(x,y,2*rad);
deltaTheta = 0.05
beginShape();
for (theta = 0; theta < 2*PI; theta+=deltaTheta) {
r = rad;
for (var i = 0; i < horizon_modes_cos.length; i++) {
//print(r);
r += horizon_modes_cos[i]*cos((i+1)*theta);
r += horizon_modes_sin[i]*sin((i+1)*theta);
curveVertex(r*cos(theta),r*sin(theta));
}
}
endShape();
// draw the other objects
for (var i = 0; i < xs.length; i++) {
// note that now I draw three things!
//circle(xs[i],ys[i],2*radObj);
for (var j = 0; j < 3; j++) {
fill(thing_colors[objColors[i][j]])
circle(xs[i]+strutObj*cos(thetas[i]+j*2*PI/3),ys[i]+strutObj*sin(thetas[i]+j*2*PI/3),2*radObj);
}
}
//noFill()
//circle(0,0,2*soundrad)
if (millis() >= creation_time && curr_phase == PHASE_CREATION) {
curr_phase = PHASE_HAWKING
// okay, we are switching phases now
// calculate how long between particle emission in the Hawking phase
delta_hawking_quanta = floor(hawking_time/eaten_number);
//print("The Hawking quanta delta is ", delta_hawking_quanta);
// cheat: set the newton's constant to zero;
G = 0;
// delete everything that's currently outside the BH.
while (xs.length > 0) {
//print("Currently on ",j, " of ", xs.length);
deleteObj(0);
}
print("Deleted everything ", xs.length)
// end the first soundtrack, start the second
song1.stop();
song2.play();
soundfreq = soundfreq/2;
}
timeEvolve();
if (curr_phase == PHASE_CREATION) {
textSize(20);
textAlign(CENTER);
fill(thing_color);
noStroke()
text("Click to feed",0,-height/2+40);
// draw the progress bar
fill(thing_color);
progress_width = (width/4)*((creation_time-millis())/creation_time)
rect(-progress_width/2,height/2-40,progress_width,20);
}
if (curr_phase == PHASE_HAWKING) {
textSize(20);
textAlign(CENTER);
fill(thing_color);
//text("A black hole eventually radiates out all that entered...",0,-height/2+40);
// draw the outer sphere
stroke(thing_color);
noFill();
strokeWeight(0.1);
circle(0,0,2*circleRad)
noStroke();
// and now draw the color splatters
for (var i = 0; i < splatterAngles.length; i++) {
for (var j = 0; j <3; j++) {
fill(thing_colors[splatterColors[i][j]]);
deltaTheta = 2*radObj/circleRad;
circle(circleRad*cos(splatterAngles[i]+deltaTheta*(j-1)), circleRad*sin(splatterAngles[i]+deltaTheta*(j-1)),2*radObj);
}
}
if (eaten_number <= 0) {
textSize(20+abs(cos(curr_time/60)));
//text("...but it emerges scrambled beyond all recognition.",0,0)
}
}
}
function timeEvolve() {
curr_time++;
// now do the horizon sloshing
for (var k = 0; k < horizon_modes_cos.length; k++) {
horizon_modes_cos[k] -= 0.005*horizon_modes_cos[k]*(k+1)*(k+1);
horizon_modes_sin[k] -= 0.005*horizon_modes_sin[k]*(k+1)*(k+1);
}
// evolve things forward in time
for (var i = 0; i < xs.length; i++) {
xs[i] += vxs[i]*deltaT;
ys[i] += vys[i]*deltaT;
thetas[i]+=omegas[i]*deltaT;
x += vx*deltaT;
y += vy*deltaT;
// now let's create the inverse square law attraction
deltaX = xs[i] - x;
deltaY = ys[i] - y;
r = sqrt(pow(deltaX,2) + pow(deltaY,2));
//print(r);
// do the inverse square law thingie on the test particles
vxs[i] -= (m_BH*G*deltaX*deltaT)/pow(r,3);
vys[i] -= (m_BH*G*deltaY*deltaT)/pow(r,3);
// now, the radiation reaction! this is complicated. first make a unit vector in the phi direction
nphiX = -deltaY/r;
nphiY = deltaX/r;
// next, figure out the sign from the for product of this with the actual velocity
prod = nphiX*vxs[i] + nphiY*vys[i];
sign = abs(prod)/prod;
//print((nphiX/pow(r,4))*radforce);
// now, do the radiation reaction thing (the power of r entering here was
// worked out by me before)
vxs[i] += (nphiX/pow(r,4))*radforce;
vys[i] += (nphiY/pow(r,4))*radforce;
freq = prod/r;
// now, do the *same* inverse square law on the BH itself
vx += (m_item*G*deltaX*deltaT)/pow(r,3);
vy += (m_item*G*deltaY*deltaT)/pow(r,3);
// adjust the amplitude (the real power here is 5, not 3)
oscs[i].amp(soundamp/pow(r,3),0.1);
//print(i, "Curr amplitude ", soundamp/pow(r,2));
oscs[i].freq(soundfreq/pow(r,1.5),0.2);
// should i alter the BG gain?
masterGain.amp(max(1,soundamp/pow(r,3)),0.1);
// now, delete the item if it gets eaten by the BH
if (r < rad) {
// store the color charges
for (var j = 0; j < 3; j++) {
eaten_colors.push(objColors[i][j]);
}
// store the angle
angle_in = findAngle(xs[i],ys[i]);
deleteObj(i);
// increase the radius
rad += deltarad;
// increase the mass
m_BH += deltaM;
eaten_number += 1;
// okay now i want to source the horizon in the right way
// randomly source the horizon modes
for (var k = 0; k < horizon_modes_cos.length; k++) {
horizon_modes_cos[k] += random(10*0.5/(k+1));
horizon_modes_sin[k] += random(10*0.5/(k+1));
/*sizeFluc = 20000;
horizon_modes_cos[k]+=sizeFluc*cos((k+1)*angle_in)*exp(-pow(k+1,2)*20);
horizon_modes_sin[k]+=sizeFluc*sin((k+1)*angle_in)*exp(-pow(k+1,2)*20);*/
}
}
// now, to determine the orbital frequency; I compute the phi component of the velocity and divide by the radius.
// reflect if off the edge
/*if (abs(xs[i]) > width/2)
vxs[i] = -vxs[i];
if (abs(ys[i]) > height/2)
vys[i] = -vys[i];*/
// now, all of that is fine; we do it for all of them
// however, if we are doing the hawking radiation, we should now emit a hawking particle
// okay, now I need to catch the final things
// now, if a bit hits the outer sphere in the hawking phase, I should get rid of the object
// and create a color splatter.
if (curr_phase == PHASE_HAWKING) {
if (r >= circleRad) {
// and add the color splatter
angle1 = findAngle(xs[i],ys[i]);
/* asin(abs(ys[i])/r);
// now I need to put it into the right quadrant, which is somehow shockingly hard.
if (xs[i] < 0 && ys[i] > 0)
angle1 = PI - angle1;
if (xs[i] < 0 && ys[i] < 0)
angle1 = PI + angle1;
if (xs[i] > 0 && ys[i] < 0)
angle1 = 2*PI - angle1;*/
// store the angles and the colors.
splatterAngles.push(angle1);
splatterColors.push(objColors[i]);
deleteObj(i);
}
}
}
if (curr_phase == PHASE_HAWKING) {
// throw out some particles with random frequency
// okay; now we need to figure out how many particles to spit out, and how long we want to take for it.
if ((curr_time % delta_hawking_quanta) == 0 && eaten_number >= 0) {
//print("Hawking!", eaten_number, curr_time);
eaten_number--;
// create a particle
// choose an angle at random
angle = random(1)*2*PI;
/*xs.push((rad+10)*cos(angle));
ys.push((rad+10)*sin(angle));
vxs.push(hawkingVelocity*cos(angle));
vys.push(hawkingVelocity*sin(angle));
thetas.push(0);
omegas.push(defaultOmega);
// take the colors that were actually in there
objColors.push([floor(random(3)),floor(random(3)),floor(random(3))]);
oscs.push(new p5.Oscillator('sine'));
oscs[oscs.length-1].start()*/
createObj((rad+10)*cos(angle),(rad+10)*sin(angle),hawkingVelocity*cos(angle),hawkingVelocity*sin(angle),[floor(random(3)),floor(random(3)),floor(random(3))]);
rad -= deltarad;
m_BH -= deltaM;
if (eaten_number == 0) {
rad = 0;
}
//eaten_number--;
}
}
}
function deleteObj(i) {
xs.splice(i,1);
ys.splice(i,1);
vxs.splice(i,1);
vys.splice(i,1);
thetas.splice(i,1);
omegas.splice(i,1);
objColors.splice(i,1);
// should work on this stuff
oscs[i].amp(0,0.3);
//oscs[i].stop();
delete oscs[i];
oscs.splice(i,1);
//print("Ate one");
//print(eaten_colors);
}
function mousePressed() {
// deal with clicks by making a new object
//print("Here!",mouseX,mouseY);
if (curr_phase == PHASE_CREATION) {
// remember to offset by the origin
/*xs.push(mouseX-width/2);
ys.push(mouseY-height/2);
vxs.push(random(200)-100);
vys.push(random(200)-100);
thetas.push(0);
omegas.push(defaultOmega);
newColor = floor(random(3));
//print(newColor);
objColors.push([newColor,newColor,newColor]);
//objColors.push()
oscs.push(new p5.Oscillator('sine'));
oscs[oscs.length-1].start()
reverb = new p5.Reverb();
reverb.process(oscs[oscs.length-1], 0.5, 5);*/
newColor = floor(random(3));
createObj(mouseX-width/2,mouseY-height/2,random(200)-100,random(200)-100,[newColor,newColor,newColor]);
}
print(xs.length)
}
function createObj(x_obj,y_obj,vx_obj,vy_obj,colors) {
xs.push(x_obj);
ys.push(y_obj);
vxs.push(vx_obj);
vys.push(vy_obj);
thetas.push(0);
omegas.push(defaultOmega);
newColor = floor(random(3));
//print(newColor);
objColors.push(colors);
//objColors.push()
oscs.push(new p5.Oscillator('sine'));
//oscs[oscs.length-1].disconnect();
//oscs[oscs.length-1].connect(masterGain);
oscs[oscs.length-1].start()
}
function findAngle(x,y) {
// and add the color splatter
r = sqrt(pow(x,2) + pow(y,2));
angle = asin(abs(y)/r);
// now I need to put it into the right quadrant, which is somehow shockingly hard.
if (x< 0 && y > 0)
angle = PI - angle;
if (x < 0 && y < 0)
angle = PI + angle;
if (x > 0 && y < 0)
angle = 2*PI - angle;
return(angle);
}