34307-vm/assets/js/game.js
2025-09-29 17:15:51 +00:00

173 lines
5.5 KiB
JavaScript

import * as THREE from 'three';
// Basic Scene Setup
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x87CEEB); // Sky blue background
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(45, 25, 0);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
// Lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.2);
directionalLight.position.set(20, 30, 20);
directionalLight.castShadow = true;
directionalLight.shadow.camera.top = 20;
directionalLight.shadow.camera.bottom = -20;
directionalLight.shadow.camera.left = -20;
directionalLight.shadow.camera.right = 20;
scene.add(directionalLight);
// Field
const fieldGeometry = new THREE.PlaneGeometry(60, 100);
const fieldMaterial = new THREE.MeshStandardMaterial({ color: 0x008000 }); // Green grass
const field = new THREE.Mesh(fieldGeometry, fieldMaterial);
field.rotation.x = -Math.PI / 2;
field.receiveShadow = true;
scene.add(field);
// Field Lines
const lineMaterial = new THREE.LineBasicMaterial({ color: 0xffffff });
// Outer boundary
const boundary = new THREE.BufferGeometry().setFromPoints([
new THREE.Vector3(-30, 0.01, -50),
new THREE.Vector3(30, 0.01, -50),
new THREE.Vector3(30, 0.01, 50),
new THREE.Vector3(-30, 0.01, 50),
new THREE.Vector3(-30, 0.01, -50)
]);
const boundaryLine = new THREE.Line(boundary, lineMaterial);
scene.add(boundaryLine);
// Center line
const centerLineGeo = new THREE.BufferGeometry().setFromPoints([
new THREE.Vector3(-30, 0.01, 0),
new THREE.Vector3(30, 0.01, 0)
]);
const centerLine = new THREE.Line(centerLineGeo, lineMaterial);
scene.add(centerLine);
// Center circle
const centerCirclePoints = [];
const centerCircleRadius = 8;
for (let i = 0; i <= 64; i++) {
const theta = (i / 64) * Math.PI * 2;
centerCirclePoints.push(new THREE.Vector3(Math.cos(theta) * centerCircleRadius, 0.01, Math.sin(theta) * centerCircleRadius));
}
const centerCircleGeo = new THREE.BufferGeometry().setFromPoints(centerCirclePoints);
const centerCircleLine = new THREE.Line(centerCircleGeo, lineMaterial);
scene.add(centerCircleLine);
// Penalty Boxes
const penaltyBox1Geo = new THREE.BufferGeometry().setFromPoints([
new THREE.Vector3(15, 0.01, -50),
new THREE.Vector3(15, 0.01, -35),
new THREE.Vector3(-15, 0.01, -35),
new THREE.Vector3(-15, 0.01, -50),
new THREE.Vector3(15, 0.01, -50)
]);
const penaltyBox1 = new THREE.Line(penaltyBox1Geo, lineMaterial);
scene.add(penaltyBox1);
const penaltyBox2Geo = new THREE.BufferGeometry().setFromPoints([
new THREE.Vector3(15, 0.01, 50),
new THREE.Vector3(15, 0.01, 35),
new THREE.Vector3(-15, 0.01, 35),
new THREE.Vector3(-15, 0.01, 50),
new THREE.Vector3(15, 0.01, 50)
]);
const penaltyBox2 = new THREE.Line(penaltyBox2Geo, lineMaterial);
scene.add(penaltyBox2);
// Goals
const goalGeometry = new THREE.BoxGeometry(20, 5, 2);
const goalMaterial = new THREE.MeshStandardMaterial({ color: 0xCCCCCC, metalness: 0.8, roughness: 0.2 });
const goal1 = new THREE.Group();
const post1_1 = new THREE.Mesh(new THREE.BoxGeometry(1, 5, 1), goalMaterial);
post1_1.position.set(-10, 2.5, 0);
const post1_2 = new THREE.Mesh(new THREE.BoxGeometry(1, 5, 1), goalMaterial);
post1_2.position.set(10, 2.5, 0);
const crossbar1 = new THREE.Mesh(new THREE.BoxGeometry(21, 1, 1), goalMaterial);
crossbar1.position.set(0, 5, 0);
goal1.add(post1_1, post1_2, crossbar1);
goal1.position.z = -50;
scene.add(goal1);
const goal2 = goal1.clone();
goal2.position.z = 50;
scene.add(goal2);
// Player
const playerGeometry = new THREE.CapsuleGeometry(1, 2, 4, 8);
const playerMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 }); // Red player
const player = new THREE.Mesh(playerGeometry, playerMaterial);
player.position.y = 1.5; // Stand on the field
player.castShadow = true;
scene.add(player);
// Simple Bot Players (Static)
const botMaterial = new THREE.MeshStandardMaterial({ color: 0x0000ff }); // Blue bots
for (let i = 0; i < 4; i++) {
const bot = new THREE.Mesh(playerGeometry, botMaterial);
bot.position.set(
(Math.random() - 0.5) * 50,
1.5,
(Math.random() - 0.5) * 80
);
bot.castShadow = true;
scene.add(bot);
}
// Player Controls
const keyboardState = {};
window.addEventListener('keydown', (e) => { keyboardState[e.code] = true; });
window.addEventListener('keyup', (e) => { keyboardState[e.code] = false; });
const playerSpeed = 0.2;
function updatePlayerPosition() {
if (keyboardState['ArrowUp']) {
player.position.x -= playerSpeed;
}
if (keyboardState['ArrowDown']) {
player.position.x += playerSpeed;
}
if (keyboardState['ArrowLeft']) {
player.position.z += playerSpeed;
}
if (keyboardState['ArrowRight']) {
player.position.z -= playerSpeed;
}
}
// Animation Loop
function animate() {
requestAnimationFrame(animate);
updatePlayerPosition();
// Camera follows player from the sideline
camera.position.z = player.position.z;
camera.lookAt(player.position);
renderer.render(scene, camera);
}
// Handle Window Resize
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
animate();