-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcode.js
More file actions
214 lines (154 loc) · 5.71 KB
/
code.js
File metadata and controls
214 lines (154 loc) · 5.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
// SETTINGS
// All of these variables are natural numbers.
var bodiesOnSpawn = 5;
var maxBodies = 5;
var minStartBodiesMass = 3000; // minimum mass of bodies at the start of simulation in 10^20 kg
var maxStartBodiesMass = 400000; // maximum mass of bodies at the start of simulation in 10^20 kg
var minInitVelocity = 50000;
var maxInitVelocity = 4000000;
// GRAVITATIONAL CONSTANT
var speedupFactor = 2000000;
var G = 0.00000000006673 * speedupFactor;
var timeStep = 1 / 50;
var width = 0.0012; // screen width in Astronomical Units
width *= 1.496e11; // convert to meters
var density = 46732037171; //used to render bodies; units are kg / m^2; equals density of Earth were it a flat circle.
onEvent("GSlider", "change", function( ) {
// GSliderValue ranges across natural numbers from 1 to 30
var GSliderValue = getNumber("GSlider");
G = 0.000000000006673 * GSliderValue * speedupFactor;
setText("GSliderLabel", (GSliderValue * 10) + "%");
console.log("G = " + G);
});
var originalWidth = width;
onEvent("widthSlider", "change", function( ) {
width = originalWidth * getNumber("widthSlider");
});
// INFORMATION OF BODIES
// These arrays begin as [-1, -1, -1 ... ]
var mass = [];
var radius = [];
var xPos = []; // in meters
var yPos = [];
// These arrays begin as [0, 0, 0 ... ]
var xVelocity = [];
var yVelocity = [];
// setup the arrays
for (var i = 0; i < maxBodies; i++) {
appendItem(mass, -1);
appendItem(radius, -1);
appendItem(xPos, -1);
appendItem(yPos, -1);
appendItem(xVelocity, randomNumber(minInitVelocity, maxInitVelocity));
appendItem(yVelocity, randomNumber(minInitVelocity, maxInitVelocity));
}
var activeBodies = []; // index of simiulated bodies
//FUNCTION TO RESET MASS AND POSITION
function reset() {
mass[i] = Math.abs(randomNumber(minStartBodiesMass, maxStartBodiesMass));
// multiply by 10^20
for (var k = 0; k < 20; k++) {
mass[i] *= 10;
}
radius[i] = Math.sqrt(mass[i] / density / Math.PI); //radius in meters
//random poisition
console.log("mass of body " + i + " = " + mass[i]);
xPos[i] = randomNumber(0, Math.round(width));
yPos[i] = randomNumber(0, Math.round(width));
}
// SPAWN BODIES and add to activeBodies
for (var i = 0; i < bodiesOnSpawn; i++) {
appendItem(activeBodies, i);
// choose random position and random mass
reset();
//DEBUG SPECIFIC SPAWNS AND MASSES
/*
mass[i] = 6e+24;
if (i == 0) {
xPos[i] = width / 2;
yPos[i] = width / 2;
} else {
xPos[i] = width / 3;
yPos[i] = width / 3;
}*/
}
//console.log("width in meters = " + width);
//MAIN SIMULATION
function tick() {
// find the force exerted on body i from every other body
for (var m = 0; m < activeBodies.length; m++) {
var i = activeBodies[m];
// these variables will store the total force on body i in each axis
var xForce = 0;
var yForce = 0;
for (var k = 0; k < activeBodies.length; k++) {
if (m == k) {
continue; // We can ignore the force that a body exerts on itself, partly due to avoiding dividing by 0
} else {
var j = activeBodies[k];
//console.log("calculating " + i + " and " + j);
// distance along each axis between body i and body j
var deltaY = yPos[j] - yPos[i];
var deltaX = (xPos[j] - xPos[i] == 0) ? 0.0078125 : xPos[j] - xPos[i];
var angle = Math.atan(deltaY / deltaX); //angle in radians of body j from +x ray, increasing towards +y ray (points down)
//console.log("r^2 = " + (deltaX*deltaX + (deltaY*deltaY)));
// magnitude of Force of gravity from body j = G * mi * mj / r^2
var F = G * mass[i] * mass[j] / (deltaX*deltaX + (deltaY*deltaY));
// components of Force vector
xForce += (deltaX < 0 ? -1 : 1) * Math.abs(Math.cos(angle)) * F;
yForce += (deltaY < 0 ? -1 : 1) * Math.abs(Math.sin(angle)) * F;
//console.log("F = " + F + " Newtons");
//console.log("Fx = " + xForce);
}
} //END LOOP OVER k
// CALCULATE VELOCITY & POSITION
// Velocity += accel * t = F / m * t
xVelocity[i] += xForce / mass[i] * timeStep;
yVelocity[i] += yForce / mass[i] * timeStep;
// update position; d = v * t
xPos[i] += xVelocity[i] * timeStep;
yPos[i] += yVelocity[i] * timeStep;
} //END LOOP OVER i
updateScreen(time);
//UPDATE GRAVITY SLIDER
/* var GSliderValue = getNumber("GSlider");
G = 0.000000000006673 * GSliderValue * speedupFactor;
setText("GSliderLabel", (GSliderValue * 10) + "%");*/
//console.log("G = " + G);
}
//END TICK FUNCTION
var time = 0;
// render positions of bodies
function updateScreen(t) {
// console.log(t == -1 ? "Begin" : Math.round(t * 10) / 10);
time += timeStep;
for (var m = 0; m < activeBodies.length; m++) {
var i = activeBodies[m];
// find coordinates of top left corner
var thisRadius = radius[i]; //radius of actual globe within the icon, in meters
//center point of body
var x = xPos[i];
var y = yPos[i];
// set position of body i, accounting for icon's margin and position of black square
// top left corner of icon: (x - 1.569 * radius, y - 1.569 * radius + 130)
var xCorner = metersToPx(x - (0.5686275 * thisRadius)); //x coordinate of top left corner in px
var yCorner = metersToPx(y - (0.5686275 * thisRadius)) + 130; //shifted down 130
var iconWidth = metersToPx(thisRadius * 1.5686275);
// RENDER
setPosition(
"body" + i,
xCorner,
yCorner,
iconWidth,
iconWidth
);
//console.log(xCorner + ", " + yCorner + "width = " + metersToPx(radius * 1.5686275));
}
}
function metersToPx(x) {
return x * 320 / width;
}
updateScreen(-1);
var Game = setInterval(function() {
tick();
}, 1000 * timeStep);