Last active
November 4, 2020 18:17
-
-
Save TylerLeite/12da2db952067fb20dbd224cf945bd4d to your computer and use it in GitHub Desktop.
Gravity
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en" dir="ltr"> | |
<head> | |
<meta charset="utf-8"> | |
<title>moonshot</title> | |
<style> | |
* {padding: 0; margin: 0; outline: 0;} | |
body {display: flex; align-items: center; justify-content: center; margin-top: 5vh} | |
canvas {width: 800px; height: 800px;} | |
</style> | |
</head> | |
<body> | |
<canvas id="canvas" width="6400px" height="6400px"></canvas> | |
<script type="text/javascript"> | |
const canvas = document.getElementById('canvas'); | |
canvas.addEventListener('mousedown', (e) => { | |
const rect = e.path[0].getBoundingClientRect(); | |
const x = (e.clientX - rect.x)/rect.width; | |
const y = (e.clientY - rect.y)/rect.height; | |
const planet = addPlanet(randomPlanetMaterial(), x, y); | |
planet.xVel = Math.random()*1e-6-5e-7 | |
planet.yVel = Math.random()*1e-6-5e-7 | |
planets.push(planet); | |
// console.log(planet) | |
}); | |
canvas.addEventListener('mouseup', (e) => { | |
return; | |
}); | |
canvas.addEventListener('mousemove', (e) => { | |
return; | |
}); | |
const ctx = canvas.getContext('2d'); | |
const sz = 6400; // aka 9 billion kilometers | |
const materials = { | |
'gas': { | |
color: '#d4bf39', | |
density: 1500, // kg/m^3 | |
// 69,911 | |
radius: () => 7.6e-4, // as a fraction of 9b km | |
}, | |
'water': { | |
color: '#3699e0', | |
density: 1000, | |
radius: () => 7.1e-5, | |
}, | |
'rock': { | |
color: '#825507', | |
density: 5500, | |
radius: () => 3.8e-5, | |
}, | |
'iron': { | |
color: '#8a8a8a', | |
density: 10000, | |
radius: () => 3.9e-5, | |
}, | |
'neutrons': { | |
color: '#eeeeee', | |
density: 1e17, | |
radius: () => 1.1e-7, | |
}, | |
'???': { | |
color: '#000000', | |
density: 2e17, | |
radius: () => 1.1e-7, | |
}, | |
'ship': { | |
color: '#ff45f9', | |
density: 1473, | |
radius: 4.1e-10, | |
}, | |
} | |
planets = []; | |
function addPlanet (material, xPos=Math.random(), yPos=Math.random(), radius=-1) { | |
const info = materials[material]; | |
if (radius == -1) { | |
radius = info.radius()*sz; | |
} | |
const planet = { | |
material, | |
mass: info.density*radius*radius*radius, | |
xPos: xPos*sz, | |
yPos: yPos*sz, | |
xVel: 0, | |
yVel: 0, | |
radius, | |
} | |
return planet; | |
} | |
function drawPlanet (material, xPos, yPos, radius) { | |
radius = Math.max(radius, 8); | |
ctx.strokeStyle = materials[material].color; | |
ctx.lineWidth = '12'; | |
ctx.beginPath(); | |
ctx.arc(xPos, yPos, radius, 0, 2*Math.PI); | |
ctx.stroke(); | |
} | |
function drawShip (xPos, yPos) { | |
drawPlanet('ship', xPos, yPos, 0.0005*sz); | |
} | |
function randomPlanetMaterial () { | |
const mats = Object.keys(materials).filter(e => e != 'ship'); | |
return mats[Math.floor(Math.random()*mats.length)]; | |
} | |
for (let i = 0; i < 2; i++) { | |
planets.push(addPlanet(randomPlanetMaterial())); | |
} | |
let ship = { | |
material: 'ship', | |
xPos: 0.25*sz, | |
yPos: 0.75*sz, | |
xVel: 1.2e-7, | |
yVel: -1.2e-7, | |
mass: materials.ship.density*materials.ship.radius*materials.ship.radius*materials.ship.radius, | |
} | |
const bigG = 6.674e-20; | |
const timeScale = 3e6; // 3 miillion seconds per second | |
function oneStep () { | |
function calcForces(a, b) { | |
const dx = Math.max(Math.abs(a.xPos - b.xPos), 1e-20); | |
const dy = Math.max(Math.abs(a.yPos - b.yPos), 1e-10); | |
const r2 = (dx*dx+dy*dy) | |
if (r2 <= a.radius*a.radius+b.radius*b.radius) { | |
return false; | |
} | |
const fg = bigG*a.mass*b.mass/r2; | |
const theta = Math.atan2(dy, dx); | |
const fgx = fg*Math.cos(theta); | |
const fgy = fg*Math.sin(theta); | |
// acceleration for a | |
const advx = (-(a.xPos - b.xPos)/dx)*timeScale*fgx; | |
const advy = (-(a.yPos - b.yPos)/dy)*timeScale*fgy; | |
a.xVel += advx/a.mass; | |
a.yVel += advy/a.mass; | |
// acceleration for b | |
const bdvx = (-(b.xPos - a.xPos)/dx)*timeScale*fgx; | |
const bdvy = (-(b.yPos - a.yPos)/dy)*timeScale*fgy; | |
b.xVel += bdvx/b.mass; | |
b.yVel += bdvy/b.mass; | |
if (isNaN(a.xVel) || isNaN(a.yVel) | |
|| isNaN(b.xVel) || isNaN(b.yVel)) { | |
console.log(a, b); | |
planets = []; | |
} | |
return true; | |
} | |
function updatePos (body, scale=timeScale) { | |
if (isNaN(body.xPos) || isNaN(body.yPos)) { | |
console.log(body); | |
planets = []; | |
} | |
body.xPos += scale*body.xVel; | |
body.yPos += scale*body.yVel; | |
if (body.xPos < 0) { | |
body.xVel = Math.max(body.xVel, body.xVel/2); | |
} else if (body.xPos > sz) { | |
body.xVel = Math.min(body.xVel, body.xVel/2); | |
} | |
if (body.yPos < 0) { | |
body.yVel = Math.max(body.yVel, body.yVel/2); | |
} else if (body.yPos > sz) { | |
body.yVel = Math.min(body.yVel, body.yVel/2); | |
} | |
do { | |
body.xPos = (body.xPos+sz)%sz; | |
body.yPos = (body.yPos+sz)%sz; | |
} while (body.xPos < 0 || body.yPos < 0) | |
} | |
// update velocities | |
for (let i = 0; i < planets.length-1; i++) { | |
const a = planets[i]; | |
// other planets | |
for (let j = i+1; j < planets.length; j++) { | |
const b = planets[j]; | |
calcForces(a, b); | |
} | |
// ship | |
calcForces(a, ship) | |
} | |
// ship with last planet | |
calcForces(planets[planets.length-1], ship) | |
// update positions | |
for (let i = 0; i < planets.length; i++) { | |
const a = planets[i]; | |
if (a.material == '???') { | |
// black holes stay in place, just for fun | |
continue; | |
} | |
updatePos(a); | |
} | |
//ship | |
updatePos(ship) | |
// clear screen | |
ctx.fillStyle = '#101010'; | |
ctx.fillRect(0, 0, sz, sz); | |
// draw planets | |
for (let i = 0; i < planets.length; i++) { | |
const p = planets[i]; | |
drawPlanet(p.material, p.xPos, p.yPos, p.radius); | |
} | |
// draw ship | |
drawShip(ship.xPos, ship.yPos); | |
} | |
function oneFrame () { | |
oneStep(); | |
requestAnimationFrame(oneFrame); | |
} | |
oneFrame(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment