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();