Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Harmonies Game 3D - Dynamic Simulation</title> | |
| <style> | |
| body { | |
| margin: 0; | |
| overflow: hidden; | |
| } | |
| canvas { | |
| display: block; | |
| } | |
| .hud { | |
| position: absolute; | |
| top: 10px; | |
| left: 10px; | |
| background: rgba(0, 0, 0, 0.5); | |
| color: white; | |
| padding: 10px; | |
| border-radius: 5px; | |
| font-family: Arial, sans-serif; | |
| } | |
| .sidebar { | |
| position: absolute; | |
| top: 0; | |
| right: 0; | |
| width: 200px; | |
| height: 100%; | |
| background: rgba(0, 0, 0, 0.8); | |
| color: white; | |
| padding: 10px; | |
| overflow-y: auto; | |
| font-family: Arial, sans-serif; | |
| } | |
| .character { | |
| margin-bottom: 10px; | |
| padding: 5px; | |
| border: 1px solid white; | |
| border-radius: 5px; | |
| } | |
| .timer { | |
| position: absolute; | |
| top: 10px; | |
| right: 10px; | |
| background: rgba(0, 0, 0, 0.5); | |
| color: white; | |
| padding: 10px; | |
| border-radius: 5px; | |
| font-family: Arial, sans-serif; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="hud" id="hud"> | |
| <p>Current Type: <span id="currentType">Swan 🦢</span></p> | |
| </div> | |
| <div class="sidebar" id="sidebar"> | |
| <h3>Population Stats</h3> | |
| </div> | |
| <div class="timer" id="timer"> | |
| <p>Simulation Time: <span id="simulationTime">0</span> seconds</p> | |
| <p>Epoch: <span id="epoch">1</span></p> | |
| </div> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script> | |
| <script> | |
| // Initialize scene, camera, and renderer | |
| const scene = new THREE.Scene(); | |
| const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); | |
| const renderer = new THREE.WebGLRenderer(); | |
| renderer.setSize(window.innerWidth, window.innerHeight); | |
| document.body.appendChild(renderer.domElement); | |
| // Timer variables | |
| let simulationTime = 0; | |
| let epoch = 1; | |
| const timerElement = document.getElementById('simulationTime'); | |
| const epochElement = document.getElementById('epoch'); | |
| // Game board parameters | |
| const boardSize = 50; // Gigantic board | |
| const tileSize = 1; | |
| const tiles = []; | |
| const tileTypes = [ | |
| { type: 'water', color: 0x87ceeb }, | |
| { type: 'forest', color: 0x228b22 }, | |
| { type: 'grass', color: 0x98fb98 } | |
| ]; | |
| // Sidebar for stats | |
| const sidebar = document.getElementById('sidebar'); | |
| // Particle system for motion simulation | |
| const particleSystem = new THREE.Group(); | |
| scene.add(particleSystem); | |
| // Generate random character stats | |
| function generateCharacter() { | |
| const names = ["Swift Feather", "Bold Antler", "Mighty Claw", "Gentle Leaf", "Shadow Pelt"]; | |
| return { | |
| name: names[Math.floor(Math.random() * names.length)], | |
| attack: Math.floor(Math.random() * 10) + 1, | |
| hitPoints: Math.floor(Math.random() * 50) + 10, | |
| strength: Math.floor(Math.random() * 10) + 1, | |
| intelligence: Math.floor(Math.random() * 10) + 1, | |
| wisdom: Math.floor(Math.random() * 10) + 1, | |
| charisma: Math.floor(Math.random() * 10) + 1, | |
| }; | |
| } | |
| // Create tiles and particles | |
| for (let x = 0; x < boardSize; x++) { | |
| for (let z = 0; z < boardSize; z++) { | |
| const tileType = tileTypes[Math.floor(Math.random() * tileTypes.length)]; | |
| const geometry = new THREE.BoxGeometry(tileSize, 0.1, tileSize); | |
| const material = new THREE.MeshBasicMaterial({ color: tileType.color }); | |
| const tile = new THREE.Mesh(geometry, material); | |
| tile.position.set(x - boardSize / 2, 0, z - boardSize / 2); | |
| tile.userData = { type: tileType.type, occupied: false }; | |
| scene.add(tile); | |
| tiles.push(tile); | |
| // Add particles for motion simulation | |
| const particleGeometry = new THREE.SphereGeometry(0.2, 16, 16); | |
| const particleMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 }); | |
| const particle = new THREE.Mesh(particleGeometry, particleMaterial); | |
| particle.position.set( | |
| x - boardSize / 2 + Math.random(), | |
| 0.2, | |
| z - boardSize / 2 + Math.random() | |
| ); | |
| particle.userData = { | |
| direction: new THREE.Vector3(Math.random(), 0, Math.random()).normalize(), | |
| rotation: new THREE.Vector3(0, Math.random() * 2 * Math.PI, 0), | |
| accelerate: Math.random() * 0.05 + 0.01, | |
| brake: 0.02, | |
| reverse: -0.02, | |
| stats: generateCharacter(), | |
| }; | |
| // Add stats to the sidebar | |
| const characterDiv = document.createElement('div'); | |
| characterDiv.className = 'character'; | |
| characterDiv.innerHTML = ` | |
| <strong>${particle.userData.stats.name}</strong><br> | |
| Attack: ${particle.userData.stats.attack}<br> | |
| HP: ${particle.userData.stats.hitPoints}<br> | |
| Strength: ${particle.userData.stats.strength}<br> | |
| Intelligence: ${particle.userData.stats.intelligence}<br> | |
| Wisdom: ${particle.userData.stats.wisdom}<br> | |
| Charisma: ${particle.userData.stats.charisma}<br> | |
| `; | |
| sidebar.appendChild(characterDiv); | |
| particleSystem.add(particle); | |
| } | |
| } | |
| // Add light | |
| const light = new THREE.AmbientLight(0xffffff, 0.8); | |
| scene.add(light); | |
| // HUD for displaying the current type | |
| const hud = document.getElementById('hud'); | |
| const currentTypeDisplay = document.getElementById('currentType'); | |
| // Current type with emoji | |
| const animalTypes = [ | |
| { name: 'Swan', emoji: '🦢' }, | |
| { name: 'Deer', emoji: '🦌' }, | |
| { name: 'Bear', emoji: '🐻' } | |
| ]; | |
| let currentTypeIndex = 0; | |
| function updateCurrentType() { | |
| currentTypeDisplay.textContent = `${animalTypes[currentTypeIndex].name} ${animalTypes[currentTypeIndex].emoji}`; | |
| } | |
| updateCurrentType(); | |
| // Handle key presses to switch types | |
| window.addEventListener('keydown', (event) => { | |
| if (event.key === 'ArrowRight') { | |
| currentTypeIndex = (currentTypeIndex + 1) % animalTypes.length; | |
| updateCurrentType(); | |
| } else if (event.key === 'ArrowLeft') { | |
| currentTypeIndex = (currentTypeIndex - 1 + animalTypes.length) % animalTypes.length; | |
| updateCurrentType(); | |
| } | |
| }); | |
| // Particle motion simulation | |
| function updateParticles() { | |
| particleSystem.children.forEach(particle => { | |
| const direction = particle.userData.direction; | |
| const position = particle.position; | |
| // Move particle | |
| position.add(direction.multiplyScalar(particle.userData.accelerate)); | |
| // Detect collisions and adjust behavior | |
| particleSystem.children.forEach(otherParticle => { | |
| if (particle !== otherParticle) { | |
| const distance = position.distanceTo(otherParticle.position); | |
| if (distance < 0.5) { | |
| // Reverse direction on collision | |
| direction.negate(); | |
| particle.userData.accelerate = particle.userData.reverse; | |
| } | |
| } | |
| }); | |
| // Gradually brake | |
| if (particle.userData.accelerate > 0) { | |
| particle.userData.accelerate -= particle.userData.brake; | |
| if (particle.userData.accelerate < 0) { | |
| particle.userData.accelerate = 0; | |
| } | |
| } | |
| // Bounce off edges of the board | |
| if (position.x < -boardSize / 2 || position.x > boardSize / 2) { | |
| direction.x = -direction.x; | |
| } | |
| if (position.z < -boardSize / 2 || position.z > boardSize / 2) { | |
| direction.z = -direction.z; | |
| } | |
| }); | |
| } | |
| // Timer update function | |
| function updateTimer() { | |
| simulationTime++; | |
| timerElement.textContent = simulationTime; | |
| if (simulationTime % 10 === 0) { | |
| epoch++; | |
| epochElement.textContent = epoch; | |
| } | |
| } | |
| setInterval(updateTimer, 1000); | |
| // Set camera position | |
| camera.position.set(0, 50, 50); | |
| camera.lookAt(0, 0, 0); | |
| // Animation loop | |
| function animate() { | |
| requestAnimationFrame(animate); | |
| updateParticles(); | |
| renderer.render(scene, camera); | |
| } | |
| animate(); | |
| </script> | |
| </body> | |
| </html> | |