Pong 3D
Classic arcade game reimagined in 3D space with realistic physics, AI opponent, and interactive controls.
What this code does
- Classic Pong Gameplay: faithful recreation of the iconic arcade game with modern 3D graphics and smooth physics.
- Dual Control System: play with mouse movement or keyboard controls (Arrow Keys/WASD) for paddle movement.
- AI Opponent: intelligent computer player with adjustable difficulty level that tracks ball movement and reacts realistically.
- Realistic Ball Physics: ball bounces with proper physics, spin effects based on paddle hit position, and speed maintenance.
- Visual Effects: ball trail system, paddle glow effects on hits, shadows, and dramatic lighting for enhanced gameplay.
- Score System: first to configurable win score (default 5) wins the game with automatic reset and ball serving.
- Game State Management: pause/resume functionality, speed controls, and comprehensive settings for customization.
- 3D Environment: complete game field with walls, goal areas, center line, and atmospheric lighting effects.
JavaScript (plain)
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000)
camera.position.set(0, 8, 25)
const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(width, height)
renderer.shadowMap.enabled = true
document.querySelector('#app').appendChild(renderer.domElement)
// Create game field
const fieldGeometry = new THREE.PlaneGeometry(20, 30)
const fieldMaterial = new THREE.MeshLambertMaterial({ color: 0x004400, transparent: true, opacity: 0.8 })
const field = new THREE.Mesh(fieldGeometry, fieldMaterial)
field.rotation.x = -Math.PI / 2
scene.add(field)
// Create paddles
const paddleGeometry = new THREE.BoxGeometry(3, 0.5, 1)
const playerPaddle = new THREE.Mesh(paddleGeometry, new THREE.MeshLambertMaterial({ color: 0x00ff00 }))
const aiPaddle = new THREE.Mesh(paddleGeometry, new THREE.MeshLambertMaterial({ color: 0xff0000 }))
playerPaddle.position.set(0, 0.25, 12)
aiPaddle.position.set(0, 0.25, -12)
scene.add(playerPaddle)
scene.add(aiPaddle)
// Create ball
const ballGeometry = new THREE.SphereGeometry(0.3, 16, 16)
const ballMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff, emissive: 0x222222 })
const ball = new THREE.Mesh(ballGeometry, ballMaterial)
ball.position.set(0, 0.3, 0)
scene.add(ball)
// Ball physics
const ballVelocity = new THREE.Vector3(0, 0, 8)
// Input handling
const keys = {}
document.addEventListener('keydown', (e) => { keys[e.code] = true })
document.addEventListener('keyup', (e) => { keys[e.code] = false })
// Lighting
const ambientLight = new THREE.AmbientLight(0x404040, 0.4)
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8)
directionalLight.position.set(0, 10, 0)
scene.add(ambientLight)
scene.add(directionalLight)
function animate() {
requestAnimationFrame(animate)
// Player movement
if (keys['ArrowLeft'] && playerPaddle.position.x > -8.5) playerPaddle.position.x -= 0.3
if (keys['ArrowRight'] && playerPaddle.position.x < 8.5) playerPaddle.position.x += 0.3
// AI movement
const aiTarget = ball.position.x * 0.8
aiPaddle.position.x += (aiTarget - aiPaddle.position.x) * 0.1
// Ball movement
ball.position.add(ballVelocity.clone().multiplyScalar(0.016))
// Ball collision with walls
if (ball.position.x > 9.7 || ball.position.x < -9.7) ballVelocity.x *= -1
// Paddle collision
if (ball.position.z > 11.5 && Math.abs(ball.position.x - playerPaddle.position.x) < 1.8) {
ballVelocity.z *= -1
ballVelocity.x += (ball.position.x - playerPaddle.position.x) * 0.3
}
if (ball.position.z < -11.5 && Math.abs(ball.position.x - aiPaddle.position.x) < 1.8) {
ballVelocity.z *= -1
ballVelocity.x += (ball.position.x - aiPaddle.position.x) * 0.3
}
// Reset ball if it goes off field
if (ball.position.z > 16 || ball.position.z < -16) {
ball.position.set(0, 0.3, 0)
ballVelocity.set(Math.random() * 4 - 2, 0, Math.random() > 0.5 ? 8 : -8)
}
renderer.render(scene, camera)
}
animate()