Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>3D Sphere Snake Game</title> | |
<style> | |
body { margin: 0; overflow: hidden; } | |
canvas { display: block; } | |
</style> | |
</head> | |
<body> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> | |
<script> | |
let camera, scene, renderer; | |
let snake, food; | |
let angle = 0; | |
function init() { | |
// Camera setup | |
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); | |
camera.position.z = 5; | |
// Scene setup | |
scene = new THREE.Scene(); | |
// Sphere (world) | |
const geometry = new THREE.SphereGeometry(2, 32, 32); | |
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true }); | |
scene.add(new THREE.Mesh(geometry, material)); | |
// Snake setup | |
snake = []; | |
for (let i = 0; i < 3; i++) { | |
const snakePart = new THREE.Mesh(new THREE.SphereGeometry(0.1), new THREE.MeshBasicMaterial({ color: 0xff0000 })); | |
snakePart.position.set(0, 0, i * 0.2 - 0.4); | |
snake.push(snakePart); | |
scene.add(snakePart); | |
} | |
// Food setup | |
food = new THREE.Mesh(new THREE.SphereGeometry(0.1), new THREE.MeshBasicMaterial({ color: 0x0000ff })); | |
setRandomFoodPosition(); | |
scene.add(food); | |
// Renderer setup | |
renderer = new THREE.WebGLRenderer(); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
document.body.appendChild(renderer.domElement); | |
// Event listeners for rotation | |
document.addEventListener('mousemove', onMouseMove); | |
document.addEventListener('touchmove', onTouchMove, { passive: false }); | |
} | |
function setRandomFoodPosition() { | |
const radius = 1.9; | |
const phi = Math.acos(2 * Math.random() - 1); | |
const theta = 2 * Math.PI * Math.random(); | |
food.position.x = radius * Math.sin(phi) * Math.cos(theta); | |
food.position.y = radius * Math.sin(phi) * Math.sin(theta); | |
food.position.z = radius * Math.cos(phi); | |
} | |
function onMouseMove(e) { | |
angle -= e.movementX * 0.001; | |
} | |
function onTouchMove(e) { | |
e.preventDefault(); | |
const touch = e.touches[0]; | |
if (touch) { | |
angle -= touch.movementX * 0.001; | |
} | |
} | |
function update() { | |
// Move snake | |
for (let i = snake.length - 1; i > 0; i--) { | |
snake[i].position.copy(snake[i - 1].position); | |
} | |
// Move head in direction (simple forward movement here) | |
const head = snake[0]; | |
const direction = head.position.clone().normalize().multiplyScalar(0.05); | |
head.position.add(direction); | |
// Check for food | |
if (head.position.distanceTo(food.position) < 0.2) { | |
const newPart = new THREE.Mesh(new THREE.SphereGeometry(0.1), new THREE.MeshBasicMaterial({ color: 0xff0000 })); | |
newPart.position.copy(snake[snake.length - 1].position); | |
snake.push(newPart); | |
scene.add(newPart); | |
setRandomFoodPosition(); | |
} | |
// Keep snake on sphere surface | |
head.position.normalize().multiplyScalar(1.9); | |
} | |
function animate() { | |
requestAnimationFrame(animate); | |
// Rotate the scene for interaction | |
scene.rotation.y = angle; | |
update(); | |
renderer.render(scene, camera); | |
} | |
init(); | |
animate(); | |
// Resize handling | |
window.addEventListener('resize', onWindowResize, false); | |
function onWindowResize() { | |
camera.aspect = window.innerWidth / window.innerHeight; | |
camera.updateProjectionMatrix(); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
} | |
</script> | |
</body> | |
</html> |