started building the game.

This commit is contained in:
2025-11-23 16:09:57 -05:00
parent f162891fe4
commit cbd4dbd3c8
3 changed files with 516 additions and 0 deletions
+289
View File
@@ -0,0 +1,289 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Scrap-Garden Prototype: Phase 1</title>
<style>
body { margin: 0; overflow: hidden; background-color: #000; font-family: monospace; }
#instructions {
position: absolute;
top: 50%; width: 100%;
text-align: center;
color: white;
pointer-events: none;
font-size: 24px;
transform: translateY(-50%);
background: rgba(0,0,0,0.5);
padding: 20px 0;
}
#reticle {
position: absolute;
top: 50%; left: 50%;
width: 10px; height: 10px;
background: yellow;
border-radius: 50%;
transform: translate(-50%, -50%);
pointer-events: none;
opacity: 0.8;
}
</style>
</head>
<body>
<div id="reticle"></div>
<div id="instructions">CLICK TO START</div>
<script type="module">
import * as THREE from 'https://unpkg.com/three@0.150.0/build/three.module.js';
// --- GLOBAL VARIABLES ---
let camera, scene, renderer;
let player, playerVelocity, playerDirection;
let moveForward = false, moveBackward = false, moveLeft = false, moveRight = false, canJump = false;
let bullets = [];
let prevTime = performance.now();
// Configuration
const PLAYER_SPEED = 20.0;
const JUMP_FORCE = 15.0;
const GRAVITY = 40.0;
const BULLET_SPEED = 50.0;
init();
animate();
function init() {
// 1. SETUP SCENE
scene = new THREE.Scene();
scene.background = new THREE.Color(0x87CEEB); // Sky Blue (Aether Sky)
scene.fog = new THREE.Fog(0x87CEEB, 10, 80); // Fog for that MML/Silo vibe
// 2. SETUP CAMERA (Third Person)
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 3. RENDERER
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
// 4. LIGHTING
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
dirLight.position.set(50, 100, 50);
dirLight.castShadow = true;
scene.add(dirLight);
// 5. THE WORLD (Ground & Obstacles)
// Ground
const floorGeo = new THREE.PlaneGeometry(200, 200);
const floorMat = new THREE.MeshStandardMaterial({ color: 0x555555 }); // Grey Concrete
const floor = new THREE.Mesh(floorGeo, floorMat);
floor.rotation.x = -Math.PI / 2;
floor.receiveShadow = true;
scene.add(floor);
// Obstacles (Random Blue Cubes)
const boxGeo = new THREE.BoxGeometry(4, 4, 4);
const boxMat = new THREE.MeshStandardMaterial({ color: 0x0044aa });
for (let i = 0; i < 50; i++) {
const box = new THREE.Mesh(boxGeo, boxMat);
// Random position spread out, avoiding center
const x = (Math.random() - 0.5) * 150;
const z = (Math.random() - 0.5) * 150;
// Keep center clear for spawn
if(Math.abs(x) < 10 && Math.abs(z) < 10) continue;
box.position.set(x, 2, z); // y=2 is half height
box.castShadow = true;
box.receiveShadow = true;
scene.add(box);
}
// 6. THE PLAYER
// Group holds the camera and mesh handles visual
player = new THREE.Group();
scene.add(player);
// Visual Mesh (Green Capsule)
const playerGeo = new THREE.CapsuleGeometry(1, 2, 4, 8);
const playerMat = new THREE.MeshStandardMaterial({ color: 0x33ff33 });
const playerMesh = new THREE.Mesh(playerGeo, playerMat);
playerMesh.position.y = 2; // Lift half height + radius so it stands on floor
playerMesh.castShadow = true;
player.add(playerMesh);
// Attach Camera to Player (The MML "Tight Follow")
// Positioned behind and slightly up
camera.position.set(0, 5, 8);
camera.lookAt(0, 2, 0); // Look at player's back/head
player.add(camera);
playerVelocity = new THREE.Vector3();
playerDirection = new THREE.Vector3();
// 7. EVENTS & CONTROLS
setupControls();
window.addEventListener('resize', onWindowResize);
}
function setupControls() {
// Pointer Lock (Click to capture mouse)
const instructions = document.getElementById('instructions');
document.addEventListener('click', () => {
document.body.requestPointerLock();
});
document.addEventListener('pointerlockchange', () => {
if (document.pointerlockElement === document.body) {
instructions.style.display = 'none';
} else {
instructions.style.display = 'block';
}
});
// Mouse Movement (Rotates Player Group)
document.addEventListener('mousemove', (event) => {
if (document.pointerlockElement === document.body) {
// Rotate player on Y axis (Yaw)
// Negative movementX because we want to turn left when moving mouse left
player.rotation.y -= event.movementX * 0.002;
// Simple vertical camera tilt (Optional constraint)
// (Skipping vertical look for pure MML feel, but usually desired)
}
});
// Keyboard
const onKeyDown = (event) => {
switch (event.code) {
case 'KeyW': moveForward = true; break;
case 'KeyA': moveLeft = true; break;
case 'KeyS': moveBackward = true; break;
case 'KeyD': moveRight = true; break;
case 'Space':
if (canJump === true) {
playerVelocity.y += JUMP_FORCE;
canJump = false;
}
break;
}
};
const onKeyUp = (event) => {
switch (event.code) {
case 'KeyW': moveForward = false; break;
case 'KeyA': moveLeft = false; break;
case 'KeyS': moveBackward = false; break;
case 'KeyD': moveRight = false; break;
}
};
// Shooting
const onMouseDown = (event) => {
if (document.pointerlockElement === document.body && event.button === 0) {
shootBullet();
}
};
document.addEventListener('keydown', onKeyDown);
document.addEventListener('keyup', onKeyUp);
document.addEventListener('mousedown', onMouseDown);
}
function shootBullet() {
// Create Bullet Geometry
const bulletGeo = new THREE.SphereGeometry(0.3, 8, 8);
const bulletMat = new THREE.MeshBasicMaterial({ color: 0xffff00 });
const bullet = new THREE.Mesh(bulletGeo, bulletMat);
// Start bullet at player position (slightly in front and up)
// We need to get the player's world position and rotation
const spawnPos = new THREE.Vector3(0, 3, -2).applyMatrix4(player.matrixWorld);
bullet.position.copy(spawnPos);
// Calculate Velocity based on player rotation
const velocity = new THREE.Vector3(0, 0, -1);
velocity.applyQuaternion(player.quaternion);
velocity.multiplyScalar(BULLET_SPEED);
scene.add(bullet);
// Add to array
bullets.push({ mesh: bullet, velocity: velocity, creationTime: performance.now() });
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
const time = performance.now();
const delta = (time - prevTime) / 1000;
// --- PLAYER MOVEMENT PHYSICS ---
// Friction/Damping
playerVelocity.x -= playerVelocity.x * 10.0 * delta;
playerVelocity.z -= playerVelocity.z * 10.0 * delta;
playerVelocity.y -= 9.8 * 2.0 * delta; // Gravity
// Input Direction
playerDirection.z = Number(moveForward) - Number(moveBackward);
playerDirection.x = Number(moveRight) - Number(moveLeft);
playerDirection.normalize(); // ensure consistent speed in all directions
if (moveForward || moveBackward) playerVelocity.z -= playerDirection.z * PLAYER_SPEED * delta;
if (moveLeft || moveRight) playerVelocity.x -= playerDirection.x * PLAYER_SPEED * delta;
// Apply movement (Local to World)
// We move the player Group based on its rotation
const forward = new THREE.Vector3(0, 0, -1).applyQuaternion(player.quaternion);
const right = new THREE.Vector3(1, 0, 0).applyQuaternion(player.quaternion);
// Re-map inputs to forward/right vectors
// If pressing 'W' (playerDirection.z is 1), we move along forward vector
if(moveForward) player.position.addScaledVector(forward, PLAYER_SPEED * delta * 0.5);
if(moveBackward) player.position.addScaledVector(forward, -PLAYER_SPEED * delta * 0.5);
if(moveRight) player.position.addScaledVector(right, PLAYER_SPEED * delta * 0.5);
if(moveLeft) player.position.addScaledVector(right, -PLAYER_SPEED * delta * 0.5);
// Apply Jump/Gravity
player.position.y += playerVelocity.y * delta;
// Floor Collision
if (player.position.y < 0) {
playerVelocity.y = 0;
player.position.y = 0;
canJump = true;
}
// --- BULLET LOGIC ---
for (let i = bullets.length - 1; i >= 0; i--) {
const b = bullets[i];
// Move bullet
b.mesh.position.addScaledVector(b.velocity, delta);
// Remove if too old (2 seconds)
if (time - b.creationTime > 2000) {
scene.remove(b.mesh);
bullets.splice(i, 1);
}
}
prevTime = time;
renderer.render(scene, camera);
}
</script>
</body>
</html>