import * as THREE from 'three'; import type { SceneResourceBag } from '@/scene/resources'; export function createCar(resources: SceneResourceBag) { const group = new THREE.Group(); group.position.set(0, 0.69, 0.5); group.scale.set(0.9, 0.65, 0.78); const bodyMaterial = resources.own('material', new THREE.MeshStandardMaterial({ color: 0x202938, roughness: 0.28, metalness: 0.78, })); const glassMaterial = resources.own('material', new THREE.MeshStandardMaterial({ color: 0x10273a, roughness: 0.12, metalness: 0.35, })); const tailMaterial = resources.own('material', new THREE.MeshBasicMaterial({ color: 0xff315f })); const silhouetteMaterial = resources.own('material', new THREE.MeshBasicMaterial({ color: 0x405875 })); const fasciaMaterial = resources.own('material', new THREE.MeshStandardMaterial({ color: 0x151c28, roughness: 0.42, metalness: 0.62, })); const underglowMaterial = resources.own('material', new THREE.MeshBasicMaterial({ color: 0x28d8ef, transparent: true, opacity: 0.42, })); const lowerGeometry = resources.own('geometry', new THREE.BoxGeometry(4.6, 0.55, 6.6)); const lower = new THREE.Mesh(lowerGeometry, bodyMaterial); lower.scale.set(1, 1, 0.92); group.add(lower); const cabinGeometry = resources.own('geometry', new THREE.CylinderGeometry(1.25, 1.72, 2.9, 4)); const cabin = new THREE.Mesh(cabinGeometry, glassMaterial); cabin.rotation.set(Math.PI / 2, Math.PI / 4, 0); cabin.scale.set(1, 1, 0.62); cabin.position.set(0, 0.64, -0.35); group.add(cabin); const lightGeometry = resources.own('geometry', new THREE.BoxGeometry(3.9, 0.12, 0.08)); const rearLight = new THREE.Mesh(lightGeometry, tailMaterial); rearLight.position.set(0, 0.04, 3.08); group.add(rearLight); const rearProfile = new THREE.Shape(); rearProfile.moveTo(-2.5, -0.32); rearProfile.lineTo(-2.32, 0.28); rearProfile.lineTo(-1.42, 0.72); rearProfile.lineTo(1.42, 0.72); rearProfile.lineTo(2.32, 0.28); rearProfile.lineTo(2.5, -0.32); rearProfile.closePath(); const silhouetteGeometry = resources.own('geometry', new THREE.ShapeGeometry(rearProfile)); const silhouette = new THREE.Mesh(silhouetteGeometry, silhouetteMaterial); silhouette.name = 'rear-silhouette'; silhouette.position.z = 2.98; group.add(silhouette); const fasciaGeometry = resources.own('geometry', new THREE.BoxGeometry(4.3, 0.38, 0.22)); const fascia = new THREE.Mesh(fasciaGeometry, fasciaMaterial); fascia.position.set(0, -0.12, 2.94); group.add(fascia); const shoulderGeometry = resources.own('geometry', new THREE.BoxGeometry(5.05, 0.18, 1.1)); const shoulders = new THREE.Mesh(shoulderGeometry, bodyMaterial); shoulders.position.set(0, 0.18, 2.48); group.add(shoulders); const accentMaterial = resources.own('material', new THREE.MeshBasicMaterial({ color: 0x28d8ef })); const accentGeometry = resources.own('geometry', new THREE.BoxGeometry(0.36, 0.1, 0.08)); for (const x of [-2.02, 2.02]) { const accent = new THREE.Mesh(accentGeometry, accentMaterial); accent.position.set(x, -0.15, 3.11); group.add(accent); } const glowGeometry = resources.own('geometry', new THREE.PlaneGeometry(4.2, 6.2)); const underglow = new THREE.Mesh(glowGeometry, underglowMaterial); underglow.rotation.x = -Math.PI / 2; underglow.position.y = -0.31; group.add(underglow); const wheelGeometry = resources.own('geometry', new THREE.CylinderGeometry(0.62, 0.62, 0.42, 18)); const wheelMaterial = resources.own('material', new THREE.MeshStandardMaterial({ color: 0x030407, roughness: 0.92 })); for (const x of [-2.05, 2.05]) { for (const z of [-2.15, 2.15]) { const wheel = new THREE.Mesh(wheelGeometry, wheelMaterial); wheel.rotation.z = Math.PI / 2; wheel.position.set(x, -0.18, z); group.add(wheel); } } return { group, update(speed: number, acceleration: number, elapsedSeconds: number) { const response = Math.min(1, Math.max(0, acceleration)); group.position.y = 0.69 + Math.sin(elapsedSeconds * (2.2 + speed)) * (0.012 + response * 0.018); group.rotation.z = Math.sin(elapsedSeconds * 1.4) * 0.003 * response; tailMaterial.color.setRGB(1, 0.12 + response * 0.08, 0.28 + response * 0.08); underglowMaterial.opacity = 0.32 + Math.min(0.3, speed * 0.2); }, }; }