codepens/habitable-planet-generator-.../dist/script.js

318 lines
9.0 KiB
JavaScript

// 🌱 CHARACTERISTICS 🌱
const planet_radius = 125
const atmosphere_thickness = 5
const offset = -10
const TAU = Zdog.TAU
let isSpinning = true
let regenerate = false
// 🐶 ZDOG ILLUSTRATION 🐶
let space = new Zdog.Illustration({
element: '#spaceCanvas',
dragRotate: true,
rotate: { x: -TAU*0.05 },
onDragStart: function() {
isSpinning = false
},
})
function generate_world(space, randomMass){
// 🌏 PLANET 🌏
const topHempishere = new Zdog.Hemisphere({
addTo: space,
diameter: planet_radius * 2,
translate: { x: offset, y: offset },
color: "cornflowerblue", //backface: "blue",
stroke: false,
})
topHempishere.copy({
rotate: { y: Zdog.TAU/2 }, //color: "blue", backface: "cornflowerblue",
})
// 💈 NORTH / SOUTH POLE 💈
const north_pole = new Zdog.Shape({
addTo: space,
translate: { x: offset, y: offset },
path: [
{y: planet_radius * -1},
{y: (planet_radius+50) * -1}
],
stroke: 7,
color: 'firebrick'
})
const north_pole_mark = new Zdog.Ellipse({
addTo: north_pole,
translate: { y: (planet_radius-1) * -1 },
rotate: {x: TAU/4 },
diameter: 20,
stroke: 8,
fill: true,
color: "rgba(200,190,190,1)",
})
// 🔰 South pole !
north_pole.copy({
path: [
{y: planet_radius },
{y: planet_radius+50 }
],
color: 'blue'
})
north_pole_mark.copy({
addTo: north_pole,
translate: { y: planet_radius-3 },
color: "rgba(100,100,255,1)",
})
// // 🇪🇨 ⭕️ Equator ⭕️ 🇪🇨
// set_latitude_marks(0, 400, 3, 0, "rgba(184,134,11,0.5)", "dot")
// // 🎅 PRIME MERIDIAN 🐧
// set_longitude_marks(0, 200, 3, 0,"rgba(0,110,0,0.3)", "dot")
// ☁️☁️☁️ CLOUDS ☁️☁️☁️
let cloudCount = 0
for (var i = 0; i < 40; i++) {
create_cloud_cluster({
lat: random(-50,50),
lng: random(-180,180),
altitude: random(10,30),
count: random(10,30),
strokeMaxMin: [8,25]
})
}
function create_cloud_cluster(cords){
for (var i = 0; i < cords.count; i++) {
set_cordinate_mark({
lat: cords.lat + random(0, cords.count/3),
lng: cords.lng + random(0, cords.count),
stroke: random(cords.strokeMaxMin[0], cords.strokeMaxMin[1]),
color: "rgba(200,200,200,"+(random(0,5)/10)+")",
altitude: cords.altitude + random(5, 15),
shape: "dot"
})
cloudCount++
}
}
// 🏔🌋⛰ LAND 🏔🌋⛰
const interval = 90
const stroke = 2
const radShift = 0
const maxGrow = -1
const maxShrink = -3
cols = [
"rgba(170,170,255,0.5)",
"rgba(170,170,255,0.5)",
"rgba(170,170,255,0.5)",
"rgba(160,130,52,1)",
"rgba(160,130,52,1)",
"rgba(0,128,0,1)",
"rgba(85,107,47,1)",
"rgba(67,85,37,1)",
"rgba(160,100,42,1)",
"rgba(140,80,42,1)",
"rgba(120,60,42,1)",
"rgba(170,110,92,1)",
"rgba(200,180,200,1)"
]
let landMassCount = 0
const lngI = 360 / interval
const d = (Math.PI*planet_radius) / interval
const r = d/2
const r2 = r/2
const pr = Math.sqrt((r*r) + (r2*r2))
const latI = Math.sqrt( ( (r*2)*(r*2) ) - (r*r))
const hexWheel = [
{TR: (s, i, {lat,lng})=>{ return [latI*s-(latI*i), (lngI/2*s)+(lngI*i/2)] } },
{R: (s, i, {lat,lng})=>{ return [-(latI*i), (lngI*s)-(lngI*i/2) ] }},
{BR: (s, i, {lat,lng})=>{ return [-latI*s, (lngI/2*s)-(lngI*i)] }},
{BL: (s, i ,{lat,lng})=>{ return [-latI*s+(latI*i), -lngI/2*s-(lngI*i/2)] } },
{L: (s, i, {lat,lng})=>{ return [(latI*i), -lngI*s+(lngI*i/2)] } },
{TL: (s, i, {lat,lng})=>{ return [latI*s, -lngI/2*s+(lngI*i)] } },
]
// ⛰🏔🌋⛰🏔 Build land around center mark! ⛰🏔🌋⛰🏔
function buildLandMass({sLat, sLng, stages}){
// 🌋 Center Land Mark
const landKey = { "0-TR-0": stages }
set_cordinate_mark({ lat: sLat, lng: sLng, radius: pr*2, stroke,
altitude: stages*.75, color: cols[stages], shape: "poly", sides: 6 })
// ⛰🌋🏔 Build land around center mark!
for (let stage = 0; stage <= stages; stage++) {
for (let hw = 0; hw < hexWheel.length; hw++) {
const key = Object.keys(hexWheel[hw])[0]
for (let i = 1; i <= stage; i++) {
let look = i <= 2 ? 0 : i-2
let land = stage != 1 ? landKey[(stage-1)+"-"+key+"-"+(look)] : landKey["0-TR-0"]
const [ lat, lng ] = hexWheel[hw][key]( stage, i-1, {sLat,sLng})
const setStk = stages - stage < 1 ? 0 : stroke
let newAlt = land + random(maxShrink, maxGrow)
if (newAlt > -1) {
set_cordinate_mark({ lat: lat+sLat, lng: lng+sLng, radius: pr*2+radShift,
stroke: setStk, altitude: newAlt*.75, color: cols[newAlt], shape: "poly", sides: 6 })
landMassCount++
// 🏔⬆️ BUILD MOUNTAINS UP!
// for (var a = 0; a < newAlt; a++) {
// set_cordinate_mark({ lat: lat+sLat, lng: lng+sLng, radius: pr*2+radShift, stroke: setStk,
// altitude: a, color: cols[newAlt], shape: "poly", sides: 6 })
// landMassCount++
// }
}
landKey[(stage)+"-"+key+"-"+(i-1)] = newAlt
}
}
}
}
if (randomMass){
for (var i = 0; i < 8; i++) {
buildLandMass({
sLat: random(-75,75),
sLng: random(0,180),
stages: random(4,12)})
}
for (var i = 0; i < 20; i++) {
buildLandMass({
sLat: random(-55,55),
sLng: random(-179,180),
stages: random(1,2)})
}
} else {
buildLandMass({sLat: 20, sLng: 37, stages: 12})
buildLandMass({sLat: 40, sLng: -37, stages: 12})
buildLandMass({sLat: 30, sLng: -27, stages: 12})
buildLandMass({sLat: 0, sLng: 150, stages: 8})
buildLandMass({sLat: 60, sLng: -70, stages: 12})
buildLandMass({sLat: 10, sLng: -10, stages: 8})
buildLandMass({sLat: -50, sLng: -130, stages: 9})
buildLandMass({sLat: 20, sLng: -90, stages: 6})
buildLandMass({sLat: -10, sLng: 10, stages: 12})
buildLandMass({sLat: -15, sLng: 180, stages: 12})
buildLandMass({sLat: 35, sLng: 80, stages: 9})
// Reefs
buildLandMass({sLat: -35, sLng: 80, stages: 3})
buildLandMass({sLat: -40, sLng: 90, stages: 3})
buildLandMass({sLat: -43, sLng: 90, stages: 2})
buildLandMass({sLat: 33, sLng: 180, stages: 2})
buildLandMass({sLat: 30, sLng: 170, stages: 3})
buildLandMass({sLat: 32, sLng: 150, stages: 2})
buildLandMass({sLat: 25, sLng: -130, stages: 3})
}
// 🌐 🛠 LATITUDE & LONGITUDE MARKS & TOOLS 🛠 🌐
function set_latitude_marks(lat, cnt, stroke, altitude, color, shape){
for ( var j=0; j < cnt; j++ ) {
set_cordinate_mark({
lng: (360 / cnt) * j,
lat, stroke, color, altitude, shape
})
}
}
function set_longitude_marks(lng, cnt, stroke, altitude, color, shape) {
for ( var j=0; j < cnt; j++ ) {
set_cordinate_mark({
lat: (180 / cnt) * j -90,
lng, stroke, color, altitude, shape
})
}
}
function set_cordinate_mark(mark){
const lat_radians = (TAU/4) - (mark.lat * (Math.PI/180)) * -1
const lng_radians = (mark.lng * (Math.PI/180)) * -1
var rotor1 = new Zdog.Anchor({
addTo: space,
translate: { x: offset, y: offset },
rotate: { y: lng_radians },
})
var rotor2 = new Zdog.Anchor({
addTo: rotor1,
rotate: { x: lat_radians },
})
if (mark.shape === "dot") {
new Zdog.Shape({
addTo: rotor2,
translate: { y: planet_radius + (mark.altitude || 0) },
stroke: mark.stroke,
color: mark.color
})
} else if (mark.shape === "cone") {
new Zdog.Cone({
addTo: rotor2,
translate: { y: planet_radius + (mark.altitude || 0) },
rotate: {x: TAU*.75},
diameter: mark.diameter,
length: mark.length,
color: mark.color,
})
} else if (mark.shape === "poly") {
new Zdog.Polygon({
addTo: rotor2,
sides: mark.sides,
radius: mark.radius,
translate: { y: planet_radius + (mark.altitude || 0) },
rotate: {x: TAU*.75},
stroke: mark.stroke,
fill: true,
color: mark.color,
backface: mark.backface,
})
}
}
function random(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
// 🔥🔥🔥🔥 Animate! 🔥🔥🔥🔥
space.rotate.z = 0.3
function animate() {
if (!regenerate) {
space.rotate.y += isSpinning ? 0.01 : 0
space.updateRenderGraph()
requestAnimationFrame( animate )
}
}
console.log("total clouds, land: ", cloudCount, landMassCount)
animate()
}
// ➰ ☁️ Regenerate ☁️ ➰
function regenerate_world(){
regenerate = true
canvasContainer.innerHTML = `
<canvas id="spaceCanvas" width="430" height="380"></canvas>
`
space = false
requestAnimationFrame(()=>{
space = new Zdog.Illustration({
element: '#spaceCanvas',
dragRotate: true,
rotate: { x: TAU*0.05 },
onDragStart: function() {
isSpinning = false
},
})
regenerate = false
generate_world(space, true)
})
}
generate_world(space)