function initThreeJS() {
// 1. Scene
scene = new THREE.Scene();
scene.background = new THREE.Color(0x87ceeb); // Sky blue background
// 2. Camera
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 10, 20); // Initial camera position
// 3. Renderer
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio); // Handle retina displays
renderer.domElement.id = 'threejs-canvas';
document.body.appendChild(renderer.domElement);
// 5. Lighting
const ambientLight = new THREE.AmbientLight(0x404040); // Soft white light
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 1); // White directional light
directionalLight.position.set(5, 10, 7);
directionalLight.castShadow = true; // Enable shadows
directionalLight.shadow.mapSize.width = 1024;
directionalLight.shadow.mapSize.height = 1024;
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = chunkSize * visibleRadius * 2;
directionalLight.shadow.camera.left = -chunkSize * visibleRadius;
directionalLight.shadow.camera.right = chunkSize * visibleRadius;
directionalLight.shadow.camera.top = chunkSize * visibleRadius;
directionalLight.shadow.camera.bottom = -chunkSize * visibleRadius;
scene.add(directionalLight);
// --- Create Reusable Geometries and Materials Here (ONE TIME!) ---
groundGeometry = new THREE.PlaneGeometry(chunkSize, chunkSize);
roadGeometry = new THREE.PlaneGeometry(10, chunkSize);
sirenLightGeometry = new THREE.CylinderGeometry(0.2, 0.2, 0.5, 8);
groundMaterial = new THREE.MeshLambertMaterial({ color: 0x33aa33 });
roadMaterial = new THREE.MeshLambertMaterial({ color: 0x555555 });
buildingMaterial = new THREE.MeshLambertMaterial({ color: 0xaaaaaa });
npcMaterial = new THREE.MeshLambertMaterial({ color: 0x00ff00 });
redSirenMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 });
blueSirenMaterial = new THREE.MeshLambertMaterial({ color: 0x0000ff });
// Car parts
carBodyGeometry = new THREE.BoxGeometry(3, 1, 1.5);
carBodyMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 });
carCabinGeometry = new THREE.BoxGeometry(2, 0.8, 1.2);
carCabinMaterial = new THREE.MeshLambertMaterial({ color: 0x3333ff });
carWheelGeometry = new THREE.CylinderGeometry(0.5, 0.5, 0.4, 16);
carWheelMaterial = new THREE.MeshLambertMaterial({ color: 0x000000 });
// Cop Car parts
copCarBodyGeometry = new THREE.BoxGeometry(3, 1, 1.5);
copCarBodyMaterial = new THREE.MeshLambertMaterial({ color: 0x0000ff });
copCarCabinGeometry = new THREE.BoxGeometry(2, 0.8, 1.2);
copCarCabinMaterial = new THREE.MeshLambertMaterial({ color: 0x3333ff });
copCarWheelGeometry = new THREE.CylinderGeometry(0.5, 0.5, 0.4, 16);
copCarWheelMaterial = new THREE.MeshLambertMaterial({ color: 0x000000 });
// Player parts
playerBodyGeometry = new THREE.CylinderGeometry(0.5, 0.5, 1.8, 16);
playerBodyMaterial = new THREE.MeshLambertMaterial({ color: 0x00ff00 });
// Gun parts
gunGeometry = new THREE.CylinderGeometry(0.1, 0.2, 0.8, 8);
gunMaterial = new THREE.MeshLambertMaterial({ color: 0x333333 });
// Tank parts
tankBodyGeometry = new THREE.BoxGeometry(4, 2, 2.5);
tankBodyMaterial = new THREE.MeshLambertMaterial({ color: 0x444444 });
turretGeometry = new THREE.CylinderGeometry(0.8, 1.2, 1, 16);
turretMaterial = new THREE.MeshLambertMaterial({ color: 0x666666 });
cannonGeometry = new THREE.CylinderGeometry(0.3, 0.4, 2, 8);
cannonMaterial = new THREE.MeshLambertMaterial({ color: 0x333333 });
tankWheelGeometry = new THREE.BoxGeometry(0.8, 1.5, 0.5);
// SWAT Truck parts
swatTruckBodyGeometry = new THREE.BoxGeometry(4, 1.5, 2);
swatTruckBodyMaterial = new THREE.MeshLambertMaterial({ color: 0x222222 });
swatTruckCabinGeometry = new THREE.BoxGeometry(3, 1.2, 1.8);
swatTruckCabinMaterial = new THREE.MeshLambertMaterial({ color: 0x111111 });
swatTruckWheelGeometry = new THREE.CylinderGeometry(0.7, 0.7, 0.6, 16);
swatTruckWheelMaterial = new THREE.MeshLambertMaterial({ color: 0x000000 });
// 6. Create Car
createCar();
// 7. Create On-Foot Player and Gun
createPlayer();
createGun();
// 8. Position player at car's initial position
player.position.copy(car.position);
player.visible = false;
// 9. Initial chunk generation
updateChunks();
// 10. Add Keyboard and Mouse Event Listeners for Car & Player Control
document.addEventListener('keydown', onKeyDown);
document.addEventListener('keyup', onKeyUp);
document.addEventListener('mousedown', onMouseDown);
}