Ride: proper 2/4 seating plus doors, dash, console, wheel
Two rows of two like a real car (2 riders: 2-seater; more: 4-seater with one seat left empty); riders sit on cushions against backrests with headrests, driver ahead of the wheel. Long painted doors with handles, full-width dashboard with dial strip, center console with shifter glow, torus steering wheel on a column. Fender arches fattened. Rng cadence preserved per rider so downstream draws don't move.
This commit is contained in:
@@ -552,6 +552,10 @@ export const ride = {
|
||||
const hood = add(new T.Mesh(new T.BoxGeometry(1.5, 0.24, 1.15), paintMat()));
|
||||
hood.position.set(0, 0.18, -1.6);
|
||||
hood.rotation.x = -0.07;
|
||||
// Hood spine: breaks the flat table read.
|
||||
const spine = add(new T.Mesh(new T.BoxGeometry(0.28, 0.07, 1.0), paintMat()));
|
||||
spine.position.set(0, 0.3, -1.6);
|
||||
spine.rotation.x = -0.07;
|
||||
// Trunk deck behind the cabin, meeting its lower edge.
|
||||
const trunk = add(new T.Mesh(new T.BoxGeometry(1.5, 0.2, 0.8), paintMat()));
|
||||
trunk.position.set(0, 0.2, 1.15);
|
||||
@@ -568,7 +572,7 @@ export const ride = {
|
||||
// Fenders: half-torus arches over each wheel. Torus arc 0..π
|
||||
// spans the upper half in XY; yawed 90° it arches across the
|
||||
// wheel in the rolling plane.
|
||||
const fenderGeo = new T.TorusGeometry(0.5, 0.1, 8, 12, Math.PI);
|
||||
const fenderGeo = new T.TorusGeometry(0.5, 0.12, 8, 12, Math.PI);
|
||||
for (const [wx, wz] of [[-0.95, 1.05], [0.95, 1.05], [-0.95, -1.35], [0.95, -1.35]]) {
|
||||
const fender = add(new T.Mesh(fenderGeo, paintMat()));
|
||||
fender.rotation.y = Math.PI / 2;
|
||||
@@ -622,6 +626,48 @@ export const ride = {
|
||||
const pipe = add(new T.Mesh(pipeGeo, pipeMat));
|
||||
pipe.position.set(side * 0.35, -0.45, 1.7);
|
||||
}
|
||||
// Doors: long painted panels with handles. One pair, front
|
||||
// and rear rows alike on a convertible — they flank the cabin
|
||||
// and clear the arches vertically (door bottoms sit above the
|
||||
// wheel tops).
|
||||
for (const side of [-1, 1]) {
|
||||
const door = add(new T.Mesh(new T.BoxGeometry(0.08, 0.5, 1.9), paintMat()));
|
||||
door.position.set(side * 0.89, 0.15, -0.05);
|
||||
const handle = add(new T.Mesh(new T.BoxGeometry(0.04, 0.05, 0.22), trimMat));
|
||||
handle.position.set(side * 0.945, 0.28, 0.35);
|
||||
}
|
||||
// Dashboard across the cabin front with a dial strip on top,
|
||||
// where high chase angles can see it.
|
||||
const dashPanel = add(new T.Mesh(new T.BoxGeometry(1.5, 0.12, 0.4), trimMat));
|
||||
dashPanel.position.set(0, 0.6, -0.85);
|
||||
const dials = add(new T.Mesh(
|
||||
new T.BoxGeometry(0.7, 0.02, 0.06),
|
||||
new T.MeshStandardMaterial({
|
||||
color: new T.Color(0.02, 0.03, 0.04),
|
||||
emissive: new T.Color(0.5, 0.7, 0.85),
|
||||
emissiveIntensity: 0.8,
|
||||
roughness: 0.5,
|
||||
})));
|
||||
dials.position.set(0, 0.665, -0.85);
|
||||
// Center console between the seats with a shifter-line glow.
|
||||
const console_ = add(new T.Mesh(new T.BoxGeometry(0.16, 0.16, 1.1), trimMat));
|
||||
console_.position.set(0, 0.64, 0.15);
|
||||
const consoleGlow = add(new T.Mesh(
|
||||
new T.BoxGeometry(0.05, 0.02, 0.8),
|
||||
new T.MeshStandardMaterial({
|
||||
color: new T.Color(0.02, 0.03, 0.04),
|
||||
emissive: new T.Color(0.5, 0.7, 0.85),
|
||||
emissiveIntensity: 0.6,
|
||||
roughness: 0.5,
|
||||
})));
|
||||
consoleGlow.position.set(0, 0.725, 0.15);
|
||||
// Steering wheel ahead of the front-left seat.
|
||||
const column = add(new T.Mesh(new T.BoxGeometry(0.05, 0.05, 0.3), trimMat));
|
||||
column.position.set(-0.33, 0.7, -0.42);
|
||||
column.rotation.x = 0.2;
|
||||
const wheel = add(new T.Mesh(new T.TorusGeometry(0.11, 0.025, 8, 18), trimMat));
|
||||
wheel.position.set(-0.33, 0.76, -0.55);
|
||||
wheel.rotation.x = -0.5;
|
||||
}
|
||||
|
||||
// Wheels: four dark torus + hub, spin with speed (see below).
|
||||
@@ -717,6 +763,33 @@ export const ride = {
|
||||
bodyParts = body.children.slice();
|
||||
} catch { bodyParts = null; }
|
||||
const count = vs && vs.population ? Math.max(2, Math.min(4, vs.population.count | 0)) : 2;
|
||||
// Two rows of two, like a real car: a 2-rider track gets a
|
||||
// 2-seater, anything more a 4-seater (3 riders leave one seat
|
||||
// empty, which is natural). Riders take seats in order, driver
|
||||
// front-left where the wheel is.
|
||||
const SEATS = count > 2
|
||||
? [{ x: -0.33, z: -0.15 }, { x: 0.33, z: -0.15 },
|
||||
{ x: -0.33, z: 0.45 }, { x: 0.33, z: 0.45 }]
|
||||
: [{ x: -0.33, z: -0.15 }, { x: 0.33, z: -0.15 }];
|
||||
const leatherMat = new T.MeshStandardMaterial({
|
||||
color: new T.Color(0.06, 0.06, 0.07), roughness: 0.8, metalness: 0.05,
|
||||
transparent: opacity < 0.999, opacity,
|
||||
});
|
||||
for (const seat of SEATS) {
|
||||
const cushion = new T.Mesh(new T.BoxGeometry(0.42, 0.12, 0.42), leatherMat);
|
||||
cushion.position.set(seat.x, 0.62, seat.z);
|
||||
instance.car.add(cushion);
|
||||
instance.bodyMeshes.push(cushion);
|
||||
const back = new T.Mesh(new T.BoxGeometry(0.4, 0.5, 0.12), leatherMat);
|
||||
back.position.set(seat.x, 0.85, seat.z + 0.24);
|
||||
back.rotation.x = -0.12;
|
||||
instance.car.add(back);
|
||||
instance.bodyMeshes.push(back);
|
||||
const headrest = new T.Mesh(new T.BoxGeometry(0.2, 0.14, 0.1), leatherMat);
|
||||
headrest.position.set(seat.x, 1.12, seat.z + 0.28);
|
||||
instance.car.add(headrest);
|
||||
instance.bodyMeshes.push(headrest);
|
||||
}
|
||||
for (let i = 0; i < count; i++) {
|
||||
let m;
|
||||
if (bodyParts && bodyParts.length) {
|
||||
@@ -742,10 +815,14 @@ export const ride = {
|
||||
}
|
||||
const g = new T.Group();
|
||||
g.add(m);
|
||||
// Seat row: spread across the cabin width, heads above the glass.
|
||||
const fx = (i - (count - 1) / 2) * 0.62 + (rng() - 0.5) * 0.1;
|
||||
// Seated in order: butt on the cushion, back against the
|
||||
// backrest. Same rng cadence as the old scatter row (four
|
||||
// draws per rider, same order) so downstream draws don't move.
|
||||
const seat = SEATS[i];
|
||||
const jx = (rng() - 0.5) * 0.08;
|
||||
const jz = (rng() - 0.5) * 0.06;
|
||||
g.scale.setScalar(0.5);
|
||||
g.position.set(fx, 0.78, -0.25 + (rng() - 0.5) * 0.3);
|
||||
g.position.set(seat.x + jx, 0.78, seat.z + jz);
|
||||
g.rotation.y = Math.PI + (rng() - 0.5) * 0.5;
|
||||
g.userData.baseY = g.position.y;
|
||||
g.userData.index = i;
|
||||
|
||||
Reference in New Issue
Block a user