import * as THREE from 'three'; export class Ball { constructor(scene) { this.scene = scene; this.createBall(); } createBall() { const ballGeometry = new THREE.SphereGeometry(0.8, 16, 16); const ballMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff }); this.mesh = new THREE.Mesh(ballGeometry, ballMaterial); this.mesh.position.y = 0.8; this.mesh.castShadow = true; this.mesh.possessedBy = null; this.mesh.velocity = new THREE.Vector3(); this.mesh.lastStealTime = 0; this.scene.add(this.mesh); } update() { const possessionDistance = 1 + 0.8 + 0.5; // player radius + ball radius + buffer if (this.mesh.possessedBy) { const ballOffset = 1.5; // Distance in front of player let offset = new THREE.Vector3(ballOffset, 0, 0); // Default offset // Ball moves with the player who possesses it if (this.mesh.possessedBy.lastVelocity && this.mesh.possessedBy.lastVelocity.lengthSq() > 0) { const direction = this.mesh.possessedBy.lastVelocity.clone().normalize(); offset = direction.multiplyScalar(ballOffset); } this.mesh.position.copy(this.mesh.possessedBy.position).add(offset); } else { // Update ball position based on velocity (when not possessed) this.mesh.position.add(this.mesh.velocity); this.mesh.velocity.multiplyScalar(0.97); // Friction } // --- Field Boundaries --- const fieldWidth = 60; const fieldLength = 100; const ballRadius = 0.8; this.mesh.position.x = Math.max(-fieldWidth / 2 + ballRadius, Math.min(fieldWidth / 2 - ballRadius, this.mesh.position.x)); this.mesh.position.z = Math.max(-fieldLength / 2 + ballRadius, Math.min(fieldLength / 2 - ballRadius, this.mesh.position.z)); // --- Force 2D movement on the XZ plane --- this.mesh.position.y = 0.8; this.mesh.velocity.y = 0; } }