cars / index.html
akhaliq's picture
akhaliq HF Staff
Update index.html
a679c46 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Car Simulator</title>
<style>
body { margin: 0; overflow: hidden; }
canvas { display: block; }
</style>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js"></script>
<script>
// Scene setup
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x87CEEB);
// Camera
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 10, 20);
// Renderer
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
// Controls
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// Lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(50, 100, 50);
directionalLight.castShadow = true;
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
scene.add(directionalLight);
// Ground
const groundGeometry = new THREE.PlaneGeometry(500, 500);
const groundMaterial = new THREE.MeshStandardMaterial({
color: 0x4CAF50,
roughness: 0.8
});
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = -Math.PI / 2;
ground.receiveShadow = true;
scene.add(ground);
// Road
const roadGeometry = new THREE.PlaneGeometry(15, 500);
const roadMaterial = new THREE.MeshStandardMaterial({
color: 0x333333,
roughness: 0.9
});
const road = new THREE.Mesh(roadGeometry, roadMaterial);
road.rotation.x = -Math.PI / 2;
road.position.y = 0.01;
road.receiveShadow = true;
scene.add(road);
// Car
const carGroup = new THREE.Group();
scene.add(carGroup);
const carBodyGeometry = new THREE.BoxGeometry(5, 1, 2);
const carBodyMaterial = new THREE.MeshStandardMaterial({ color: 0xFF5722 });
const carBody = new THREE.Mesh(carBodyGeometry, carBodyMaterial);
carBody.position.y = 1;
carBody.castShadow = true;
carGroup.add(carBody);
const carTopGeometry = new THREE.BoxGeometry(3, 1, 2);
const carTopMaterial = new THREE.MeshStandardMaterial({ color: 0xE91E63 });
const carTop = new THREE.Mesh(carTopGeometry, carTopMaterial);
carTop.position.y = 2;
carTop.castShadow = true;
carGroup.add(carTop);
function addWheel(x, z) {
const wheelGeometry = new THREE.CylinderGeometry(0.5, 0.5, 0.4, 32);
const wheelMaterial = new THREE.MeshStandardMaterial({ color: 0x212121 });
const wheel = new THREE.Mesh(wheelGeometry, wheelMaterial);
wheel.rotation.z = Math.PI / 2;
wheel.position.set(x, 0.5, z);
wheel.castShadow = true;
carGroup.add(wheel);
}
addWheel(-2, -1);
addWheel(-2, 1);
addWheel(2, -1);
addWheel(2, 1);
// Mountains
function createMountain() {
const mountainGroup = new THREE.Group();
const height = 10 + Math.random() * 20;
const width = 20 + Math.random() * 30;
const depth = 20 + Math.random() * 30;
const mountainGeometry = new THREE.ConeGeometry(width, height, 32);
const mountainMaterial = new THREE.MeshStandardMaterial({ color: 0x795548 });
const mountain = new THREE.Mesh(mountainGeometry, mountainMaterial);
mountain.rotation.x = -Math.PI / 2;
mountain.position.y = height / 2;
mountain.castShadow = true;
mountainGroup.add(mountain);
const positionX = -250 + Math.random() * 500;
const positionZ = -250 + Math.random() * 500;
mountainGroup.position.set(positionX, 0, positionZ);
return mountainGroup;
}
for (let i = 0; i < 15; i++) {
scene.add(createMountain());
}
// Trees
function createTree() {
const treeGroup = new THREE.Group();
const trunkGeometry = new THREE.CylinderGeometry(0.3, 0.5, 5);
const trunkMaterial = new THREE.MeshStandardMaterial({ color: 0x5D4037 });
const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
trunk.position.y = 2.5;
trunk.castShadow = true;
treeGroup.add(trunk);
const leavesGeometry = new THREE.ConeGeometry(2, 4, 8);
const leavesMaterial = new THREE.MeshStandardMaterial({ color: 0x2E7D32 });
const leaves = new THREE.Mesh(leavesGeometry, leavesMaterial);
leaves.position.y = 6;
leaves.castShadow = true;
treeGroup.add(leaves);
const positionX = -200 + Math.random() * 400;
const positionZ = -200 + Math.random() * 400;
treeGroup.position.set(positionX, 0, positionZ);
return treeGroup;
}
for (let i = 0; i < 30; i++) {
scene.add(createTree());
}
// Clouds
function createCloud() {
const cloudGroup = new THREE.Group();
for (let i = 0; i < 3; i++) {
const cloudGeometry = new THREE.SphereGeometry(2.5 + Math.random() * 2, 16, 16);
const cloudMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });
const cloud = new THREE.Mesh(cloudGeometry, cloudMaterial);
cloud.position.set(
-3 + Math.random() * 6,
-2 + Math.random() * 4,
-3 + Math.random() * 6
);
cloud.castShadow = true;
cloudGroup.add(cloud);
}
const positionX = -200 + Math.random() * 400;
const positionZ = -200 + Math.random() * 400;
const positionY = 20 + Math.random() * 30;
cloudGroup.position.set(positionX, positionY, positionZ);
return cloudGroup;
}
for (let i = 0; i < 10; i++) {
scene.add(createCloud());
}
// Train
const trainGroup = new THREE.Group();
scene.add(trainGroup);
function createTrainCar() {
const carGroup = new THREE.Group();
const carGeometry = new THREE.BoxGeometry(5, 3, 8);
const carMaterial = new THREE.MeshStandardMaterial({ color: 0x2196F3 });
const car = new THREE.Mesh(carGeometry, carMaterial);
car.position.y = 1.5;
car.castShadow = true;
carGroup.add(car);
const wheelGeometry = new THREE.CylinderGeometry(0.8, 0.8, 1, 32);
const wheelMaterial = new THREE.MeshStandardMaterial({ color: 0x212121 });
const wheelFL = new THREE.Mesh(wheelGeometry, wheelMaterial);
wheelFL.rotation.z = Math.PI / 2;
wheelFL.position.set(-2.5, 0.8, 3);
wheelFL.castShadow = true;
carGroup.add(wheelFL);
const wheelFR = new THREE.Mesh(wheelGeometry, wheelMaterial);
wheelFR.rotation.z = Math.PI / 2;
wheelFR.position.set(2.5, 0.8, 3);
wheelFR.castShadow = true;
carGroup.add(wheelFR);
const wheelBL = new THREE.Mesh(wheelGeometry, wheelMaterial);
wheelBL.rotation.z = Math.PI / 2;
wheelBL.position.set(-2.5, 0.8, -3);
wheelBL.castShadow = true;
carGroup.add(wheelBL);
const wheelBR = new THREE.Mesh(wheelGeometry, wheelMaterial);
wheelBR.rotation.z = Math.PI / 2;
wheelBR.position.set(2.5, 0.8, -3);
wheelBR.castShadow = true;
carGroup.add(wheelBR);
return carGroup;
}
// Train tracks
const trackRadius = 100;
for (let i = 0; i < 64; i++) {
const angle = (i / 64) * Math.PI * 2;
const x = Math.cos(angle) * trackRadius;
const z = Math.sin(angle) * trackRadius;
const trackGeometry = new THREE.BoxGeometry(5, 0.2, 1);
const trackMaterial = new THREE.MeshStandardMaterial({ color: 0x212121 });
const track = new THREE.Mesh(trackGeometry, trackMaterial);
track.position.set(x, 0.02, z);
track.rotation.y = angle;
track.receiveShadow = true;
scene.add(track);
if (i % 8 === 0) {
const sleeperGeometry = new THREE.BoxGeometry(0.5, 0.5, 3);
const sleeperMaterial = new THREE.MeshStandardMaterial({ color: 0x795548 });
const sleeper = new THREE.Mesh(sleeperGeometry, sleeperMaterial);
sleeper.position.set(x, 0.02, z);
sleeper.receiveShadow = true;
scene.add(sleeper);
}
}
// Create train with multiple cars
for (let i = 0; i < 4; i++) {
const trainCar = createTrainCar();
trainCar.position.z = -i * 8;
trainGroup.add(trainCar);
}
// Move car forward with keyboard
const keys = {};
document.addEventListener('keydown', (e) => { keys[e.code] = true; });
document.addEventListener('keyup', (e) => { keys[e.code] = false; });
// Animation
let trainAngle = 0;
function animate() {
requestAnimationFrame(animate);
// Car movement
if (keys['ArrowUp']) {
carGroup.position.z -= 0.2;
}
if (keys['ArrowDown']) {
carGroup.position.z += 0.2;
}
if (keys['ArrowLeft']) {
carGroup.rotation.y += 0.05;
}
if (keys['ArrowRight']) {
carGroup.rotation.y -= 0.05;
}
// Train movement
trainAngle += 0.005;
trainGroup.position.x = Math.cos(trainAngle) * trackRadius;
trainGroup.position.z = Math.sin(trainAngle) * trackRadius;
trainGroup.rotation.y = -trainAngle + Math.PI / 2;
// Update camera to follow car
const carDirection = new THREE.Vector3();
carGroup.getWorldDirection(carDirection);
carDirection.multiplyScalar(-10);
const carPosition = carGroup.position.clone();
carPosition.y += 5;
camera.position.lerp(carPosition.clone().add(carDirection), 0.1);
camera.lookAt(carPosition);
controls.update();
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();
</script>
</body>
</html>