globe-future / index.html
docto41's picture
Add 2 files
93de478 verified
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simulateur de Camion - Vues Extérieures</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
font-family: 'Arial', sans-serif;
}
#container {
position: relative;
width: 100vw;
height: 100vh;
}
#ui {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 100;
}
.dashboard {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.7);
border-radius: 15px;
padding: 15px;
display: flex;
gap: 30px;
backdrop-filter: blur(5px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.gauge {
display: flex;
flex-direction: column;
align-items: center;
color: white;
}
.gauge-value {
font-size: 1.5rem;
font-weight: bold;
margin-top: 5px;
color: #4ade80;
}
.gauge-label {
font-size: 0.8rem;
opacity: 0.8;
}
.steering-wheel {
position: absolute;
bottom: 120px;
left: 50%;
transform: translateX(-50%);
width: 120px;
height: 120px;
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle cx="50" cy="50" r="45" fill="none" stroke="white" stroke-width="5"/><circle cx="50" cy="50" r="15" fill="none" stroke="white" stroke-width="5"/><path d="M50,5 L50,25 M50,75 L50,95 M5,50 L25,50 M75,50 L95,50" stroke="white" stroke-width="5"/></svg>') no-repeat center;
background-size: contain;
pointer-events: none;
}
.gear-indicator {
position: absolute;
bottom: 100px;
right: 30px;
background: rgba(0, 0, 0, 0.7);
color: white;
padding: 10px 15px;
border-radius: 8px;
font-size: 1.2rem;
font-weight: bold;
backdrop-filter: blur(5px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.menu {
position: absolute;
top: 20px;
left: 20px;
background: rgba(0, 0, 0, 0.7);
border-radius: 10px;
padding: 10px;
backdrop-filter: blur(5px);
border: 1px solid rgba(255, 255, 255, 0.2);
pointer-events: all;
}
.menu-button {
background: rgba(255, 255, 255, 0.1);
color: white;
border: none;
padding: 8px 15px;
border-radius: 5px;
margin: 5px;
cursor: pointer;
transition: all 0.2s;
}
.menu-button:hover {
background: rgba(255, 255, 255, 0.3);
}
.view-buttons {
position: absolute;
top: 20px;
right: 20px;
background: rgba(0, 0, 0, 0.7);
border-radius: 10px;
padding: 10px;
backdrop-filter: blur(5px);
border: 1px solid rgba(255, 255, 255, 0.2);
pointer-events: all;
}
.loading-screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #111;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
z-index: 1000;
}
.progress-bar {
width: 300px;
height: 10px;
background: rgba(255, 255, 255, 0.2);
border-radius: 5px;
margin-top: 20px;
overflow: hidden;
}
.progress {
height: 100%;
background: #3b82f6;
width: 0%;
transition: width 0.3s;
}
</style>
</head>
<body>
<div id="container">
<div id="ui">
<div class="dashboard">
<div class="gauge">
<div class="gauge-label">VITESSE</div>
<div id="speed" class="gauge-value">0 km/h</div>
</div>
<div class="gauge">
<div class="gauge-label">RPM</div>
<div id="rpm" class="gauge-value">0</div>
</div>
<div class="gauge">
<div class="gauge-label">RÉSERVOIR</div>
<div id="fuel" class="gauge-value">100%</div>
</div>
<div class="gauge">
<div class="gauge-label">TEMPS</div>
<div id="time" class="gauge-value">00:00</div>
</div>
<div class="gauge">
<div class="gauge-label">DISTANCE</div>
<div id="distance" class="gauge-value">0 km</div>
</div>
</div>
<div class="steering-wheel" id="steering-wheel"></div>
<div class="gear-indicator" id="gear-indicator">N</div>
<div class="menu">
<button class="menu-button" id="toggle-camera">VUE INTÉRIEURE</button>
<button class="menu-button" id="toggle-lights">PHARES</button>
<button class="menu-button" id="reset-truck">RÉINITIALISER</button>
</div>
<div class="view-buttons">
<button class="menu-button" id="view-behind">VUE ARRIÈRE</button>
<button class="menu-button" id="view-side">VUE LATÉRALE</button>
<button class="menu-button" id="view-top">VUE AÉRIENNE</button>
<button class="menu-button" id="view-free">CAMÉRA LIBRE</button>
</div>
</div>
<div class="loading-screen" id="loading-screen">
<h1 class="text-2xl font-bold mb-4">SIMULATEUR DE CAMION - PAYSAGES</h1>
<p class="mb-2">Chargement des ressources...</p>
<div class="progress-bar">
<div class="progress" id="progress-bar"></div>
</div>
<p class="mt-4 text-sm" id="loading-text">Initialisation du système...</p>
</div>
</div>
<script>
// Variables globales
let scene, camera, renderer, truck, controls;
let speed = 0, rpm = 1000, fuel = 100, time = 0, distance = 0;
let steeringAngle = 0, gear = 'N';
let lightsOn = false, hornPlaying = false;
let cameraMode = 'interior';
let currentView = 'free'; // free, behind, side, top
let lastTime = 0;
let loadingProgress = 0;
let assetsLoaded = false;
let clock = new THREE.Clock();
// Initialisation
function init() {
// Création de la scène
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2(0xcccccc, 0.002);
// Création de la caméra
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 10000);
camera.position.set(0, 5, -10);
camera.lookAt(0, 2, 10);
// Création du rendu
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 0.8;
document.getElementById('container').appendChild(renderer.domElement);
// Contrôles de la caméra
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = true;
controls.enablePan = false;
controls.maxPolarAngle = Math.PI * 0.5;
controls.minDistance = 5;
controls.maxDistance = 50;
// Configuration des lumières
setupLights();
// Création de l'environnement
createEnvironment();
// Création du camion
createTruck();
// Configuration des événements
setupEventListeners();
// Animation
animate();
}
// Chargement des assets
function loadAssets() {
const loadingStages = [
"Initialisation du système...",
"Chargement des textures...",
"Création de l'environnement...",
"Finalisation..."
];
let currentStage = 0;
document.getElementById('loading-text').textContent = loadingStages[currentStage];
const loadingInterval = setInterval(() => {
loadingProgress += Math.random() * 3;
if (loadingProgress > (currentStage + 1) * 20) {
currentStage++;
if (currentStage < loadingStages.length) {
document.getElementById('loading-text').textContent = loadingStages[currentStage];
}
}
if (loadingProgress > 100) loadingProgress = 100;
document.getElementById('progress-bar').style.width = loadingProgress + '%';
if (loadingProgress >= 100) {
clearInterval(loadingInterval);
setTimeout(() => {
document.getElementById('loading-screen').style.display = 'none';
assetsLoaded = true;
}, 500);
}
}, 100);
}
// Configuration des lumières
function setupLights() {
// Lumière directionnelle principale
const sunlight = new THREE.DirectionalLight(0xffffff, 1);
sunlight.position.set(100, 100, 50);
sunlight.castShadow = true;
sunlight.shadow.mapSize.width = 2048;
sunlight.shadow.mapSize.height = 2048;
sunlight.shadow.camera.near = 0.5;
sunlight.shadow.camera.far = 500;
sunlight.shadow.camera.left = -100;
sunlight.shadow.camera.right = 100;
sunlight.shadow.camera.top = 100;
sunlight.shadow.camera.bottom = -100;
scene.add(sunlight);
// Lumière ambiante
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
// Phares du camion
const headlight1 = new THREE.SpotLight(0xffffff, 1, 100, Math.PI/4, 0.5);
headlight1.position.set(1, 2, 3);
headlight1.castShadow = true;
headlight1.visible = false;
scene.add(headlight1);
const headlight2 = new THREE.SpotLight(0xffffff, 1, 100, Math.PI/4, 0.5);
headlight2.position.set(-1, 2, 3);
headlight2.castShadow = true;
headlight2.visible = false;
scene.add(headlight2);
}
// Création de l'environnement amélioré
function createEnvironment() {
// Sol avec texture haute résolution
const groundGeometry = new THREE.PlaneGeometry(10000, 10000);
const groundMaterial = new THREE.MeshStandardMaterial({
color: 0x3a5f0b,
roughness: 0.8,
metalness: 0.2
});
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = -Math.PI / 2;
ground.receiveShadow = true;
scene.add(ground);
// Route principale avec marquages détaillés
const roadGeometry = new THREE.PlaneGeometry(20, 10000);
const roadMaterial = new THREE.MeshStandardMaterial({
color: 0x333333,
roughness: 0.7,
metalness: 0.1
});
const road = new THREE.Mesh(roadGeometry, roadMaterial);
road.rotation.x = -Math.PI / 2;
road.position.y = 0.01;
road.receiveShadow = true;
scene.add(road);
// Lignes de la route avec réflexion
const lineGeometry = new THREE.PlaneGeometry(0.5, 5);
const lineMaterial = new THREE.MeshStandardMaterial({
color: 0xffff00,
emissive: 0x333300,
emissiveIntensity: 0.5,
roughness: 0.1,
metalness: 0.8
});
for (let i = -5000; i < 5000; i += 15) {
const line = new THREE.Mesh(lineGeometry, lineMaterial);
line.rotation.x = -Math.PI / 2;
line.position.set(0, 0.02, i);
scene.add(line);
}
// Paysage naturel détaillé
createNaturalFeatures();
}
// Création des éléments naturels améliorés
function createNaturalFeatures() {
// Arbres variés
const treeTypes = [
{ height: 5, trunkColor: 0x8b4513, leavesColor: 0x3a5f0b },
{ height: 8, trunkColor: 0x654321, leavesColor: 0x2a4b0d },
{ height: 12, trunkColor: 0x5e2605, leavesColor: 0x1e3b0a }
];
for (let i = 0; i < 500; i++) {
const type = treeTypes[Math.floor(Math.random() * treeTypes.length)];
const x = (Math.random() > 0.5 ? 1 : -1) * (30 + Math.random() * 500);
const z = -2000 + Math.random() * 4000;
const tree = new THREE.Group();
// Tronc
const trunkGeometry = new THREE.CylinderGeometry(0.3, 0.5, type.height * 0.3, 8);
const trunkMaterial = new THREE.MeshStandardMaterial({ color: type.trunkColor });
const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
trunk.position.y = type.height * 0.15;
trunk.castShadow = true;
tree.add(trunk);
// Feuillage
const leavesGeometry = new THREE.SphereGeometry(type.height * 0.4, 16, 16);
const leavesMaterial = new THREE.MeshStandardMaterial({
color: type.leavesColor,
transparent: true,
opacity: 0.9
});
const leaves = new THREE.Mesh(leavesGeometry, leavesMaterial);
leaves.position.y = type.height * 0.3;
leaves.castShadow = true;
tree.add(leaves);
// Position aléatoire
tree.position.set(x, 0, z);
tree.rotation.y = Math.random() * Math.PI;
scene.add(tree);
}
// Montagnes réalistes
const mountainGeometry = new THREE.ConeGeometry(300, 500, 64);
const mountainMaterial = new THREE.MeshStandardMaterial({
color: 0x777777,
roughness: 0.9,
metalness: 0.1
});
for (let i = 0; i < 8; i++) {
const x = (Math.random() > 0.5 ? 1 : -1) * (1000 + Math.random() * 2000);
const z = -4000 + Math.random() * 8000;
const mountain = new THREE.Mesh(mountainGeometry, mountainMaterial);
mountain.position.set(x, -100, z);
mountain.rotation.y = Math.random() * Math.PI;
// Détails supplémentaires
const snowGeometry = new THREE.ConeGeometry(250, 100, 64);
const snowMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });
const snow = new THREE.Mesh(snowGeometry, snowMaterial);
snow.position.y = 200;
mountain.add(snow);
scene.add(mountain);
}
}
// Création du camion
function createTruck() {
// Groupe principal du camion
truck = new THREE.Group();
// Cabine
const cabinGeometry = new THREE.BoxGeometry(3, 2.5, 3);
const cabinMaterial = new THREE.MeshStandardMaterial({
color: 0x2a75bb,
roughness: 0.5,
metalness: 0.5
});
const cabin = new THREE.Mesh(cabinGeometry, cabinMaterial);
cabin.position.set(0, 2, 0);
cabin.castShadow = true;
cabin.receiveShadow = true;
truck.add(cabin);
// Pare-brise
const windshieldGeometry = new THREE.BoxGeometry(2.8, 1.5, 0.1);
const windshieldMaterial = new THREE.MeshStandardMaterial({
color: 0x7ec0ee,
transparent: true,
opacity: 0.7,
roughness: 0.1,
metalness: 0.9
});
const windshield = new THREE.Mesh(windshieldGeometry, windshieldMaterial);
windshield.position.set(0, 2.5, 1.5);
truck.add(windshield);
// Châssis
const chassisGeometry = new THREE.BoxGeometry(4, 1, 8);
const chassisMaterial = new THREE.MeshStandardMaterial({
color: 0x1a1a1a,
roughness: 0.7,
metalness: 0.3
});
const chassis = new THREE.Mesh(chassisGeometry, chassisMaterial);
chassis.position.set(0, 1, -2);
chassis.castShadow = true;
chassis.receiveShadow = true;
truck.add(chassis);
// Roues
const wheelGeometry = new THREE.CylinderGeometry(0.5, 0.5, 0.4, 32);
const wheelMaterial = new THREE.MeshStandardMaterial({
color: 0x333333,
roughness: 0.8,
metalness: 0.2
});
const wheelTireGeometry = new THREE.TorusGeometry(0.5, 0.2, 16, 32);
const wheelTireMaterial = new THREE.MeshStandardMaterial({ color: 0x111111 });
// Roues avant
const wheelFL = new THREE.Group();
const wheelFLBase = new THREE.Mesh(wheelGeometry, wheelMaterial);
wheelFLBase.rotation.z = Math.PI / 2;
wheelFL.add(wheelFLBase);
const wheelFLTire = new THREE.Mesh(wheelTireGeometry, wheelTireMaterial);
wheelFLTire.rotation.x = Math.PI / 2;
wheelFL.add(wheelFLTire);
wheelFL.position.set(1.5, 1, 2);
truck.add(wheelFL);
const wheelFR = new THREE.Group();
const wheelFRBase = new THREE.Mesh(wheelGeometry, wheelMaterial);
wheelFRBase.rotation.z = Math.PI / 2;
wheelFR.add(wheelFRBase);
const wheelFRTire = new THREE.Mesh(wheelTireGeometry, wheelTireMaterial);
wheelFRTire.rotation.x = Math.PI / 2;
wheelFR.add(wheelFRTire);
wheelFR.position.set(-1.5, 1, 2);
truck.add(wheelFR);
// Roues arrière (double essieu)
for (let i = 0; i < 2; i++) {
const wheelRL = new THREE.Group();
const wheelRLBase = new THREE.Mesh(wheelGeometry, wheelMaterial);
wheelRLBase.rotation.z = Math.PI / 2;
wheelRL.add(wheelRLBase);
const wheelRLTire = new THREE.Mesh(wheelTireGeometry, wheelTireMaterial);
wheelRLTire.rotation.x = Math.PI / 2;
wheelRL.add(wheelRLTire);
wheelRL.position.set(1.5, 1, -4 + i * 0.8);
truck.add(wheelRL);
const wheelRR = new THREE.Group();
const wheelRRBase = new THREE.Mesh(wheelGeometry, wheelMaterial);
wheelRRBase.rotation.z = Math.PI / 2;
wheelRR.add(wheelRRBase);
const wheelRRTire = new THREE.Mesh(wheelTireGeometry, wheelTireMaterial);
wheelRRTire.rotation.x = Math.PI / 2;
wheelRR.add(wheelRRTire);
wheelRR.position.set(-1.5, 1, -4 + i * 0.8);
truck.add(wheelRR);
}
// Ajout du camion à la scène
scene.add(truck);
truck.position.set(0, 2, 0);
}
// Configuration des événements
function setupEventListeners() {
// Contrôles clavier
const keyStates = {};
document.addEventListener('keydown', (event) => {
keyStates[event.key.toLowerCase()] = true;
// Klaxon
if (event.key.toLowerCase() === 'h' && !hornPlaying) {
hornPlaying = true;
setTimeout(() => { hornPlaying = false; }, 1000);
}
// Phares
if (event.key.toLowerCase() === 'f') {
toggleLights();
}
// Changement de caméra
if (event.key.toLowerCase() === 'c') {
toggleCamera();
}
// Changement de vitesse
if (event.key >= '1' && event.key <= '6') {
gear = event.key;
document.getElementById('gear-indicator').textContent = gear;
}
});
document.addEventListener('keyup', (event) => {
keyStates[event.key.toLowerCase()] = false;
});
// Contrôles UI
document.getElementById('toggle-camera').addEventListener('click', toggleCamera);
document.getElementById('toggle-lights').addEventListener('click', toggleLights);
document.getElementById('reset-truck').addEventListener('click', resetTruck);
// Boutons de vue
document.getElementById('view-behind').addEventListener('click', () => setView('behind'));
document.getElementById('view-side').addEventListener('click', () => setView('side'));
document.getElementById('view-top').addEventListener('click', () => setView('top'));
document.getElementById('view-free').addEventListener('click', () => setView('free'));
// Animation des contrôles
function updateControls(delta) {
// Accélération/freinage
if (keyStates['z'] || keyStates['arrowup']) {
if (speed < getMaxSpeed()) speed += 0.1 * delta * 60;
if (rpm < getMaxRpm()) rpm += 50 * delta * 60;
} else if (keyStates['s'] || keyStates['arrowdown']) {
if (speed > -20) speed -= 0.2 * delta * 60;
if (rpm > 1000) rpm -= 100 * delta * 60;
} else {
// Ralentissement naturel
if (speed > 0) speed = Math.max(0, speed - 0.05 * delta * 60);
if (speed < 0) speed = Math.min(0, speed + 0.05 * delta * 60);
if (rpm > 1000) rpm = Math.max(1000, rpm - 50 * delta * 60);
}
// Direction
if (keyStates['q'] || keyStates['arrowleft']) {
steeringAngle = Math.min(0.5, steeringAngle + 0.02 * delta * 60);
} else if (keyStates['d'] || keyStates['arrowright']) {
steeringAngle = Math.max(-0.5, steeringAngle - 0.02 * delta * 60);
} else {
// Retour au centre
if (steeringAngle > 0) steeringAngle = Math.max(0, steeringAngle - 0.01 * delta * 60);
if (steeringAngle < 0) steeringAngle = Math.min(0, steeringAngle + 0.01 * delta * 60);
}
// Frein
if (keyStates[' ']) {
if (speed > 0) speed = Math.max(0, speed - 0.2 * delta * 60);
if (speed < 0) speed = Math.min(0, speed + 0.2 * delta * 60);
if (rpm > 1000) rpm = Math.max(1000, rpm - 100 * delta * 60);
}
// Rétrograder
if (keyStates['r'] && speed < 5) {
gear = gear === 'R' ? '1' : 'R';
document.getElementById('gear-indicator').textContent = gear;
}
// Mise à jour de l'UI
document.getElementById('speed').textContent = Math.abs(Math.round(speed)) + ' km/h';
document.getElementById('rpm').textContent = rpm;
document.getElementById('steering-wheel').style.transform = `translateX(-50%) rotate(${steeringAngle * 60}deg)`;
// Consommation de carburant
if (speed > 0) {
fuel = Math.max(0, fuel - 0.001 * delta * 60);
document.getElementById('fuel').textContent = Math.round(fuel) + '%';
}
// Mise à jour de la distance
distance += speed * delta * 0.01;
document.getElementById('distance').textContent = Math.round(distance) + ' km';
// Mise à jour du temps
time += delta;
const minutes = Math.floor(time / 60);
const seconds = Math.floor(time % 60);
document.getElementById('time').textContent =
(minutes < 10 ? '0' + minutes : minutes) + ':' +
(seconds < 10 ? '0' + seconds : seconds);
}
// Vitesse maximale en fonction de la vitesse
function getMaxSpeed() {
switch(gear) {
case '1': return 30;
case '2': return 50;
case '3': return 80;
case '4': return 110;
case '5': return 140;
case '6': return 180;
case 'R': return 20;
default: return 30;
}
}
// RPM maximal en fonction de la vitesse
function getMaxRpm() {
switch(gear) {
case '1': return 4000;
case '2': return 4500;
case '3': return 5000;
case '4': return 5500;
case '5': return 6000;
case '6': return 6500;
case 'R': return 3000;
default: return 4000;
}
}
// Rafraîchissement des contrôles
let lastUpdateTime = 0;
function updateControlsLoop(timestamp) {
const delta = (timestamp - lastUpdateTime) / 1000;
lastUpdateTime = timestamp;
if (delta < 0.1) { // Éviter les gros sauts en cas de perte de focus
updateControls(delta);
}
requestAnimationFrame(updateControlsLoop);
}
requestAnimationFrame(updateControlsLoop);
}
// Basculer les phares
function toggleLights() {
lightsOn = !lightsOn;
scene.children.forEach(child => {
if (child.type === 'SpotLight') {
child.visible = lightsOn;
}
});
document.getElementById('toggle-lights').textContent = lightsOn ? 'ÉTEINDRE' : 'PHARES';
}
// Basculer la caméra
function toggleCamera() {
cameraMode = cameraMode === 'interior' ? 'exterior' : 'interior';
document.getElementById('toggle-camera').textContent =
cameraMode === 'interior' ? 'VUE EXTÉRIEURE' : 'VUE INTÉRIEURE';
}
// Changer la vue
function setView(view) {
currentView = view;
// Mettre à jour l'état des boutons
document.getElementById('view-behind').classList.toggle('bg-blue-500', view === 'behind');
document.getElementById('view-side').classList.toggle('bg-blue-500', view === 'side');
document.getElementById('view-top').classList.toggle('bg-blue-500', view === 'top');
document.getElementById('view-free').classList.toggle('bg-blue-500', view === 'free');
}
// Réinitialiser le camion
function resetTruck() {
truck.position.set(0, 2, 0);
truck.rotation.set(0, 0, 0);
speed = 0;
rpm = 1000;
steeringAngle = 0;
gear = 'N';
distance = 0;
document.getElementById('gear-indicator').textContent = gear;
}
// Animation
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
if (!assetsLoaded) return;
// Déplacement du camion
if (truck) {
truck.position.z += speed * delta;
truck.rotation.y = -steeringAngle * 0.5;
// Rotation des roues
truck.children.forEach(child => {
if (child.type === 'Group') { // Roues
child.children.forEach(wheel => {
if (wheel.geometry?.type === 'CylinderGeometry') {
wheel.rotation.x += speed * delta;
}
});
// Direction des roues avant
if (Math.abs(child.position.z - 2) < 0.1) {
child.rotation.y = steeringAngle * 2;
}
}
});
// Positionnement de la caméra en fonction de la vue
if (cameraMode === 'interior') {
// Vue intérieure
camera.position.set(
truck.position.x + 0.5 * Math.sin(truck.rotation.y),
truck.position.y + 2,
truck.position.z - 5 + 2 * Math.sin(truck.rotation.y)
);
camera.lookAt(
truck.position.x,
truck.position.y + 1,
truck.position.z + 10
);
} else {
// Vue extérieure avec différentes perspectives
switch(currentView) {
case 'behind':
// Vue arrière
camera.position.set(
truck.position.x + 5 * Math.sin(truck.rotation.y),
truck.position.y + 5,
truck.position.z - 15 + 5 * Math.sin(truck.rotation.y)
);
camera.lookAt(truck.position);
break;
case 'side':
// Vue latérale
camera.position.set(
truck.position.x + 15,
truck.position.y + 5,
truck.position.z
);
camera.lookAt(truck.position);
break;
case 'top':
// Vue aérienne
camera.position.set(
truck.position.x,
truck.position.y + 25,
truck.position.z - 10
);
camera.lookAt(truck.position);
break;
case 'free':
default:
// Caméra libre (contrôlée par OrbitControls)
break;
}
}
}
// Mise à jour des contrôles
controls.update();
// Rendu
renderer.render(scene, camera);
}
// Redimensionnement
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// Démarrer l'application
init();
loadAssets();
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=docto41/globe-future" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>