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</title> | |
<style> | |
body { | |
margin: 0; | |
overflow: hidden; | |
} | |
canvas { | |
display: block; | |
} | |
</style> | |
</head> | |
<body> | |
<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); | |
// Create the game board (grid of tiles) | |
const boardSize = 6; | |
const tileSize = 1; | |
const tiles = []; | |
const tileTypes = [ | |
{ type: 'water', color: 0x87ceeb }, | |
{ type: 'forest', color: 0x228b22 }, | |
{ type: 'grass', color: 0x98fb98 } | |
]; | |
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 light | |
const light = new THREE.AmbientLight(0xffffff, 0.8); | |
scene.add(light); | |
// Add animals | |
const animalModels = { | |
swan: { model: null, color: 0xffffff }, | |
deer: { model: null, color: 0x8b4513 }, | |
bear: { model: null, color: 0x000000 } | |
}; | |
const animalCards = [ | |
{ name: 'Swan', habitat: 'water', color: 0xffffff }, | |
{ name: 'Deer', habitat: 'grass', color: 0x8b4513 }, | |
{ name: 'Bear', habitat: 'forest', color: 0x000000 } | |
]; | |
const animalGeometry = new THREE.SphereGeometry(0.2, 32, 32); | |
for (const animal in animalModels) { | |
animalModels[animal].model = new THREE.Mesh( | |
animalGeometry, | |
new THREE.MeshBasicMaterial({ color: animalModels[animal].color }) | |
); | |
} | |
// Game state | |
let currentPlayer = 1; | |
const scores = { 1: 0, 2: 0 }; | |
// Handle mouse click events | |
const raycaster = new THREE.Raycaster(); | |
const mouse = new THREE.Vector2(); | |
function onMouseClick(event) { | |
mouse.x = (event.clientX / window.innerWidth) * 2 - 1; | |
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; | |
raycaster.setFromCamera(mouse, camera); | |
const intersects = raycaster.intersectObjects(tiles); | |
if (intersects.length > 0) { | |
const tile = intersects[0].object; | |
if (tile.userData.occupied) { | |
alert('This tile is already occupied!'); | |
return; | |
} | |
const selectedAnimal = animalCards[Math.floor(Math.random() * animalCards.length)]; | |
if (selectedAnimal.habitat !== tile.userData.type) { | |
alert(`${selectedAnimal.name} cannot live on ${tile.userData.type} tile!`); | |
return; | |
} | |
const animal = animalModels[selectedAnimal.name.toLowerCase()].model.clone(); | |
animal.position.copy(tile.position); | |
animal.position.y += 0.2; | |
scene.add(animal); | |
tile.userData.occupied = true; | |
scores[currentPlayer] += 5; | |
switchPlayer(); | |
} | |
} | |
function switchPlayer() { | |
currentPlayer = currentPlayer === 1 ? 2 : 1; | |
alert(`Player ${currentPlayer}'s turn!`); | |
} | |
window.addEventListener('click', onMouseClick); | |
// Set camera position | |
camera.position.set(0, 5, 5); | |
camera.lookAt(0, 0, 0); | |
// Animation loop | |
function animate() { | |
requestAnimationFrame(animate); | |
renderer.render(scene, camera); | |
} | |
animate(); | |
</script> | |
</body> | |
</html> | |