feat: build procedural lifecycle-safe drive scene

This commit is contained in:
2026-09-02 04:53:55 +03:00
parent cc0887fee0
commit fd8347fbdc
14 changed files with 1822 additions and 0 deletions

69
src/scene/world/car.ts Normal file
View File

@@ -0,0 +1,69 @@
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.72, 4.4);
const bodyMaterial = resources.own('material', new THREE.MeshStandardMaterial({
color: 0x111722,
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 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 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.72 + 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);
},
};
}