import * as THREE from 'three'; function flatMat(color, opts = {}) { return new THREE.MeshLambertMaterial({ color, flatShading: true, ...opts }); } export class Aircraft { constructor() { this.group = new THREE.Group(); this.propeller = null; this.landingGear = []; this.gearExtended = true; this.build(); } build() { const bodyMat = flatMat(0x6688AA); const whiteMat = flatMat(0xFFFFFF); const redMat = flatMat(0xCC0000); const cockpitMat = flatMat(0x333333, { transparent: true, opacity: 0.6 }); const darkMat = flatMat(0x333333); const metalMat = flatMat(0x888888); // Fuselage const fuselage = new THREE.Mesh( new THREE.CylinderGeometry(0.6, 0.45, 9, 6), bodyMat ); fuselage.rotation.x = Math.PI / 2; this.group.add(fuselage); // Nose cone const nose = new THREE.Mesh( new THREE.SphereGeometry(0.4, 6, 4, 0, Math.PI * 2, 0, Math.PI / 2), bodyMat ); nose.rotation.x = -Math.PI / 2; nose.position.z = -4.5; this.group.add(nose); // Tail cone const tailCone = new THREE.Mesh( new THREE.CylinderGeometry(0.4, 0.15, 2.5, 6), bodyMat ); tailCone.rotation.x = Math.PI / 2; tailCone.position.z = 5.5; this.group.add(tailCone); // Cockpit canopy const canopy = new THREE.Mesh( new THREE.SphereGeometry(0.55, 6, 4, 0, Math.PI * 2, 0, Math.PI / 2), cockpitMat ); canopy.position.set(0, 0.4, -1); this.group.add(canopy); // Wings const wings = new THREE.Mesh( new THREE.BoxGeometry(14, 0.2, 2), bodyMat ); wings.position.z = -0.5; this.group.add(wings); // Wingtips (red) const leftTip = new THREE.Mesh(new THREE.BoxGeometry(0.8, 0.25, 1.6), redMat); leftTip.position.set(-6.9, 0, -0.5); this.group.add(leftTip); const rightTip = leftTip.clone(); rightTip.position.x = 6.9; this.group.add(rightTip); // Ailerons (white strips on wing trailing edge) const leftAileron = new THREE.Mesh(new THREE.BoxGeometry(2, 0.15, 0.4), whiteMat); leftAileron.position.set(-5, -0.15, 0.3); this.group.add(leftAileron); const rightAileron = leftAileron.clone(); rightAileron.position.x = 5; this.group.add(rightAileron); // Vertical stabilizer const vStab = new THREE.Mesh( new THREE.BoxGeometry(0.15, 2.5, 1.5), bodyMat ); vStab.position.set(0, 1.2, 5.5); this.group.add(vStab); // Rudder (white) const rudder = new THREE.Mesh( new THREE.BoxGeometry(0.12, 1.8, 0.5), whiteMat ); rudder.position.set(0, 1.2, 6.3); this.group.add(rudder); // Red tail band const tailBand = new THREE.Mesh( new THREE.BoxGeometry(0.12, 0.6, 1.2), redMat ); tailBand.position.set(0, 1.8, 5.5); this.group.add(tailBand); // Horizontal stabilizer const hStab = new THREE.Mesh( new THREE.BoxGeometry(5, 0.15, 1.2), bodyMat ); hStab.position.set(0, 0.1, 5.5); this.group.add(hStab); // Elevators (white) const leftElev = new THREE.Mesh(new THREE.BoxGeometry(1.8, 0.12, 0.4), whiteMat); leftElev.position.set(-2.5, -0.05, 6); this.group.add(leftElev); const rightElev = leftElev.clone(); rightElev.position.x = 2.5; this.group.add(rightElev); // Engine cowling const cowling = new THREE.Mesh( new THREE.CylinderGeometry(0.45, 0.55, 1.5, 6), darkMat ); cowling.rotation.x = Math.PI / 2; cowling.position.z = -5; this.group.add(cowling); // Propeller this.propeller = new THREE.Group(); const blade1 = new THREE.Mesh( new THREE.BoxGeometry(0.12, 3, 0.08), metalMat ); this.propeller.add(blade1); const blade2 = new THREE.Mesh( new THREE.BoxGeometry(3, 0.12, 0.08), metalMat ); this.propeller.add(blade2); // Hub const hub = new THREE.Mesh( new THREE.SphereGeometry(0.15, 4, 4), metalMat ); this.propeller.add(hub); this.propeller.position.z = -5.8; this.group.add(this.propeller); // Landing gear const gearMat = flatMat(0x222222); const wheelMat = flatMat(0x111111); // Nose gear const noseGearStrut = new THREE.Mesh( new THREE.CylinderGeometry(0.06, 0.06, 2, 4), gearMat ); noseGearStrut.position.set(0, -1.5, -3.5); this.group.add(noseGearStrut); const noseWheel = new THREE.Mesh( new THREE.SphereGeometry(0.2, 4, 4), wheelMat ); noseWheel.position.set(0, -2.5, -3.5); this.group.add(noseWheel); this.landingGear.push(noseGearStrut, noseWheel); // Left main gear const leftGearStrut = new THREE.Mesh( new THREE.CylinderGeometry(0.06, 0.06, 2, 4), gearMat ); leftGearStrut.position.set(-2, -1.5, -1); this.group.add(leftGearStrut); const leftWheel = new THREE.Mesh( new THREE.SphereGeometry(0.25, 4, 4), wheelMat ); leftWheel.position.set(-2, -2.5, -1); this.group.add(leftWheel); this.landingGear.push(leftGearStrut, leftWheel); // Right main gear const rightGearStrut = leftGearStrut.clone(); rightGearStrut.position.x = 2; this.group.add(rightGearStrut); const rightWheel = leftWheel.clone(); rightWheel.position.x = 2; this.group.add(rightWheel); this.landingGear.push(rightGearStrut, rightWheel); this.group.rotation.order = 'YXZ'; } updatePropeller(thrust, delta) { if (this.propeller) { this.propeller.rotation.z += thrust * delta * 60; } } retractGear(onGround) { if (onGround && !this.gearExtended) { this.landingGear.forEach(part => { part.visible = true; }); } else if (!onGround && this.gearExtended) { this.landingGear.forEach(part => { part.visible = false; }); } this.gearExtended = onGround; } getGroup() { return this.group; } }