318 lines
9.0 KiB
JavaScript
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)
|