3D Mini Space Shooter
by ThunderPhoenix57221 lines6.3 KB🛠️ Three.js (3D graphics)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>3D Mini Space Shooter</title>
<style>
body {
margin: 0;
overflow: hidden;
background: #000;
font-family: sans-serif;
}
#ui {
position: absolute;
top: 20px;
left: 20px;
color: #00ffcc;
font-size: 20px;
font-weight: bold;
text-shadow: 0 0 5px #00ffcc;
pointer-events: none;
}
#instructions {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
color: #ffffff;
font-size: 14px;
letter-spacing: 1px;
pointer-events: none;
opacity: 0.8;
}
</style>
<!-- Load Three.js library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
</head>
<body>
<div id="ui">Score: <span id="score">0</span></div>
<div id="instructions">Move: MOUSE | Shoot: CLICK / SPACEBAR</div>
<script>
// 1. Scene Setup
const scene = new THREE.Scene();
scene.fog = new THREE.FogExp2(0x000000, 0.015);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 3, 10);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
// 2. Lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.3);
scene.add(ambientLight);
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(5, 10, 7);
scene.add(dirLight);
// 3. Game Objects
// Player Ship
const playerGroup = new THREE.Group();
const bodyGeo = new THREE.ConeGeometry(0.6, 2, 8);
const bodyMat = new THREE.MeshStandardMaterial({ color: 0x00ffcc, roughness: 0.3, metalness: 0.8 });
const shipMesh = new THREE.Mesh(bodyGeo, bodyMat);
shipMesh.rotation.x = Math.PI / 2;
playerGroup.add(shipMesh);
// Ship Wings
const wingGeo = new THREE.BoxGeometry(2, 0.1, 0.8);
const wingMat = new THREE.MeshStandardMaterial({ color: 0xff0055 });
const wings = new THREE.Mesh(wingGeo, wingMat);
wings.position.set(0, 0, 0.3);
playerGroup.add(wings);
scene.add(playerGroup);
// Starfield Background
const starsGeo = new THREE.BufferGeometry();
const starCount = 800;
const starPositions = new Float32Array(starCount * 3);
for (let i = 0; i < starCount * 3; i++) {
starPositions[i] = (Math.random() - 0.5) * 200;
}
starsGeo.setAttribute('position', new THREE.BufferAttribute(starPositions, 3));
const starMat = new THREE.PointsMaterial({ color: 0xffffff, size: 0.5 });
const starField = new THREE.Points(starsGeo, starMat);
scene.add(starField);
// Game Arrays & State
const bullets = [];
const asteroids = [];
let score = 0;
const mouse = { x: 0, y: 0 };
const targetPos = new THREE.Vector3();
// 4. Input Handlers
window.addEventListener('mousemove', (e) => {
mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
});
function shoot() {
const laserGeo = new THREE.CylinderGeometry(0.05, 0.05, 1, 8);
const laserMat = new THREE.MeshBasicMaterial({ color: 0x00ffff });
const laser = new THREE.Mesh(laserGeo, laserMat);
laser.rotation.x = Math.PI / 2;
laser.position.copy(playerGroup.position);
laser.position.z -= 1;
scene.add(laser);
bullets.push(laser);
}
window.addEventListener('click', shoot);
window.addEventListener('keydown', (e) => {
if (e.code === 'Space') shoot();
});
// Handle Window Resizing
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// 5. Spawning Asteroids
function spawnAsteroid() {
const radius = 0.5 + Math.random() * 0.8;
const geo = new THREE.DodecahedronGeometry(radius, 1);
const mat = new THREE.MeshStandardMaterial({ color: 0x888888, roughness: 0.9 });
const asteroid = new THREE.Mesh(geo, mat);
asteroid.position.x = (Math.random() - 0.5) * 16;
asteroid.position.y = (Math.random() - 0.5) * 10;
asteroid.position.z = -60;
asteroid.userData = {
rotX: (Math.random() - 0.5) * 0.05,
rotY: (Math.random() - 0.5) * 0.05,
speed: 0.2 + Math.random() * 0.3,
radius: radius
};
scene.add(asteroid);
asteroids.push(asteroid);
}
setInterval(spawnAsteroid, 600);
// 6. Main Game Loop
function animate() {
requestAnimationFrame(animate);
// Smooth Ship Movement toward mouse
targetPos.set(mouse.x * 8, mouse.y * 5, 0);
playerGroup.position.lerp(targetPos, 0.1);
// Ship banking/tilt effect based on mouse
playerGroup.rotation.z = -mouse.x * 0.5;
playerGroup.rotation.x = mouse.y * 0.2;
// Update Bullets
for (let i = bullets.length - 1; i >= 0; i--) {
const b = bullets[i];
b.position.z -= 1.2;
if (b.position.z < -70) {
scene.remove(b);
bullets.splice(i, 1);
}
}
// Update Asteroids & Collision Detection
for (let i = asteroids.length - 1; i >= 0; i--) {
const a = asteroids[i];
a.position.z += a.userData.speed;
a.rotation.x += a.userData.rotX;
a.rotation.y += a.userData.rotY;
// Check laser hits
for (let j = bullets.length - 1; j >= 0; j--) {
const b = bullets[j];
const dist = a.position.distanceTo(b.position);
if (dist < a.userData.radius + 0.5) {
scene.remove(a);
scene.remove(b);
asteroids.splice(i, 1);
bullets.splice(j, 1);
score += 10;
document.getElementById('score').innerText = score;
break;
}
}
// Remove off-screen asteroids
if (a && a.position.z > 15) {
scene.remove(a);
asteroids.splice(i, 1);
}
}
// Scroll background stars
starField.rotation.z += 0.0005;
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>
Game Source: 3D Mini Space Shooter
Creator: ThunderPhoenix57
Libraries: three
Complexity: complex (221 lines, 6.3 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: 3d-mini-space-shooter-thunderphoenix57" to link back to the original. Then publish at arcadelab.ai/publish.