Spaces:
Running
Running
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>Recursive Polygons in 3D with Continuous Snowflakes</title> | |
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script> | |
<script src="https://unpkg.com/aframe-environment-component/dist/aframe-environment-component.min.js"></script> | |
<style> | |
#canvas { | |
height: 500px; | |
width: 800px; | |
} | |
</style> | |
</head> | |
<body> | |
<a-scene> | |
<a-entity environment="preset: forest"></a-entity> | |
<!-- Existing Recursive Polygon Component --> | |
<!-- ... Your existing entities ... --> | |
<!-- Snowflakes Components --> | |
<!-- Clouds will be added dynamically --> | |
<a-entity camera position="0 1.6 0" look-controls wasd-controls></a-entity> | |
<a-plane position="0 0 0" rotation="-90 0 0" width="100" height="100" color="#FFF"></a-plane> | |
</a-scene> | |
<script> | |
AFRAME.registerComponent('snowflake', { | |
schema: { | |
size: { type: 'number', default: 0.1 }, | |
meltTime: { type: 'number', default: 15000 } | |
}, | |
init: function() { | |
let size = this.data.size; | |
this.el.setAttribute('geometry', { | |
primitive: 'sphere', | |
radius: size | |
}); | |
this.el.setAttribute('material', { color: '#FFF' }); | |
this.resetPosition(); | |
this.startMeltingLoop(); | |
}, | |
startMeltingLoop: function() { | |
const resetAndStartAgain = () => { | |
this.resetPosition(); | |
setTimeout(resetAndStartAgain, Math.random() * this.data.meltTime + 15000); | |
}; | |
setTimeout(resetAndStartAgain, Math.random() * this.data.meltTime + 15000); | |
}, | |
resetPosition: function() { | |
this.el.object3D.position.set( | |
Math.random() * 20 - 10, | |
5 + Math.random() * 5, | |
Math.random() * 20 - 10 | |
); | |
this.velocity = new THREE.Vector3( | |
(Math.random() - 0.5) * 0.01, // Random wind effect | |
-0.02, // Falling speed | |
(Math.random() - 0.5) * 0.01 // Random wind effect | |
); | |
}, | |
tick: function() { | |
this.el.object3D.position.add(this.velocity); | |
if (this.el.object3D.position.y <= -3.5) { | |
this.el.object3D.position.y = -3.5; // Accumulate on the ground | |
this.velocity.set(0, 0, 0); // Stop movement when it hits the ground | |
} | |
} | |
}); | |
AFRAME.registerComponent('custom-controls', { | |
init: function () { | |
this.velocityY = 0; | |
this.isMovingUp = false; | |
window.addEventListener('keydown', (e) => { | |
if (e.key === 'q' || e.key === 'Q') { | |
this.isMovingUp = true; | |
} | |
if (e.key === 'e' || e.key === 'E') { | |
this.velocityY = 0; // Stop upward movement | |
} | |
}); | |
window.addEventListener('keyup', (e) => { | |
if (e.key === 'q' || e.key === 'Q') { | |
this.isMovingUp = false; | |
} | |
}); | |
}, | |
tick: function () { | |
let position = this.el.getAttribute('position'); | |
if (this.isMovingUp) { | |
this.velocityY = 0.05; // Upward velocity | |
} else { | |
this.velocityY -= 0.01; // Gravity | |
} | |
position.y += this.velocityY; | |
if (position.y < 1.6) { // Ground level | |
position.y = 1.6; | |
this.velocityY = 0; | |
} | |
this.el.setAttribute('position', position); | |
} | |
}); | |
function createSnowflakeCloud(x, y, z, numParticles) { | |
let cloud = document.createElement('a-entity'); | |
cloud.object3D.position.set(x, y, z); | |
for (let i = 0; i < numParticles; i++) { | |
let size = Math.random() * 0.1 + 0.05; // Random size between 0.05 and 0.15 | |
let meltTime = Math.random() * 20000 + 5000; // Random time between 5 and 25 seconds | |
setTimeout(() => { | |
let snowflakeEl = document.createElement('a-entity'); | |
snowflakeEl.setAttribute('snowflake', {size: size, meltTime: meltTime}); | |
cloud.appendChild(snowflakeEl); | |
}, i * 100); | |
} | |
document.querySelector('a-scene').appendChild(cloud); | |
} | |
// Create a grid of 9 snowflake clouds | |
for (let x = -10; x <= 10; x += 10) { | |
for (let z = -10; z <= 10; z += 10) { | |
createSnowflakeCloud(x, 5, z, 50); // Increase the number of particles per cloud | |
} | |
} | |
// Create a larger central cloud | |
createSnowflakeCloud(0, 8, 0, 100); | |
</script> | |
</body> | |
</html> |