Spaces:
Running
Running
<html> | |
<head> | |
<title>Space Shooter with Controls</title> | |
<style> | |
body { margin: 0; overflow: hidden; } | |
#hud { | |
position: fixed; | |
top: 10px; | |
left: 10px; | |
color: #0ff; | |
font-family: monospace; | |
font-size: 16px; | |
text-shadow: 0 0 5px #00f; | |
pointer-events: none; | |
} | |
.controls { | |
position: fixed; | |
bottom: 20px; | |
width: 100%; | |
display: flex; | |
justify-content: center; | |
gap: 20px; | |
touch-action: none; | |
} | |
.control-btn { | |
width: 60px; | |
height: 60px; | |
background: rgba(0,255,255,0.2); | |
border: 2px solid #0ff; | |
border-radius: 50%; | |
color: #0ff; | |
font-size: 24px; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
cursor: pointer; | |
user-select: none; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="hud"> | |
SCORE: <span id="score">0</span><br> | |
HEALTH: <div id="health" style="width: 100px; height: 5px; background: #333;"> | |
<div style="height: 100%; width: 100%; background: #0f0;"></div> | |
</div> | |
</div> | |
<div class="controls"> | |
<div class="control-btn" id="leftBtn">←</div> | |
<div class="control-btn" id="shootBtn">●</div> | |
<div class="control-btn" id="rightBtn">→</div> | |
</div> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> | |
<script> | |
let scene, camera, renderer, player; | |
let score = 0, health = 100, lastFire = 0; | |
const enemies = []; | |
const bullets = []; | |
const controls = { left: false, right: false }; | |
function init() { | |
// Scene setup | |
scene = new THREE.Scene(); | |
camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000); | |
renderer = new THREE.WebGLRenderer(); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
document.body.appendChild(renderer.domElement); | |
// Generate starfield | |
const stars = new THREE.BufferGeometry(); | |
const starPositions = []; | |
for(let i = 0; i < 1000; i++) { | |
starPositions.push( | |
(Math.random() - 0.5) * 2000, | |
(Math.random() - 0.5) * 2000, | |
(Math.random() - 0.5) * 2000 | |
); | |
} | |
stars.setAttribute('position', new THREE.Float32BufferAttribute(starPositions, 3)); | |
scene.add(new THREE.Points(stars, | |
new THREE.PointsMaterial({size: 0.2, color: 0xFFFFFF}))); | |
// Create player | |
player = new THREE.Mesh( | |
new THREE.ConeGeometry(0.8, 2, 8), | |
new THREE.MeshStandardMaterial({ | |
color: 0x00FF00, | |
metalness: 0.5, | |
emissive: 0x003300 | |
}) | |
); | |
player.position.z = 5; | |
scene.add(player); | |
// Create initial enemies | |
for(let i = 0; i < 5; i++) createEnemy(); | |
// Lighting | |
const light = new THREE.PointLight(0xFFFFFF, 1, 100); | |
light.position.set(0, 0, 50); | |
scene.add(light); | |
setupControls(); | |
animate(); | |
} | |
function createEnemy() { | |
const enemy = new THREE.Mesh( | |
new THREE.IcosahedronGeometry(1), | |
new THREE.MeshStandardMaterial({ | |
color: 0xFF0000, | |
metalness: 0.3, | |
emissive: 0x330000 | |
}) | |
); | |
enemy.position.set( | |
(Math.random() - 0.5) * 30, | |
(Math.random() - 0.5) * 30, | |
-50 - Math.random() * 50 | |
); | |
enemies.push(enemy); | |
scene.add(enemy); | |
} | |
function setupControls() { | |
// Mobile touch events | |
document.getElementById('leftBtn').addEventListener('touchstart', () => controls.left = true); | |
document.getElementById('leftBtn').addEventListener('touchend', () => controls.left = false); | |
document.getElementById('rightBtn').addEventListener('touchstart', () => controls.right = true); | |
document.getElementById('rightBtn').addEventListener('touchend', () => controls.right = false); | |
document.getElementById('shootBtn').addEventListener('touchstart', shoot); | |
// Desktop mouse events | |
document.getElementById('leftBtn').addEventListener('mousedown', () => controls.left = true); | |
document.getElementById('leftBtn').addEventListener('mouseup', () => controls.left = false); | |
document.getElementById('leftBtn').addEventListener('mouseleave', () => controls.left = false); | |
document.getElementById('rightBtn').addEventListener('mousedown', () => controls.right = true); | |
document.getElementById('rightBtn').addEventListener('mouseup', () => controls.right = false); | |
document.getElementById('rightBtn').addEventListener('mouseleave', () => controls.right = false); | |
document.getElementById('shootBtn').addEventListener('click', shoot); | |
// Keyboard controls | |
window.addEventListener('keydown', e => { | |
if(e.key === 'ArrowLeft') controls.left = true; | |
if(e.key === 'ArrowRight') controls.right = true; | |
if(e.key === ' ') shoot(); | |
}); | |
window.addEventListener('keyup', e => { | |
if(e.key === 'ArrowLeft') controls.left = false; | |
if(e.key === 'ArrowRight') controls.right = false; | |
}); | |
} | |
function shoot() { | |
if(Date.now() - lastFire < 250) return; | |
lastFire = Date.now(); | |
const bullet = new THREE.Mesh( | |
new THREE.SphereGeometry(0.2), | |
new THREE.MeshStandardMaterial({ | |
color: 0xFFFF00, | |
emissive: 0x444400 | |
}) | |
); | |
bullet.position.copy(player.position); | |
bullet.velocity = new THREE.Vector3(0, 0, -0.3); | |
bullets.push(bullet); | |
scene.add(bullet); | |
} | |
function update() { | |
// Player movement | |
if(controls.left) player.rotation.z += 0.05; | |
if(controls.right) player.rotation.z -= 0.05; | |
// Update bullets | |
bullets.forEach((bullet, index) => { | |
bullet.position.add(bullet.velocity); | |
if(bullet.position.z < -100) { | |
scene.remove(bullet); | |
bullets.splice(index, 1); | |
} | |
}); | |
// Update enemies | |
enemies.forEach((enemy, index) => { | |
enemy.position.z += 0.1; | |
if(enemy.position.z > 10) { | |
enemy.position.set( | |
(Math.random() - 0.5) * 30, | |
(Math.random() - 0.5) * 30, | |
-50 - Math.random() * 50 | |
); | |
} | |
}); | |
// Collisions | |
bullets.forEach((bullet, bIndex) => { | |
enemies.forEach((enemy, eIndex) => { | |
if(bullet.position.distanceTo(enemy.position) < 2) { | |
scene.remove(bullet); | |
scene.remove(enemy); | |
bullets.splice(bIndex, 1); | |
enemies.splice(eIndex, 1); | |
score += 100; | |
document.getElementById('score').textContent = score; | |
createEnemy(); | |
} | |
}); | |
}); | |
} | |
function animate() { | |
requestAnimationFrame(animate); | |
update(); | |
renderer.render(scene, camera); | |
} | |
window.onresize = () => { | |
camera.aspect = window.innerWidth / window.innerHeight; | |
camera.updateProjectionMatrix(); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
}; | |
init(); | |
</script> | |
</body> | |
</html> |