Aggiunta schermata di caricamento e timer per la partita

This commit is contained in:
2026-03-23 09:43:02 +01:00
parent 7ee94cb046
commit 4f2c2ffd19
4 changed files with 123 additions and 16 deletions
+2 -1
View File
@@ -28,7 +28,8 @@
- [✅] **Sistema Ostacoli:** Inserimento di modelli 3D di alberi e oggetti ambientali decorativi. - [✅] **Sistema Ostacoli:** Inserimento di modelli 3D di alberi e oggetti ambientali decorativi.
- [✅] **Meccaniche di Raccolta:** Gestione delle collisioni e incremento del punteggio ecologico. - [✅] **Meccaniche di Raccolta:** Gestione delle collisioni e incremento del punteggio ecologico.
- [✅] **Interfaccia (HUD):** Overlay con Timer (60s), contatore rifiuti e disattivazione della pausa. - [✅] **Interfaccia (HUD):** Overlay con Timer (60s), contatore rifiuti e disattivazione della pausa.
- [] **Oggetti umani:** Inserimento di case o di elementi che fanno pensare all'attivita' umana sull'isola - [⚠️] **Schermata di caricamento:** Schermata di caricamento iniziale
- [⚠️] **Schermata iniziale:** Schermata iniziale
- [❌] **Rifinitura (Polish):** Animazioni di raccolta e ottimizzazione delle mesh 3D. - [❌] **Rifinitura (Polish):** Animazioni di raccolta e ottimizzazione delle mesh 3D.
- [❌] **Timer:** Meccanica del timer per il tempo di raccolta dei rifiuti - [❌] **Timer:** Meccanica del timer per il tempo di raccolta dei rifiuti
- [❌] **Personaggio:** Cilindro che rappresenta il personaggio (fatto per collisioni piu' precise) - [❌] **Personaggio:** Cilindro che rappresenta il personaggio (fatto per collisioni piu' precise)
+12 -1
View File
@@ -6,6 +6,15 @@
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
</head> </head>
<body> <body>
<!-- SCHERMATA DI CARICAMENTO -->
<div id="loading-screen" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: #000; display: flex; flex-direction: column; align-items: center; justify-content: center; z-index: 9999;">
<div style="width: 80%; max-width: 600px; background: #222; height: 20px; border-radius: 10px; overflow: hidden; margin-bottom: 10px;">
<div id="loading-bar" style="width: 0%; height: 100%; background: #4CAF50; transition: width 0.3s;"></div>
</div>
<div id="loading-text" style="color: #fff; font-family: monospace; font-size: 14px;">Loading...</div>
</div>
<!-- SCHERMATA INIZIALE -->
<div id="start"> <div id="start">
<video autoplay muted loop id="bg-video"> <video autoplay muted loop id="bg-video">
<source src="./video/background.mp4" type="video/mp4"> <source src="./video/background.mp4" type="video/mp4">
@@ -30,8 +39,10 @@
</div> </div>
</div> </div>
</div> </div>
<!-- INTERFACCIA GRAFICA DEL GIOCO -->
<div id="punti">Rifiuti: <span id="score">0</span></div> <div id="punti">Rifiuti: <span id="score">0</span></div>
<div id="tempo">Tempo: <span id="time">XX:XX</span></div> <div id="tempo">Tempo: <span id="minuti">XX</span>:<span id="secondi">XX</span></div>
<div id="crosshair">+</div> <div id="crosshair">+</div>
<script type="importmap"> <script type="importmap">
{ {
+95 -14
View File
@@ -2,7 +2,31 @@ import * as THREE from 'three';
import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js'; import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
// 1. SCENA E CAMERA // 1a. INIZIALIZZAZIONE CARICAMENTO ASSETS
const manager = new THREE.LoadingManager();
manager.onStart = function (url, itemsLoaded, itemsTotal) {
document.getElementById("loading-text").innerHTML = `Inizio caricamento: ${url}`;
console.log(`Inizio caricamento: ${url}`);
};
manager.onLoad = function () {
document.getElementById('loading-screen').style.display = 'none';
animate(); // avvia il rendering
};
manager.onProgress = function (url, itemsLoaded, itemsTotal) {
// Calcola la percentuale
const percent = (itemsLoaded / itemsTotal) * 100;
document.getElementById('loading-bar').style.width = percent + '%';
// Aggiorna il testo
document.getElementById("loading-text").innerHTML = `Caricamento: ${itemsLoaded} di ${itemsTotal} - ${url}`;
console.log(`Caricamento: ${itemsLoaded} di ${itemsTotal} - ${url}`);
};
manager.onError = function (url) {
document.getElementById("loading-text").innerHTML = `Errore nel caricamento: ${url}`;
console.log(`Errore nel caricamento: ${url}`);
};
// 1b. SCENA E CAMERA
const scene = new THREE.Scene(); const scene = new THREE.Scene();
scene.background = new THREE.Color(0x33ccff); // Cielo più azzurro scene.background = new THREE.Color(0x33ccff); // Cielo più azzurro
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
@@ -14,7 +38,7 @@ window.addEventListener('resize', function () {
}) })
// AGGIUNTA MARE // AGGIUNTA MARE
const oceanGeometry = new THREE.PlaneGeometry(2000, 2000); const oceanGeometry = new THREE.PlaneGeometry(2000, 2000);
const oceanMaterial = new THREE.MeshStandardMaterial({ const oceanMaterial = new THREE.MeshStandardMaterial({
color: 0x0077be, color: 0x0077be,
transparent: true, transparent: true,
opacity: 0.8 opacity: 0.8
@@ -51,7 +75,7 @@ const grass = new THREE.Mesh(grassGeo, grassMat);
grass.rotation.x = -Math.PI / 2; grass.rotation.x = -Math.PI / 2;
// Posizioniamo il prato all'altezza desiderata // Posizioniamo il prato all'altezza desiderata
grass.position.y = altezzaIsola; grass.position.y = altezzaIsola;
islandGroup.add(grass); islandGroup.add(grass);
// --- LA SABBIA (Cilindro Svasato) --- // --- LA SABBIA (Cilindro Svasato) ---
@@ -69,6 +93,58 @@ scene.add(islandGroup);
scene.fog = new THREE.Fog(0x33ccff, 20, 100); scene.fog = new THREE.Fog(0x33ccff, 20, 100);
// 3. CONTROLLI // 3. CONTROLLI
window.totalTime;
class PausableTimer {
constructor(callback, delay) {
this.callback = callback;
this.delay = delay; // salvi il delay originale
this.remaining = delay;
this.timerId = null;
this.start = null;
this.loop = null;
this.cont = 0;
window.totalTime = delay / 1000;
}
pause() {
if (this.timerId) {
clearTimeout(this.timerId);
this.timerId = null;
// Calcola il tempo passato
this.remaining -= Date.now() - this.start;
}
if (this.loop) {
clearInterval(this.loop);
this.loop = null;
}
console.log("pausa");
}
resume() {
console.log("resume");
if (this.timerId) return; // già in esecuzione
if (this.remaining > 0) {
this.start = Date.now();
this.timerId = setTimeout(() => {
this.pause();
this.callback();
}, this.remaining);
// Se il ciclo di aggiornamento non è già attivo, avvialo
if (!this.loop) {
this.loop = setInterval(() => {
this.cont++;
// Aggiorna il timer visualizzato
document.getElementById("minuti").innerHTML = String(Math.floor((window.totalTime - this.cont) / 60)).padStart(2, '0');
document.getElementById("secondi").innerHTML = String((window.totalTime - this.cont) % 60).padStart(2, '0');
console.log(`${document.getElementById("minuti").innerHTML}:${document.getElementById("secondi").innerHTML}`);
}, 1000);
}
}
}
}
const timer = new PausableTimer(() => {
localStorage.setItem("punteggio", document.getElementById("score").innerHTML.trim());
window.location = "test.html";
}, 60000)
function lock() { function lock() {
document.getElementById('start').style.display = 'none'; document.getElementById('start').style.display = 'none';
document.getElementById('punti').style.display = 'block'; document.getElementById('punti').style.display = 'block';
@@ -76,22 +152,27 @@ function lock() {
document.getElementById('crosshair').style.display = 'block'; document.getElementById('crosshair').style.display = 'block';
} }
function unlock() { function unlock() {
const startDiv = document.getElementById('start'); timer.pause();
startDiv.style.display = 'flex'; // Forza il layout Flexbox document.getElementById('start').style.display = 'flex';
// Nascondi l'HUD
document.getElementById('punti').style.display = 'none'; document.getElementById('punti').style.display = 'none';
document.getElementById('tempo').style.display = 'none'; document.getElementById('tempo').style.display = 'none';
document.getElementById('crosshair').style.display = 'none'; document.getElementById('crosshair').style.display = 'none';
} }
const controls = new PointerLockControls(camera, document.body); const controls = new PointerLockControls(camera, document.body);
document.getElementById('start').addEventListener('click', () => controls.lock()); document.getElementById('start').addEventListener('click', () => {
controls.addEventListener('lock', lock); controls.lock();
controls.addEventListener('unlock', unlock); lock();
});
controls.addEventListener('lock', () => {
lock();
timer.resume();
});
controls.addEventListener('unlock', () => { unlock(); });
// 4. GESTIONE OGGETTI DI SCENA (20 rifiuti + 6 alberi) // 4. GESTIONE OGGETTI DI SCENA (20 rifiuti + 6 alberi)
const trashArray = []; const trashArray = [];
let score = 0; let score = 0;
const loader = new GLTFLoader(); const loader = new GLTFLoader(manager);
loader.load('models/rifiuto.glb', (gltf) => { loader.load('models/rifiuto.glb', (gltf) => {
const mesh = gltf.scene.getObjectByName("Trash_Pile_03_GEO"); const mesh = gltf.scene.getObjectByName("Trash_Pile_03_GEO");
@@ -193,7 +274,7 @@ function animate() {
const intersects = raycaster.intersectObjects([grass, sand]); const intersects = raycaster.intersectObjects([grass, sand]);
if (intersects.length > 0) { if (intersects.length > 0) {
// Logica del "Punto più alto": // Logica del "Punto più alto":
// Se il raggio colpisce sia prato che sabbia, prendiamo il prato. // Se il raggio colpisce sia prato che sabbia, prendiamo il prato.
let highestPoint = -Infinity; let highestPoint = -Infinity;
for (let i = 0; i < intersects.length; i++) { for (let i = 0; i < intersects.length; i++) {
@@ -206,7 +287,7 @@ function animate() {
camera.position.y = highestPoint + altezzaOcchi; camera.position.y = highestPoint + altezzaOcchi;
// --- CONTROLLO BARRIERA ACQUA --- // --- CONTROLLO BARRIERA ACQUA ---
// Se il punto più alto è sotto il livello del mare (0) // Se il punto più alto è sotto il livello del mare (0)
// e non possiamo uscire, blocchiamo il movimento // e non possiamo uscire, blocchiamo il movimento
if (!canLeaveIsland && highestPoint < 0) { if (!canLeaveIsland && highestPoint < 0) {
camera.position.x = oldPos.x; camera.position.x = oldPos.x;
@@ -238,5 +319,5 @@ function animate() {
renderer.render(scene, camera); renderer.render(scene, camera);
} }
document.getElementById("minuti").innerHTML = String(Math.floor(window.totalTime / 60)).padStart(2, '0');
animate(); document.getElementById("secondi").innerHTML = String(window.totalTime % 60).padStart(2, '0');
+14
View File
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test Punti</title>
</head>
<body>
<p>Punti: <span id="punti">0</span></p>
<script>
document.getElementById("punti").innerHTML = localStorage.getItem("punteggio");
</script>
</body>
</html>