```javascript // SquirrelVision 3D Playground - Main Game Script class SquirrelVisionPlayground { constructor() { this.scene = null; this.camera = null; this.renderer = null; this.controls = null; this.objects = []; this.isPlaying = false; this.moveForward = false; this.moveBackward = false; this.moveLeft = false; this.moveRight = false; this.canJump = false; this.prevTime = performance.now(); this.velocity = new THREE.Vector3(); this.direction = new THREE.Vector3(); this.interactiveObjects = []; this.init(); } async init() { // Update loading progress this.updateLoadingProgress(10, 'Creating 3D scene...'); // Create scene this.scene = new THREE.Scene(); this.scene.background = new THREE.Color(0x87CEEB); // Sky blue // Create camera this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); this.camera.position.set(0, 1.6, 0); // Create renderer this.renderer = new THREE.WebGLRenderer({ antialias: true }); this.renderer.setSize(window.innerWidth, window.innerHeight); this.renderer.shadowMap.enabled = true; this.renderer.shadowMap.type = THREE.PCFSoftShadowMap; // Add renderer to DOM document.getElementById('gameContainer').appendChild(this.renderer.domElement); this.updateLoadingProgress(30, 'Setting up lighting...'); await this.setupLighting(); this.updateLoadingProgress(50, 'Creating world geometry...'); await this.createWorld(); this.updateLoadingProgress(70, 'Adding interactive objects...'); await this.addInteractiveObjects(); this.updateLoadingProgress(90, 'Setting up controls...'); this.setupControls(); this.updateLoadingProgress(100, 'Ready!'); // Show start screen after a brief delay setTimeout(() => { document.getElementById('loadingScreen').style.display = 'none'; document.getElementById('startScreen').style.display = 'flex'; }, 500); // Start animation loop this.animate(); // Handle window resize window.addEventListener('resize', () => this.onWindowResize()); } updateLoadingProgress(percent, text) { document.getElementById('progressBar').style.width = percent + '%'; document.getElementById('loadingText').textContent = text; } async setupLighting() { // Ambient light const ambientLight = new THREE.AmbientLight(0x404040, 0.6); this.scene.add(ambientLight); // Directional light (sun) const directionalLight = new THREE.DirectionalLight(0xffffff, 1); directionalLight.position.set(50, 50, 50); directionalLight.castShadow = true; directionalLight.shadow.mapSize.width = 2048; directionalLight.shadow.mapSize.height = 2048; directionalLight.shadow.camera.near = 0.5; directionalLight.shadow.camera.far = 500; directionalLight.shadow.camera.left = -100; directionalLight.shadow.camera.right = 100; directionalLight.shadow.camera.top = 100; directionalLight.shadow.camera.bottom = -100; this.scene.add(directionalLight); // Hemisphere light for more natural outdoor lighting const hemisphereLight = new THREE.HemisphereLight(0x87CEEB, 0x8B4513, 0.4); this.scene.add(hemisphereLight); } async createWorld() { // Create ground const groundGeometry = new THREE.PlaneGeometry(100, 100); const groundMaterial = new THREE.MeshLambertMaterial({ color: 0x7CFC00, // Lawn green side: THREE.DoubleSide }); const ground = new THREE.Mesh(groundGeometry, groundMaterial); ground.rotation.x = -Math.PI / 2; ground.receiveShadow = true; this.scene.add(ground); // Add some grass texture variation const grassTexture = new THREE.MeshLambertMaterial({ color: 0x32CD32, // Lime green side: THREE.DoubleSide }); for (let i = 0; i < 200; i++) { const grassBlade = new THREE.Mesh( new THREE.PlaneGeometry(0.1, 0.5), grassTexture ); grassBlade.position.set( Math.random() * 80 - 40, 0.25, Math.random() * 80 - 40 ); grassBlade.rotation.x = -Math.PI / 2; grassBlade.rotation.z = Math.random() * Math.PI; this.scene.add(grassBlade); } // Create trees for (let i = 0; i < 15; i++) { this.createTree( Math.random() * 70 - 35, Math.random() * 70 - 35 ); } // Create buildings this.createBuilding(-15, 0, -15, 8, 12, 8, 0x888888); this.createBuilding(15, 0, 15, 6, 8, 6, 0x666666); this.createBuilding(-15, 0, 15, 5, 6, 5, 0x777777); // Create a central fountain this.createFountain(0, 0, 0); // Create some rocks for (let i = 0; i < 10; i++) { this.createRock( Math.random() * 60 - 30, Math.random() * 60 - 30 ); } } createTree(x, z) { // Tree trunk const trunkGeometry = new THREE.CylinderGeometry(0.3, 0.4, 4); const trunkMaterial = new THREE.MeshLambertMaterial({ color: 0x8B4513 }); const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial); trunk.position.set(x, 2, z); trunk.castShadow = true; this.scene.add(trunk); // Tree leaves const leavesGeometry = new THREE.SphereGeometry(2); const leavesMaterial = new THREE.MeshLambertMaterial({ color: 0x228B22 }); const leaves = new THREE.Mesh(leavesGeometry, leavesMaterial); leaves.position.set(x, 5, z); leaves.castShadow = true; this.scene.add(leaves); } createBuilding(x, y, z, width, height, depth, color) { const geometry = new THREE.BoxGeometry(width, height, depth); const material = new THREE.MeshLambertMaterial({ color: color }); const building = new THREE.Mesh(geometry, material); building.position.set(x, height / 2, z); building.castShadow = true; building.receiveShadow = true; this.scene.add(building); // Add windows const windowMaterial = new THREE.MeshLambertMaterial({ color: 0x87CEEB }); for (let i = 0; i < 3; i++) { for (let j = 0; j < 2; j++) { const window = new THREE.Mesh( new THREE.PlaneGeometry(0.8, 0.8), windowMaterial ); window.position.set( x + (j - 0.5) * (width - 1), y + 2 + i * 2.5, z + depth / 2 + 0.1 ); window.rotation.y = Math.PI; this.scene.add(window); } } } createFountain(x, y, z) { // Fountain base const baseGeometry = new THREE.CylinderGeometry(3, 3, 0.5, 32); const baseMaterial = new THREE.MeshLambertMaterial({ color: 0xCCCCCC }); const base = new THREE.Mesh(baseGeometry, baseMaterial); base.position.set(x, 0.25, z); base.receiveShadow = true; this.scene.add(base); // Fountain center const centerGeometry = new THREE.CylinderGeometry(1, 1.2, 2, 32); const centerMaterial = new THREE.MeshLambertMaterial({ color: 0xDDDDDD }); const center = new THREE.Mesh(centerGeometry, centerMaterial); center.position.set(x, 1.5, z); center.castShadow = true; this.scene.add(center); // Water (animated) const waterGeometry = new THREE.CylinderGeometry(1.2, 1.2, 0.2, 32); const waterMaterial = new THREE.MeshLambertMaterial({ color: 0x4F94CD, transparent: true, opacity: 0.7 }); const water = new THREE.Mesh(waterGeometry, waterMaterial); water.position.set(x, 1.1, z); water.userData = { type: 'fountain', animate: true }; this.scene.add(water); this.interactiveObjects.push(water); } createRock(x, z) { const geometry = new THREE.SphereGeometry(0.5 + Math.random() * 0.5, 6, 6); const material = new THREE.MeshLambertMaterial({ color: 0x696969 }); const rock = new THREE.Mesh(geometry, material); rock.position.set(x, 0.5, z); rock.rotation.set( Math.random() * Math.PI, Math.random() * Math.PI, Math.random() * Math.PI ); rock.castShadow = true; this.scene.add(rock); } async addInteractiveObjects() { // Create interactive squirrel NPC this.createSquirrel(10, 0, 0); // Create treasure chest this.createTreasureChest(-10, 0, 10); // Create signpost this.createSignpost(15, 0, -15); } createSquirrel(x, y, z) { // Squirrel body const bodyGeometry = new THREE.SphereGeometry(0.4, 16, 16); const bodyMaterial = new THREE.MeshLambertMaterial({ color: 0xFF8C00 }); const body = new THREE.Mesh(bodyGeometry, bodyMaterial); body.position.set(x, y + 0.4, z); // Squirrel head const headGeometry = new THREE.SphereGeometry(0.3, 16, 16); const head = new THREE.Mesh(headGeometry, bodyMaterial); head.position.set(x, y + 0.8, z + 0.3); // Squirrel tail const tailGeometry = new THREE.SphereGeometry(0.25, 16, 16); const tail = new THREE.Mesh(tailGeometry, bodyMaterial); tail.position.set(x, y + 0.4, z - 0.5); tail.scale.set(1.5, 0.8, 2); const squirrel = new THREE.Group(); squirrel.add(body); squirrel.add(head); squirrel.add(tail); squirrel.userData = { type: 'squirrel', interactive: true, message: "Hello! I'm your friendly squirrel guide. Explore the playground and find hidden treasures!" }; squirrel.castShadow = true; this.scene.add(squirrel); this.interactiveObjects.push(squirrel); } createTreasureChest(x, y, z) { const chestGeometry = new THREE.BoxGeometry(1.5, 0.8, 1); const chestMaterial = new THREE.MeshLambertMaterial({ color: 0xDAA520 });