Add the ball & implement pass/shoot functionality
This commit is contained in:
parent
5681888e69
commit
db2d07f244
@ -112,10 +112,31 @@ const playerMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 }); // R
|
||||
const player = new THREE.Mesh(playerGeometry, playerMaterial);
|
||||
player.position.y = 1.5; // Stand on the field
|
||||
player.castShadow = true;
|
||||
player.lastVelocity = new THREE.Vector3();
|
||||
player.team = 'player';
|
||||
scene.add(player);
|
||||
|
||||
// Teammates
|
||||
const teammateMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 }); // Red teammates
|
||||
const teammates = [];
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const teammate = new THREE.Mesh(playerGeometry, teammateMaterial);
|
||||
teammate.position.set(
|
||||
(Math.random() - 0.5) * 50,
|
||||
1.5,
|
||||
(Math.random() - 0.5) * 80
|
||||
);
|
||||
teammate.castShadow = true;
|
||||
teammate.team = 'player';
|
||||
teammate.lastVelocity = new THREE.Vector3();
|
||||
scene.add(teammate);
|
||||
teammates.push(teammate);
|
||||
}
|
||||
|
||||
|
||||
// Simple Bot Players (Static)
|
||||
const botMaterial = new THREE.MeshStandardMaterial({ color: 0x0000ff }); // Blue bots
|
||||
const bots = [];
|
||||
for (let i = 0; i < 4; i++) {
|
||||
const bot = new THREE.Mesh(playerGeometry, botMaterial);
|
||||
bot.position.set(
|
||||
@ -124,9 +145,24 @@ for (let i = 0; i < 4; i++) {
|
||||
(Math.random() - 0.5) * 80
|
||||
);
|
||||
bot.castShadow = true;
|
||||
bot.team = 'bot';
|
||||
bot.lastVelocity = new THREE.Vector3();
|
||||
scene.add(bot);
|
||||
bots.push(bot);
|
||||
}
|
||||
|
||||
const allPlayers = [player, ...teammates, ...bots];
|
||||
|
||||
// Ball
|
||||
const ballGeometry = new THREE.SphereGeometry(0.8, 16, 16);
|
||||
const ballMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });
|
||||
const ball = new THREE.Mesh(ballGeometry, ballMaterial);
|
||||
ball.position.y = 0.8;
|
||||
ball.castShadow = true;
|
||||
ball.possessedBy = null;
|
||||
ball.velocity = new THREE.Vector3();
|
||||
scene.add(ball);
|
||||
|
||||
|
||||
// Player Controls
|
||||
const keyboardState = {};
|
||||
@ -134,19 +170,136 @@ window.addEventListener('keydown', (e) => { keyboardState[e.code] = true; });
|
||||
window.addEventListener('keyup', (e) => { keyboardState[e.code] = false; });
|
||||
|
||||
const playerSpeed = 0.2;
|
||||
const playerRadius = 1; // Approximate radius for collision
|
||||
|
||||
function updatePlayerPosition() {
|
||||
const velocity = new THREE.Vector3();
|
||||
|
||||
if (keyboardState['ArrowUp']) {
|
||||
player.position.x -= playerSpeed;
|
||||
velocity.x -= playerSpeed;
|
||||
}
|
||||
if (keyboardState['ArrowDown']) {
|
||||
player.position.x += playerSpeed;
|
||||
velocity.x += playerSpeed;
|
||||
}
|
||||
if (keyboardState['ArrowLeft']) {
|
||||
player.position.z += playerSpeed;
|
||||
velocity.z += playerSpeed;
|
||||
}
|
||||
if (keyboardState['ArrowRight']) {
|
||||
player.position.z -= playerSpeed;
|
||||
velocity.z -= playerSpeed;
|
||||
}
|
||||
|
||||
if (velocity.lengthSq() > 0) {
|
||||
player.lastVelocity.copy(velocity);
|
||||
}
|
||||
|
||||
const newPosition = player.position.clone().add(velocity);
|
||||
|
||||
// Collision detection with other players
|
||||
let collision = false;
|
||||
for (const otherPlayer of allPlayers) {
|
||||
if (otherPlayer === player) continue;
|
||||
const distance = newPosition.distanceTo(otherPlayer.position);
|
||||
if (distance < playerRadius * 2) {
|
||||
collision = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!collision) {
|
||||
player.position.copy(newPosition);
|
||||
}
|
||||
|
||||
// Shooting
|
||||
if (keyboardState['KeyD']) {
|
||||
shoot();
|
||||
}
|
||||
|
||||
// Passing
|
||||
if (keyboardState['KeyS']) {
|
||||
pass();
|
||||
}
|
||||
}
|
||||
|
||||
function shoot() {
|
||||
if (ball.possessedBy === player) {
|
||||
ball.possessedBy = null;
|
||||
const shootPower = 1.5;
|
||||
ball.velocity.copy(player.lastVelocity).normalize().multiplyScalar(shootPower);
|
||||
}
|
||||
}
|
||||
|
||||
function pass() {
|
||||
if (ball.possessedBy === player) {
|
||||
ball.possessedBy = null;
|
||||
const passPower = 0.8;
|
||||
const passAngle = Math.PI / 6; // 30 degrees
|
||||
|
||||
let targetTeammate = null;
|
||||
let minAngle = passAngle;
|
||||
|
||||
const playerDirection = player.lastVelocity.clone().normalize();
|
||||
|
||||
for (const teammate of teammates) {
|
||||
const toTeammate = teammate.position.clone().sub(player.position);
|
||||
const distanceToTeammate = toTeammate.length();
|
||||
toTeammate.normalize();
|
||||
|
||||
const angle = playerDirection.angleTo(toTeammate);
|
||||
|
||||
if (angle < minAngle && distanceToTeammate < 40) { // Max pass distance
|
||||
minAngle = angle;
|
||||
targetTeammate = teammate;
|
||||
}
|
||||
}
|
||||
|
||||
if (targetTeammate) {
|
||||
const direction = targetTeammate.position.clone().sub(player.position).normalize();
|
||||
ball.velocity.copy(direction).multiplyScalar(passPower);
|
||||
} else {
|
||||
ball.velocity.copy(playerDirection).multiplyScalar(passPower);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function updateBallPosition() {
|
||||
const possessionDistance = playerRadius + 0.8 + 0.5; // player radius + ball radius + buffer
|
||||
|
||||
if (ball.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 (ball.possessedBy.lastVelocity && ball.possessedBy.lastVelocity.lengthSq() > 0) {
|
||||
const direction = ball.possessedBy.lastVelocity.clone().normalize();
|
||||
offset = direction.multiplyScalar(ballOffset);
|
||||
}
|
||||
ball.position.copy(ball.possessedBy.position).add(offset);
|
||||
ball.position.y = 0.8; // Keep it on the ground
|
||||
} else {
|
||||
// Update ball position based on velocity (when not possessed)
|
||||
ball.position.add(ball.velocity);
|
||||
ball.velocity.multiplyScalar(0.97); // Friction
|
||||
|
||||
// Ball collision with players
|
||||
for (const p of allPlayers) {
|
||||
const distance = ball.position.distanceTo(p.position);
|
||||
if (distance < playerRadius + 0.8) {
|
||||
const normal = ball.position.clone().sub(p.position).normalize();
|
||||
ball.velocity.reflect(normal).multiplyScalar(0.8);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check for gaining possession
|
||||
for (const p of allPlayers) {
|
||||
const distanceToPlayer = ball.position.distanceTo(p.position);
|
||||
if (distanceToPlayer < possessionDistance && ball.velocity.lengthSq() < 0.1) {
|
||||
ball.possessedBy = p;
|
||||
ball.velocity.set(0, 0, 0);
|
||||
break; // Only one player can possess the ball at a time
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,6 +307,7 @@ function updatePlayerPosition() {
|
||||
function animate() {
|
||||
requestAnimationFrame(animate);
|
||||
updatePlayerPosition();
|
||||
updateBallPosition();
|
||||
|
||||
// Camera follows player from the sideline
|
||||
camera.position.z = player.position.z;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user