diff --git a/assets/media/img/sfondo_finale.png b/assets/media/img/sfondo_finale.png new file mode 100644 index 0000000..1bed999 Binary files /dev/null and b/assets/media/img/sfondo_finale.png differ diff --git a/assets/media/img/sfondo_iniziale.png b/assets/media/img/sfondo_iniziale.png new file mode 100644 index 0000000..a07a2a4 Binary files /dev/null and b/assets/media/img/sfondo_iniziale.png differ diff --git a/css/classifica.css b/css/classifica.css index 54275f3..2b5204d 100644 --- a/css/classifica.css +++ b/css/classifica.css @@ -1,19 +1,148 @@ +/* --- VARIABILI COLORI --- */ +:root { + --bg-light: #f8fafc; + --text-dark: #1e293b; + --green-eco: #10b981; + --green-dark: #065f46; + --gold: #f1c40f; + --silver: #95a5a6; + --bronze: #cd7f32; + --white: #ffffff; +} + +/* --- RESET E BASE --- */ body { - font-family: "Arial"; -} -table, h1 { - margin: auto; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; + background-color: var(--bg-light); + margin: 0; + padding: 40px 20px; + color: var(--text-dark); + line-height: 1.5; } + h1 { text-align: center; - padding: 15px; + color: var(--text-dark); + font-size: 2.5rem; + text-transform: uppercase; + letter-spacing: 2px; + margin-bottom: 30px; } -table { - width: 75vw; + +/* --- BOTTONI ORDINAMENTO --- */ +.sorting-buttons { text-align: center; - border-collapse: collapse; + margin-bottom: 30px; } + +.sort-button { + display: inline-block; + padding: 12px 25px; + margin: 0 10px; + background-color: var(--white); + color: var(--green-eco); + text-decoration: none; + border-radius: 12px; + border: 2px solid var(--green-eco); + font-weight: 600; + transition: all 0.3s ease; +} + +.sort-button:hover { + background-color: var(--green-eco); + color: var(--white); + transform: translateY(-2px); +} + +.sort-button.active { + background-color: var(--green-eco); + color: var(--white); + box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3); +} + +/* --- TABELLA --- */ +table { + width: 100%; + max-width: 1100px; + margin: 0 auto; + border-collapse: separate; + border-spacing: 0; + background-color: var(--white); + border-radius: 20px; + overflow: hidden; + box-shadow: 0 10px 30px rgba(0,0,0,0.05); +} + th, td { - padding: 10px; - border: 1px solid black; + padding: 18px; + text-align: center; + border-bottom: 1px solid #edf2f7; +} + +th { + background-color: var(--green-eco); + color: var(--white); + font-weight: 700; + text-transform: uppercase; + font-size: 0.85rem; + letter-spacing: 1px; +} + +/* --- COLORAZIONE PODIO DINAMICA (Basata su Classi) --- */ + +/* 1° Posto - ORO (Funziona ovunque sia la riga) */ +tr.rank-gold { + background-color: rgba(241, 196, 15, 0.08) !important; +} +tr.rank-gold td:first-child strong { + color: var(--gold); + font-size: 1.4rem; + display: inline-block; +} + +/* 2° Posto - ARGENTO */ +tr.rank-silver { + background-color: rgba(189, 195, 199, 0.08) !important; +} +tr.rank-silver td:first-child strong { + color: var(--silver); + font-size: 1.25rem; +} + +/* 3° Posto - BRONZO */ +tr.rank-bronze { + background-color: rgba(205, 127, 50, 0.05) !important; +} +tr.rank-bronze td:first-child strong { + color: var(--bronze); + font-size: 1.15rem; +} + +/* Stile base per la colonna posizione */ +td strong { + font-weight: 800; + color: var(--text-dark); +} + +/* Effetto al passaggio del mouse sulle righe */ +tr:hover { + background-color: #f1f5f9; +} + +/* Arrotondamento angoli inferiori della tabella */ +table tr:last-child td:first-child { border-bottom-left-radius: 20px; } +table tr:last-child td:last-child { border-bottom-right-radius: 20px; } + +/* Rimuove l'ultima linea per pulizia estetica */ +table tr:last-child td { + border-bottom: none; +} + +/* --- RESPONSIVE --- */ +@media (max-width: 768px) { + body { padding: 20px 10px; } + table { font-size: 0.8rem; } + th, td { padding: 12px 8px; } + h1 { font-size: 1.8rem; } + .sort-button { padding: 10px 15px; margin: 5px; } } \ No newline at end of file diff --git a/css/fase1.css b/css/fase1.css index 5509be5..0d46bf6 100755 --- a/css/fase1.css +++ b/css/fase1.css @@ -1,31 +1,25 @@ +/* --- VARIABILI GLOBALI --- */ :root { + --green-bright: #2ecc71; + --green-glow: rgba(46, 204, 113, 0.6); + --glass-bg: rgba(0, 0, 0, 0.7); + --glass-border: rgba(46, 204, 113, 0.3); --top: 10px; --border: 20px; --text: 1.5rem; } + +/* --- RESET E BODY --- */ body { margin: 0; + padding: 0; overflow: hidden; - font-family: sans-serif; -} -#punti { - position: absolute; - top: var(--top); - left: var(--border); + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + background-color: #000; color: white; - font-size: var(--text); - pointer-events: none; - display: none; -} -#tempo { - position: absolute; - top: var(--top); - right: var(--border); - color: white; - font-size: var(--text); - pointer-events: none; - display: none; } + +/* --- HUD DI GIOCO (Punti e Tempo) --- */ #punti, #tempo { position: absolute; top: var(--top); @@ -33,182 +27,365 @@ body { font-size: var(--text); pointer-events: none; display: none; - /* Aggiungi questa riga */ - text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7); + text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8), 0 0 10px var(--green-glow); font-weight: bold; + z-index: 50; } -/* Cursore */ +#punti { left: var(--border); } +#tempo { right: var(--border); } +#fps-counter { + position: absolute; + top: var(--top); /* Usa la stessa variabile degli altri */ + left: 50%; + transform: translateX(-50%); /* Lo centra perfettamente */ + color: var(--green-bright); + font-size: 1.2rem; /* Leggermente più piccolo dei punti per non distrarre */ + font-family: monospace; + pointer-events: none; + display: none; /* Verrà mostrato insieme agli altri al lock() */ + text-shadow: 0 0 10px var(--green-glow); + z-index: 50; +} + +/* --- MIRINO (Crosshair) --- */ #crosshair { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); - color: white; + color: var(--green-bright); font-size: 24px; - font-family: sans-serif; pointer-events: none; - display: none; /* Sarà visualizzato solo durante il gioco */ + display: none; z-index: 10; + text-shadow: 0 0 5px #000; } -/* Schermata iniziale del gioco */ +/* --- SCHERMATA DI CARICAMENTO (MATRIX) --- */ +#loading-screen { + position: fixed; + inset: 0; + background: #000; + display: flex; + align-items: center; + justify-content: center; + z-index: 9999; + overflow: hidden; +} + +#matrix-canvas { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0.3; +} + +.loader-content { + position: relative; + z-index: 10; + width: 80%; + max-width: 500px; + text-align: center; +} + +.eco-title { + font-family: 'Courier New', monospace; + color: var(--green-bright); + font-size: 1.5rem; + font-weight: bold; + letter-spacing: 5px; + margin-bottom: 30px; + text-shadow: 0 0 10px var(--green-glow); +} + +.bar-container { + width: 100%; + background: #222 !important; + height: 10px; + border-radius: 5px; + overflow: hidden; + position: relative; + z-index: 20; + border: 1px solid rgba(255,255,255,0.1); +} + +#loading-bar { + width: 0%; + height: 100%; + background-color: var(--green-bright) !important; + box-shadow: 0 0 20px var(--green-bright); + transition: width 0.3s ease-out; +} + +#loading-text { + color: var(--green-bright); + font-family: monospace; + font-size: 0.9rem; + letter-spacing: 2px; + opacity: 0.8; + margin-top: 10px; +} + +/* --- POPUP INSERIMENTO USERNAME --- */ +/* Overlay con sfocatura profonda */ +#name-popup-overlay { + position: fixed; + inset: 0; + z-index: 9999; + background: radial-gradient(circle, rgba(0, 20, 10, 0.7) 0%, rgba(0, 0, 0, 0.95) 100%); + backdrop-filter: blur(12px); + display: none; + align-items: center; + justify-content: center; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} + +/* Contenitore Popup */ +.name-popup { + background: rgba(10, 15, 12, 0.85); + border: 2px solid var(--green-bright); + padding: 3rem; + border-radius: 30px; + text-align: center; + box-shadow: 0 0 40px rgba(46, 204, 113, 0.2), inset 0 0 20px rgba(46, 204, 113, 0.1); + max-width: 450px; + width: 90%; + transform: translateY(20px); + animation: popupFadeIn 0.6s ease forwards; + border-top: 5px solid var(--green-bright); /* Accento superiore */ +} + +@keyframes popupFadeIn { + to { transform: translateY(0); opacity: 1; } +} + +.name-popup h3 { + color: var(--green-bright); + margin-bottom: 10px; + letter-spacing: 3px; + text-transform: uppercase; + font-weight: 900; + text-shadow: 0 0 10px var(--green-glow); +} + +.name-popup p { + color: rgba(255, 255, 255, 0.7); + font-size: 0.9rem; + margin-bottom: 2rem; + font-style: italic; +} + +/* Input stilizzato */ +#username-input { + width: 100%; + padding: 15px; + background: rgba(0, 0, 0, 0.4); + border: 1px solid rgba(46, 204, 113, 0.4); + border-radius: 12px; + color: #fff; + font-size: 1.2rem; + margin-bottom: 25px; + outline: none; + text-align: center; + transition: all 0.3s ease; + box-sizing: border-box; + letter-spacing: 1px; +} + +#username-input:focus { + border-color: var(--green-bright); + box-shadow: 0 0 15px var(--green-glow); + background: rgba(46, 204, 113, 0.05); +} + +/* Pulsante di conferma */ +#confirm-name-btn { + width: 100%; + background: var(--green-bright); + color: #002b12; + border: none; + padding: 15px; + font-weight: 800; + text-transform: uppercase; + letter-spacing: 2px; + cursor: pointer; + border-radius: 12px; + transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); +} + +#confirm-name-btn:hover { + background: #fff; + color: #000; + box-shadow: 0 0 25px #fff; + transform: scale(1.03); +} + +/* Effetto errore (scuotimento) */ +.shake { + animation: shakeAnim 0.4s ease; +} + +@keyframes shakeAnim { + 0%, 100% { transform: translateX(0); } + 25% { transform: translateX(-10px); } + 75% { transform: translateX(10px); } +} + +/* --- SCHERMATA INIZIALE (START) --- */ +/* L'overlay serve come ulteriore strato di colore per far leggere bene i testi */ +.overlay { + position: absolute; + inset: 0; + background: radial-gradient(circle, rgba(0,0,0,0) 0%, rgba(0,0,0,0.6) 100%); + z-index: 0; + pointer-events: none; +} + +/* Assicurati che il contenitore start non mostri lo scale dell'immagine fuori dai bordi */ #start { position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - overflow: hidden; - color: white; - font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; - /* Queste 4 righe garantiscono la centratura totale */ + inset: 0; + overflow: hidden; /* Fondamentale per il trucco dello scale */ display: flex; flex-direction: column; - justify-content: center; - align-items: center; - z-index: 100; /* Assicurati che sia sopra al renderer di Three.js */ + z-index: 100; } -/* Video a tutto schermo */ -#bg-video { +#bg-island { position: absolute; top: 0; left: 0; width: 100%; height: 100%; + object-fit: cover; z-index: -1; - object-fit: cover; /* Riempie lo schermo senza deformare */ + /* Effetto sfocatura e luminosità ridotta */ + filter: blur(6px) brightness(0.5); + /* Lo scale(1.1) serve a "ingrandire" l'immagine quel tanto che basta + per nascondere i bordi sfocati che altrimenti diventerebbero bianchi */ + transform: scale(1.1); } .overlay { position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: rgba(0, 0, 0, 0.4); + inset: 0; + background: rgba(0, 0, 0, 0.5); z-index: 0; - pointer-events: none; /* Il click attraversa l'overlay e arriva a #start */ + pointer-events: none; } .content { position: relative; z-index: 1; height: 100%; - width: 100%; /* Aggiunto */ + width: 100%; display: flex; flex-direction: column; } -/* Divisione 50% Sopra */ +/* Titolo Missione */ .top-section { flex: 1; display: flex; align-items: center; justify-content: center; + padding-top: 40px; } .main-title { width: 25%; height: auto; + filter: drop-shadow(0 0 15px var(--green-bright)); } - -/* Divisione 50% Sotto */ +/* Layout a Tre Colonne */ .bottom-section { - flex: 1; - display: flex; - flex-direction: row; - width: 100%; /* Forza l'espansione orizzontale */ - align-items: flex-start; - padding-top: 20px; + flex: 1.5; + display: grid; + grid-template-columns: 1fr 1fr 1fr; + align-items: center; + padding: 0 5%; + gap: 20px; } .item { - /* flex: 1 0 33%; significa: cresci, non restringerti, base 33% */ - flex: 1 0 33.33%; display: flex; justify-content: center; - text-align: center; -} - -/* Styling dei Controlli */ -.controls-box { - width: 100%; - display: flex; - flex-direction: column; align-items: center; - justify-content: center; height: 100%; +} + +/* Box con effetto Vetro (Glassmorphism) */ +.controls-box, .instructions-box { + background: var(--glass-bg); + backdrop-filter: blur(10px); + border: 1px solid var(--glass-border); + padding: 25px; + border-radius: 15px; color: white; - text-shadow: 2px 2px 4px rgba(0,0,0,0.8); - font-family: 'Press Start 2P', cursive; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); + width: 100%; + max-width: 350px; } -.controls-box h3 { - margin-bottom: 10px; - font-size: 1.4rem; +.controls-box h3, .instructions-box h3 { + margin-top: 0; + margin-bottom: 15px; + font-size: 1.3rem; text-transform: uppercase; + color: var(--green-bright); text-align: center; + border-bottom: 1px solid var(--glass-border); + padding-bottom: 10px; } -.controls-box p { - margin: 6px 0; - font-size: 1.1rem; +.controls-box p, .instructions-box p { + margin: 8px 0; + font-size: 1rem; text-align: center; + line-height: 1.5; } -/* Stile dei tasti */ -.controls-box kbd { - background-color: #5e5d5d; - color: #fff; - padding: 4px 8px; +/* Tasti Tastiera */ +kbd { + background-color: #333; + border: 1px solid var(--green-bright); + color: var(--green-bright); + padding: 3px 6px; border-radius: 4px; font-family: monospace; font-weight: bold; - margin: 6px 0; + box-shadow: 0 0 5px var(--green-glow); } -/* Box delle istruzioni */ -.instructions-box { - width: 100%; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100%; - color: white; - text-shadow: 2px 2px 4px rgba(0,0,0,0.8); - font-family: 'Press Start 2P', cursive; -} - -.instructions-box h3 { - margin-bottom: 10px; - font-size: 1.4rem; - text-transform: uppercase; - text-align: center; -} - -.instructions-box p { - margin: 6px 0; - font-size: 1.1rem; - text-align: center; -} - - - - -/* Animazione per "Clicca per giocare" */ +/* Testo Pulsante Centrale */ .pulse-text { - font-size: 1.5rem; + font-size: 2rem; + font-weight: 800; text-transform: uppercase; - letter-spacing: 2px; + letter-spacing: 4px; + color: #fff; + text-shadow: 0 0 15px var(--green-bright); + cursor: pointer; animation: pulse 2s infinite; + text-align: center; } @keyframes pulse { - 0% { opacity: 1; } - 50% { opacity: 0.4; } - 100% { opacity: 1; } + 0% { opacity: 1; transform: scale(1); } + 50% { opacity: 0.5; transform: scale(0.95); } + 100% { opacity: 1; transform: scale(1); } +} + +/* Responsive per schermi piccoli */ +@media (max-width: 900px) { + .bottom-section { + grid-template-columns: 1fr; + overflow-y: auto; + padding-bottom: 40px; + } + .main-title { width: 50%; } } \ No newline at end of file diff --git a/css/fase2.css b/css/fase2.css index fa043fb..92a404e 100644 --- a/css/fase2.css +++ b/css/fase2.css @@ -1,123 +1,156 @@ -body { - margin: 0; - font-family: Arial, sans-serif; - background-color: #f0f0f0; - display: flex; - flex-direction: column; - align-items: center; -} - -#game-container { - width: 1000px; - height: 600px; - background-color: #000; - position: relative; - overflow: hidden; - border: 5px solid #333; - margin: 0 auto; - cursor: default; -} - -/* Area dei bidoni */ -#bins-container { - display: flex; - justify-content: space-between; - padding: 20px 10px; - width: 100%; - box-sizing: border-box; -} - -/* Effetto bagliore per risposta corretta (Verde) */ -.glow-success { - box-shadow: 0 0 30px 15px rgba(0, 255, 0, 0.6); - border-radius: 50%; /* Rende l'effetto ovale/circolare */ - transition: box-shadow 0.2s ease-in-out; -} - -/* Effetto bagliore per risposta errata (Rosso) */ -.glow-error { - box-shadow: 0 0 30px 15px rgba(255, 0, 0, 0.6); - border-radius: 50%; - transition: box-shadow 0.2s ease-in-out; -} - -.bin img { - width: 100%; - height: auto; - pointer-events: none; - - /* Questa riga è la magia: */ - mix-blend-mode: screen; - - /* 'screen' mantiene i colori chiari e rende invisibile il nero. - In questo modo il bagliore dietro passerà attraverso le zone nere. */ -} - - -/* Modifica leggera al bagliore per renderlo più visibile sotto il bidone */ -.bin::after { - content: ""; - position: absolute; - top: 60%; /* Abbassato un po' per centrarsi meglio sulla base del bidone */ - left: 50%; - transform: translate(-50%, -50%); - width: 150px; - height: 100px; /* Più largo che alto per un effetto ovale perfetto */ - border-radius: 50%; - opacity: 0; - filter: blur(10px); /* Sfuma i bordi della luce */ - transition: opacity 0.3s; - z-index: -1; -} - -/* Stato Successo (Verde) */ -.glow-success::after { - opacity: 1; - box-shadow: 0 0 40px 20px rgba(0, 255, 0, 0.7); - background-color: rgba(0, 255, 0, 0.2); /* Opzionale: un leggero centro colorato */ -} - -/* Stato Errore (Rosso) */ -.glow-error::after { - opacity: 1; - box-shadow: 0 0 40px 20px rgba(255, 0, 0, 0.7); - background-color: rgba(255, 0, 0, 0.2); -} - -.bin img { - width: 100%; - height: auto; - pointer-events: none; /* Impedisce che il mouse "prenda" l'immagine del bidone */ -} - -/* I rifiuti */ -.trash { - width: 100px; - height: 100px; - object-fit: contain; - position: absolute; - z-index: 100; -} -.trash:active { - cursor: grabbing; -} -/* Il bancone marrone in basso */ -#counter { - position: absolute; - bottom: 0; - width: 100%; - height: 100px; - background-color: #5d4037; - /* Colore marrone bancone */ - display: flex; - justify-content: center; - align-items: center; -} - -/* Area UI (Punti e Tempo) */ -#ui { - margin-top: 10px; - font-size: 24px; - font-weight: bold; -} - +/* --- VARIABILI GLOBALI --- */ +:root { + --bg-light: #f8fafc; + --text-dark: #1e293b; + --green-eco: #10b981; + --red-alert: #ef4444; + --counter-top: #334155; +} + +/* --- RESET BASE --- */ +body { + margin: 0; + padding: 0; + font-family: 'Inter', -apple-system, sans-serif; + background-color: var(--bg-light); + color: var(--text-dark); + display: flex; + flex-direction: column; + align-items: center; + min-height: 100vh; +} + +/* --- UI SUPERIORE (Punti e Tempo) --- */ +#ui { + margin-top: 20px; + padding: 12px 40px; + background: white; + border-radius: 16px; + font-size: 1.1rem; + font-weight: 700; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); + border: 1px solid #e2e8f0; + z-index: 1000; +} + +#ui span { + color: var(--green-eco); +} + +/* --- CONTAINER GIOCO --- */ +#game-container { + width: 92vw; + height: 82vh; + background-color: #000; /* Fondo nero per il mix-blend-mode */ + position: relative; + overflow: hidden; + border-radius: 24px; + box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); + margin: 20px auto; + border: 8px solid white; /* Cornice stile tablet */ +} + +/* --- AREA DEI BIDONI (Ingranditi) --- */ +#bins-container { + display: flex; + justify-content: center; /* Centra i bidoni */ + gap: 12px; /* Spazio tra i bidoni */ + align-items: flex-end; + padding: 30px 20px; + width: 100%; + height: 72%; /* Più spazio verticale per cestini grandi */ + box-sizing: border-box; +} + +.bin { + position: relative; + /* Ingrandimento: ora i bidoni occupano fino al 20% della larghezza */ + width: 20%; + max-width: 200px; + min-width: 140px; + transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1); +} + +.bin:hover { + transform: scale(1.08) translateY(-10px); +} + +/* Gestione immagini con sfondo nero e scritta interna */ +.bin img { + width: 100%; + height: auto; + mix-blend-mode: screen; /* Rende il nero dell'immagine trasparente */ + pointer-events: none; + z-index: 2; + position: relative; + + /* Aumentiamo luminosità e contrasto per far leggere meglio le scritte nere */ + filter: brightness(1.25) contrast(1.1); +} + +/* --- EFFETTI FEEDBACK (Bagliore sotto) --- */ +.bin::after { + content: ""; + position: absolute; + bottom: 5%; + left: 50%; + transform: translateX(-50%); + width: 100%; + height: 100px; + border-radius: 50%; + opacity: 0; + filter: blur(25px); + transition: opacity 0.3s ease; + z-index: 1; +} + +.glow-success::after { + opacity: 0.8; + background: var(--green-eco); + box-shadow: 0 0 60px 30px var(--green-eco); +} + +.glow-error::after { + opacity: 0.8; + background: var(--red-alert); + box-shadow: 0 0 60px 30px var(--red-alert); +} + +/* --- I RIFIUTI (Trash) --- */ +.trash { + width: 90px; + height: 90px; + object-fit: contain; + position: absolute; + z-index: 500; + cursor: grab; + /* Ombra per farli sembrare sollevati */ + filter: drop-shadow(0 12px 10px rgba(0,0,0,0.4)); +} + +.trash:active { + cursor: grabbing; +} + +/* --- IL BANCONE (Counter) --- */ +#counter { + position: absolute; + bottom: 0; + width: 100%; + height: 120px; + background: var(--counter-top); + border-top: 3px solid rgba(255,255,255,0.1); + display: flex; + justify-content: center; + align-items: center; +} + +/* Effetto profondità sul bordo del bancone */ +#counter::before { + content: ""; + position: absolute; + top: 0; + width: 100%; + height: 8px; + background: linear-gradient(to bottom, rgba(0,0,0,0.3), transparent); +} \ No newline at end of file diff --git a/css/fase2.css.old b/css/fase2.css.old new file mode 100644 index 0000000..cb5ebc7 --- /dev/null +++ b/css/fase2.css.old @@ -0,0 +1,125 @@ +body { + margin: 0; + font-family: Arial, sans-serif; + background-color: #f0f0f0; + display: flex; + flex-direction: column; + align-items: center; +} + +#game-container { + /*width: 1000px; + height: 600px;*/ + width: 90vw; + height: 90vh; + background-color: #000; + position: relative; + overflow: hidden; + border: 5px solid #333; + margin: 0 auto; + cursor: default; +} + +/* Area dei bidoni */ +#bins-container { + display: flex; + justify-content: space-between; + padding: 20px 10px; + width: 100%; + box-sizing: border-box; +} + +/* Effetto bagliore per risposta corretta (Verde) */ +.glow-success { + box-shadow: 0 0 30px 15px rgba(0, 255, 0, 0.6); + border-radius: 50%; /* Rende l'effetto ovale/circolare */ + transition: box-shadow 0.2s ease-in-out; +} + +/* Effetto bagliore per risposta errata (Rosso) */ +.glow-error { + box-shadow: 0 0 30px 15px rgba(255, 0, 0, 0.6); + border-radius: 50%; + transition: box-shadow 0.2s ease-in-out; +} + +.bin img { + width: 100%; + height: auto; + pointer-events: none; + + /* Questa riga è la magia: */ + mix-blend-mode: screen; + + /* 'screen' mantiene i colori chiari e rende invisibile il nero. + In questo modo il bagliore dietro passerà attraverso le zone nere. */ +} + + +/* Modifica leggera al bagliore per renderlo più visibile sotto il bidone */ +.bin::after { + content: ""; + position: absolute; + top: 60%; /* Abbassato un po' per centrarsi meglio sulla base del bidone */ + left: 50%; + transform: translate(-50%, -50%); + width: 150px; + height: 100px; /* Più largo che alto per un effetto ovale perfetto */ + border-radius: 50%; + opacity: 0; + filter: blur(10px); /* Sfuma i bordi della luce */ + transition: opacity 0.3s; + z-index: -1; +} + +/* Stato Successo (Verde) */ +.glow-success::after { + opacity: 1; + box-shadow: 0 0 40px 20px rgba(0, 255, 0, 0.7); + background-color: rgba(0, 255, 0, 0.2); /* Opzionale: un leggero centro colorato */ +} + +/* Stato Errore (Rosso) */ +.glow-error::after { + opacity: 1; + box-shadow: 0 0 40px 20px rgba(255, 0, 0, 0.7); + background-color: rgba(255, 0, 0, 0.2); +} + +.bin img { + width: 100%; + height: auto; + pointer-events: none; /* Impedisce che il mouse "prenda" l'immagine del bidone */ +} + +/* I rifiuti */ +.trash { + width: 100px; + height: 100px; + object-fit: contain; + position: absolute; + z-index: 100; +} +.trash:active { + cursor: grabbing; +} +/* Il bancone marrone in basso */ +#counter { + position: absolute; + bottom: 0; + width: 100%; + height: 100px; + background-color: #5d4037; + /* Colore marrone bancone */ + display: flex; + justify-content: center; + align-items: center; +} + +/* Area UI (Punti e Tempo) */ +#ui { + margin-top: 10px; + font-size: 24px; + font-weight: bold; +} + diff --git a/css/istruzioniFase2.css b/css/istruzioniFase2.css index e69de29..a493d98 100644 --- a/css/istruzioniFase2.css +++ b/css/istruzioniFase2.css @@ -0,0 +1,194 @@ +/* --- VARIABILI GLOBALI --- */ +:root { + --green-bright: #2ecc71; + --green-glow: rgba(46, 204, 113, 0.4); + --glass-bg: rgba(255, 255, 255, 0.05); + --glass-border: rgba(46, 204, 113, 0.2); + --top: 10px; + --text-base: 1.1rem; +} + +/* --- RESET E BASE --- */ +body { + margin: 0; + padding: 0; + overflow: hidden; + background-color: #000; /* Sfondo di sicurezza */ +} + +/* --- SCHERMATA FASE 2 --- */ +#start-fase2 { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + z-index: 500; + color: white; + font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; + + /* Sfondo Sfumato Base */ + background: radial-gradient(circle at center, #0a2f1a 0%, #000000 100%); + transition: opacity 0.5s ease; +} + +/* Overlay per dare texture allo sfondo */ +.overlay-gradient { + position: absolute; + inset: 0; + background: linear-gradient(180deg, transparent 0%, rgba(46, 204, 113, 0.05) 100%); + pointer-events: none; + z-index: 0; +} + +/* --- CONTENUTO --- */ +.content { + position: relative; + z-index: 1; + display: flex; + flex-direction: column; + width: 100%; + height: 100%; +} + +/* Sezione Titolo (50% sopra) */ +.top-section { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + text-align: center; +} + +.top-section h1 { + font-size: 3.5rem; + text-transform: uppercase; + letter-spacing: 5px; + color: var(--green-bright); + text-shadow: 0 0 20px var(--green-glow); + margin: 0; + padding: 20px; +} + +/* Sezione Box (50% sotto) */ +.bottom-section { + flex: 1; + display: flex; + flex-direction: row; + width: 100%; + align-items: flex-start; + padding-top: 20px; +} + +.item { + flex: 1; + display: flex; + justify-content: center; + align-items: flex-start; + padding: 0 20px; +} + +/* --- BOX STILIZZATI (Glassmorphism) --- */ +.controls-box, .instructions-box { + background: var(--glass-bg); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border: 1px solid var(--glass-border); + border-top: 4px solid var(--green-bright); + padding: 30px; + border-radius: 20px; + box-shadow: 0 15px 35px rgba(0,0,0,0.6); + width: 100%; + max-width: 350px; + min-height: 200px; + text-align: center; +} + +.controls-box h3, .instructions-box h3 { + margin-top: 0; + margin-bottom: 20px; + font-size: 1.4rem; + text-transform: uppercase; + color: var(--green-bright); + letter-spacing: 1px; +} + +.controls-box p, .instructions-box p { + font-size: var(--text-base); + line-height: 1.6; + margin: 10px 0; + text-shadow: 1px 1px 2px rgba(0,0,0,0.5); +} + +/* --- ELEMENTI SPECIALI --- */ +kbd { + background: #222; + color: var(--green-bright); + border: 1px solid var(--green-bright); + padding: 3px 10px; + border-radius: 5px; + font-family: 'Courier New', Courier, monospace; + font-weight: bold; + box-shadow: 0 0 5px var(--green-glow); +} + +b, i { + color: var(--green-bright); + font-style: normal; +} + +/* --- PULSANTE CENTRALE --- */ +.item.center { + align-items: center; /* Il pulsante centrale lo vogliamo a metà altezza */ + height: 50%; +} + +.pulse-text { + display: inline-block; + padding: 20px 40px; + font-size: 1.5rem; + font-weight: 800; + text-transform: uppercase; + letter-spacing: 2px; + color: white; + border: 2px solid var(--green-bright); + border-radius: 50px; + cursor: pointer; + transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); + animation: pulse 2s infinite; + background: rgba(46, 204, 113, 0.1); +} + +.pulse-text:hover { + background: var(--green-bright); + color: black; + box-shadow: 0 0 30px var(--green-glow); + transform: scale(1.1); + animation-play-state: paused; /* Si ferma quando ci passi sopra */ +} + +/* --- ANIMAZIONI --- */ +@keyframes pulse { + 0% { transform: scale(1); opacity: 1; box-shadow: 0 0 0 0 rgba(46, 204, 113, 0.7); } + 50% { transform: scale(1.05); opacity: 0.7; box-shadow: 0 0 20px 10px rgba(46, 204, 113, 0); } + 100% { transform: scale(1); opacity: 1; box-shadow: 0 0 0 0 rgba(46, 204, 113, 0); } +} + +/* --- RESPONSIVE VELOCE --- */ +@media (max-width: 900px) { + .bottom-section { + flex-direction: column; + align-items: center; + } + .item { + margin-bottom: 20px; + width: 80%; + } + .top-section h1 { + font-size: 2rem; + } +} \ No newline at end of file diff --git a/css/risultatiFinali.css b/css/risultatiFinali.css index e69de29..b7d8648 100644 --- a/css/risultatiFinali.css +++ b/css/risultatiFinali.css @@ -0,0 +1,203 @@ +:root { + --green-bright: #2ecc71; + --green-glow: #27ae60; + --bg-overlay: rgba(0, 0, 0, 0.6); + --panel-bg: rgba(0, 0, 0, 0.3); + --text-main: 1.2rem; +} + +body, html { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + overflow: hidden; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + color: white; + background: url('../assets/media/img/sfondo_finale.png') no-repeat center center fixed; + background-size: cover; +} + +/* Overlay per scurire leggermente lo sfondo e far risaltare il testo */ +.overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: var(--bg-overlay); + z-index: 0; +} + +/* Layout Principale (Diviso in Sinistra e Destra) */ +#start { + position: relative; + width: 100vw; + height: 100vh; + z-index: 10; +} + +.content { + display: flex; + width: 100%; + height: 100%; + position: relative; +} + +/* --- SEZIONE SINISTRA (60% del totale) --- */ +.left1 { + flex: 1.5; + display: flex; + flex-direction: column; /* Divide in Alto e Basso */ + border-right: 1px solid rgba(46, 204, 113, 0.2); +} + +/* Parte in ALTO a sinistra (Titolo) */ +.left1 .top { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + padding: 20px; +} + +.left1 .top h1 { + font-size: 4.5rem; + margin: 0; + color: #fff; + text-shadow: 0 0 20px var(--green-bright), 0 0 30px var(--green-glow); + letter-spacing: 5px; + text-align: center; +} + +/* Parte in BASSO a sinistra (Divisa in Bottoni e Punteggi) */ +.left1 .bottom { + flex: 1; + display: flex; /* Divide in Sinistra (left2) e Destra (right2) */ + padding: 40px; + gap: 30px; +} + +/* Bottoni (Basso-Sinistra) */ +.left2 { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 20px; +} + +button { + width: 280px; + padding: 18px; + font-size: 1.1rem; + font-weight: bold; + color: white; + background: transparent; + border: 2px solid var(--green-bright); + border-radius: 8px; + cursor: pointer; + text-transform: uppercase; + transition: all 0.3s ease; +} + +button:hover { + background: var(--green-bright); + color: black; + box-shadow: 0 0 25px var(--green-bright); + transform: scale(1.05); +} + +/* Riepilogo Punteggi (Basso-Destra) */ +.right2 { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + background: var(--panel-bg); + border: 1px solid rgba(46, 204, 113, 0.3); + border-radius: 20px; + padding: 20px; +} + +.right2 p { + font-size: 1.4rem; + line-height: 2; + margin: 0; +} + +.right2 b { + color: var(--green-bright); + font-size: 1.6rem; + display: block; + margin-bottom: 10px; +} + +.right2 i { + color: #ccc; + font-style: normal; + font-weight: bold; +} + +/* --- SEZIONE DESTRA (40% del totale - Classifica) --- */ +.right1 { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + padding: 40px 20px; + background: rgba(0, 0, 0, 0.4); +} + +.right1 h2 { + font-size: 2.5rem; + color: var(--green-bright); + margin-bottom: 30px; + text-transform: uppercase; +} + +/* Tabella Classifica */ +table.container { + width: 90%; + border-collapse: collapse; + background: rgba(255, 255, 255, 0.03); + border-radius: 10px; + overflow: hidden; +} + +table.container th { + background: rgba(46, 204, 113, 0.5); + padding: 15px; + text-align: center; + font-size: 1.1rem; +} + +table.container td { + padding: 12px; + text-align: center; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + font-size: 1.1rem; +} + +table.container tr:last-child td { + border-bottom: none; +} + +table.container tr:hover { + background: rgba(46, 204, 113, 0.1); +} + +/* Supporto per Mobile/Schermi piccoli */ +@media (max-width: 1000px) { + .content { + flex-direction: column; + overflow-y: auto; + } + .left1 .bottom { + flex-direction: column; + } + .left1 .top h1 { + font-size: 2.5rem; + } +} \ No newline at end of file diff --git a/db_iniziale.sql b/db_iniziale.sql index 9884a56..58b8fa4 100644 --- a/db_iniziale.sql +++ b/db_iniziale.sql @@ -14,4 +14,13 @@ CREATE TABLE punteggi ( -- velocita = score1 / 60 -- precisione = score2 / score1 -- punteggio finale = 10000 * ( (score1 / MAX_SCORE) + (score2 / MAX_SCORE) ) / 2 --- MAX_SCORE = 180 (numero massimo possibile di rifiuti raccolti in 1 minuto) \ No newline at end of file +-- MAX_SCORE = 180 (numero massimo possibile di rifiuti raccolti in 1 minuto) + + +-- DATI DI TEST +INSERT INTO punteggi (data_partita, score1, score2, scoreT, nome) VALUES +('2024-06-01', 150, 120, 7500, 'Simone'), +('2024-06-02', 180, 160, 9444, 'Luca'), +('2024-06-03', 120, 100, 6111, 'Giulia'), +('2024-06-04', 90, 70, 4444, 'Marco'), +('2024-06-05', 60, 50, 3055, 'Sara'); \ No newline at end of file diff --git a/index.php b/index.php index 2b68b9f..1f8276d 100644 --- a/index.php +++ b/index.php @@ -1,9 +1,17 @@ + + + + + + 'fase1.html', 'mid' => 'istruzioniFase2.html', 'sep' => 'fase2.html', - 'end' => 'risultatiFinali.html', + 'end' => 'risultatiFinali.php', 'leaderboard' => 'classifica.php', 'error' => 'error.html' ]; diff --git a/js/fase1.js b/js/fase1.js index dec36f0..d86c98d 100755 --- a/js/fase1.js +++ b/js/fase1.js @@ -2,29 +2,79 @@ import * as THREE from 'three'; import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js'; import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; +// 0. IMPOSTAZIONE FPS +let lastTime = performance.now(); +let frameCount = 0; +let fps = 0; +const fpsDisplay = document.getElementById('fps-counter'); + // 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}`); + // Testo iniziale + document.getElementById("loading-text").innerHTML = "IDENTIFICAZIONE RISORSE..."; }; manager.onLoad = function () { - document.getElementById('loading-screen').style.display = 'none'; - animate(); // avvia il rendering + const loadingText = document.getElementById("loading-text"); + // Testo in italiano, tecnico e pulito + loadingText.innerHTML = "CARICAMENTO COMPLETATO CON SUCCESSO"; + // Estetica finale: testo fisso e brillante + loadingText.style.animation = "none"; + loadingText.style.color = "#ffffff"; + loadingText.style.textShadow = "0 0 15px var(--green-bright)"; + loadingText.style.opacity = "1"; + // Timeout per lasciare all'utente il tempo di leggere il successo + setTimeout(() => { + const loadingScreen = document.getElementById('loading-screen'); + loadingScreen.style.opacity = '0'; + loadingScreen.style.transition = 'opacity 0.8s ease'; + setTimeout(() => { + loadingScreen.style.display = 'none'; + // MOSTRA IL POPUP DEL NOME + document.getElementById('name-popup-overlay').style.display = 'flex'; + }, 800); + }, 500); + animate(); // Parte il loop di Three.js }; 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}`); + const percent = Math.round((itemsLoaded / itemsTotal) * 100); + // Estraiamo solo il nome del file dall'URL per pulizia + // Esempio: "assets/models/bottiglia.glb" diventa "bottiglia.glb" + const fileName = url.split('/').pop().toUpperCase(); + // Aggiorniamo la barra + const bar = document.getElementById('loading-bar'); + if (bar) bar.style.width = percent + '%'; + // Nuovo formato del testo: NOME_FILE [XX%] + document.getElementById("loading-text").innerHTML = `${fileName} [${percent}%]`; }; manager.onError = function (url) { - document.getElementById("loading-text").innerHTML = `Errore nel caricamento: ${url}`; - console.log(`Errore nel caricamento: ${url}`); + document.getElementById("loading-text").innerHTML = `ERRORE CARICAMENTO: ${url.split('/').pop()}`; + document.getElementById("loading-text").style.color = "#ff4d4d"; }; +// GESTIONE CONFERMA NOME +document.getElementById('confirm-name-btn').addEventListener('click', function() { + const input = document.getElementById('username-input'); + const name = input.value.trim(); + localStorage.setItem("username", name); + // 1. Nascondi il Popup + const popup = document.getElementById('name-popup-overlay'); + popup.style.opacity = '0'; + popup.style.transition = 'opacity 0.5s ease'; + + setTimeout(() => { + popup.style.display = 'none'; + + // 2. MOSTRA LA SCHERMATA INIZIALE (Controlli e Titolo) + const mainContent = document.getElementById('main-start-content'); + mainContent.style.display = 'flex'; + // Piccolo trucco per l'animazione di entrata (fade in) + setTimeout(() => { + mainContent.style.opacity = '1'; + mainContent.style.transition = 'opacity 1s ease'; + }, 50); + + }, 500); +}); // 1b. SCENA E CAMERA const scene = new THREE.Scene(); @@ -150,6 +200,7 @@ function lock() { document.getElementById('punti').style.display = 'block'; document.getElementById('tempo').style.display = 'block'; document.getElementById('crosshair').style.display = 'block'; + document.getElementById('fps-counter').style.display = 'block'; } function unlock() { timer.pause(); @@ -157,6 +208,7 @@ function unlock() { document.getElementById('punti').style.display = 'none'; document.getElementById('tempo').style.display = 'none'; document.getElementById('crosshair').style.display = 'none'; + document.getElementById('fps-counter').style.display = 'none'; } const controls = new PointerLockControls(camera, document.body); document.getElementById('start').addEventListener('click', () => { @@ -255,6 +307,21 @@ let lastSafePosition = camera.position.clone(); function animate() { requestAnimationFrame(animate); + // --- Calcolo FPS --- + frameCount++; + const currentTime = performance.now(); + // Ogni secondo (1000ms) aggiorniamo il contatore visivo + if (currentTime >= lastTime + 1000) { + fps = frameCount; + fpsDisplay.innerText = `FPS: ${fps}`; + // Colore dinamico: verde se fluido, giallo/rosso se lagga + if (fps < 30) fpsDisplay.style.color = "#ff4d4d"; + else if (fps < 55) fpsDisplay.style.color = "#f1c40f"; + else fpsDisplay.style.color = "var(--green-bright)"; + + frameCount = 0; + lastTime = currentTime; + } if (controls.isLocked) { // 1. Salva la posizione attuale prima del movimento diff --git a/js/fase2.js b/js/fase2.js index 7795024..d9eb7b8 100644 --- a/js/fase2.js +++ b/js/fase2.js @@ -14,8 +14,7 @@ const listaRifiuti = [ { img: 'assets/media/img/fase2/rifiuti/pannolino.png', tipo: 'indifferenziata' } ]; -let punteggio = 0; -let tempo = 60; +let rifiutiTotali = 0; const counter = document.getElementById('counter'); const scoreDisplay = document.getElementById('score'); @@ -143,6 +142,7 @@ function controllaCollisione(rifiuto) { // PORTIAMO IL BIDONE IN PRIMO PIANO bidone.style.zIndex = "2000"; + rifiutiTotali++; if (rifiuto.dataset.tipo === bidone.dataset.type) { // CORRETTO punteggio += 1; @@ -164,7 +164,9 @@ function controllaCollisione(rifiuto) { bidone.style.zIndex = "1"; // Ritorna al suo posto dopo l'effetto }, 400); } - + if (rifiutiTotali >= localStorage.getItem('punteggioFase1')) { + mostraFineGioco(); + } document.getElementById('score').innerText = punteggio; rifiuto.remove(); setTimeout(generaRifiuto, 500); @@ -181,23 +183,27 @@ let timerIntervallo; let tempoRimanente; function avviaTimer(secondiIniziali) { - const displayTimer = document.getElementById('timer'); + const minuti = document.getElementById('minuti'); + const secondi = document.getElementById('secondi'); // Inizializziamo la variabile globale con il valore ricevuto tempoRimanente = secondiIniziali; - displayTimer.innerText = tempoRimanente; + minuti.innerText = String(Math.floor(tempoRimanente / 60)).padStart(2, '0'); + secondi.innerText = String(tempoRimanente % 60).padStart(2, '0'); // Puliamo timer precedenti clearInterval(timerIntervallo); timerIntervallo = setInterval(() => { tempoRimanente--; // Sottraiamo un secondo alla variabile globale - displayTimer.innerText = tempoRimanente; // Aggiorniamo lo schermo + minuti.innerText = String(Math.floor(tempoRimanente / 60)).padStart(2, '0'); + secondi.innerText = String(tempoRimanente % 60).padStart(2, '0'); if (tempoRimanente <= 0) { clearInterval(timerIntervallo); tempoRimanente = 0; - displayTimer.innerText = "0"; + minuti.innerText = "00"; + secondi.innerText = "00"; mostraFineGioco();//LISA E' COMPITO TUO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1 } }, 1000); @@ -236,36 +242,32 @@ function riposizionaSulBancone(rifiuto) { function mostraFineGioco() { // Blocca la generazione di nuovi rifiuti clearInterval(timerIntervallo); - - // Mostra un messaggio finale più gradevole - const messaggio = document.createElement('div'); - messaggio.id = 'fine-gioco'; - messaggio.innerHTML = ` -

Tempo scaduto!

-

Il tuo punteggio finale è: ${punteggio}

- - `; - messaggio.style.position = 'absolute'; - messaggio.style.top = '50%'; - messaggio.style.left = '50%'; - messaggio.style.transform = 'translate(-50%, -50%)'; - messaggio.style.backgroundColor = 'rgba(255, 255, 255, 0.9)'; - messaggio.style.padding = '20px'; - messaggio.style.borderRadius = '10px'; - messaggio.style.textAlign = 'center'; - messaggio.style.zIndex = '3000'; - - document.body.appendChild(messaggio); - // Salva il punteggio nel localStorage localStorage.setItem('punteggioFase2', punteggio); - - // Aggiunge il pulsante per ricominciare - document.getElementById('restart-btn').addEventListener('click', () => { - document.body.removeChild(messaggio); - punteggio = 0; - scoreDisplay.innerText = punteggio; - avviaTimer(60); // o il tempo che vuoi - generaRifiuto(); + const username = localStorage.getItem('username') || 'Anonimo'; + const score1 = parseInt(localStorage.getItem('punteggioFase1')) || 0; + const score2 = parseInt(localStorage.getItem('punteggioFase2')) || 0; + const scoreT = 10_000 * ((score1 / MAX_SCORE) + (score2 / MAX_SCORE)) / 2; + const data_partita = new Date().toISOString().split('T')[0]; // Formato YYYY-MM-DD + fetch('http://localhost:8888/php/save_score.php', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + body: new URLSearchParams({ + nome: username, + score1: score1, + score2: score2, + scoreT: scoreT, + data_partita: data_partita + }) + }) + .then(response => response.text()) + .then(result => { + console.log("Punteggio salvato con successo:", result); + }) + .catch(error => { + console.error("Errore nella richiesta:", error); }); + window.location = "?pagina=end"; } \ No newline at end of file diff --git a/js/loadingScreen.js b/js/loadingScreen.js new file mode 100644 index 0000000..a6cab72 --- /dev/null +++ b/js/loadingScreen.js @@ -0,0 +1,38 @@ +const canvas = document.getElementById('matrix-canvas'); +const ctx = canvas.getContext('2d'); + +canvas.width = window.innerWidth; +canvas.height = window.innerHeight; + +const symbols = '♻☘01RECYCLE-EARTH-SAVE-FUTURE'; +const fontSize = 16; +const columns = canvas.width / fontSize; +const drops = Array(Math.floor(columns)).fill(1); + +function drawMatrix() { + // Sfondo semi-trasparente per creare l'effetto scia + ctx.fillStyle = 'rgba(0, 0, 0, 0.05)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + + ctx.fillStyle = '#2ecc71'; // Il tuo verde brillante + ctx.font = fontSize + 'px monospace'; + + for (let i = 0; i < drops.length; i++) { + const text = symbols.charAt(Math.floor(Math.random() * symbols.length)); + ctx.fillText(text, i * fontSize, drops[i] * fontSize); + + if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) { + drops[i] = 0; + } + drops[i]++; + } +} + +// Avvia l'animazione +setInterval(drawMatrix, 35); + +// Adatta se l'utente ridimensiona la finestra +window.addEventListener('resize', () => { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; +}); \ No newline at end of file diff --git a/materiale/presentazione.pdf b/materiale/presentazione.pdf new file mode 100644 index 0000000..197bf7b Binary files /dev/null and b/materiale/presentazione.pdf differ diff --git a/pages/classifica.php b/pages/classifica.php index 6464785..de86b86 100644 --- a/pages/classifica.php +++ b/pages/classifica.php @@ -1,32 +1,77 @@ - - - - Classifica completa - - - -

Classifica

- - - - - - - - - - - - - $record) { - riga($posizione, $record); - } - ?> - -
PosizioneNomePunteggio 1° fasePunteggio 2° fasePunteggio totaleData di gioco
- + + + + Classifica completa + + + +

Classifica

+ + Posizione) + $rankMap = getRankMap(); + + // Carico i dati in base all'ordinamento scelto + if ($sort === 'data') { + $leaderboard = getSortedLeaderboardByDate(); + } else { + $leaderboard = getSortedLeaderboardByScore(); + } + ?> + +
+ Ordina per data + Ordina per punteggio +
+ + + + + + + + + + + + + + + + + + 0) ? intval(intval($entry['score2']) / intval($entry['score1']) * 100) : 0; + $punteggio_finale = number_format(intval($entry['scoreT']) / 100, 2); + $data_formattata = date("d/m/Y", strtotime($entry['data_partita'])); + ?> + + + + + + + + + + + +
PosizioneNome1° Fase (RPS)2° Fase (%)Punteggio Totale (% isola pulita)Data
Nessun punteggio registrato.
° rps%%
+ \ No newline at end of file diff --git a/pages/fase1.html b/pages/fase1.html index 92ee42a..b79c369 100755 --- a/pages/fase1.html +++ b/pages/fase1.html @@ -7,52 +7,66 @@ -
-
-
+
+ +
+
SAVE THE ISLAND
+
+
+
+
Caricamento delle risorse...
+
+
+ + +
+
+

IDENTIFICAZIONE GIOCATORE

+

Inserisci il tuo nome per iniziare a giocare:

+ +
-
Loading...
- + Sfondo Isola
-
- titolo -
-
-
-
+
+ Eco-Mission +
+
+
+

Controlli

-

Movimento

-

Freccia su / W Avanti

-

Freccia giù / S Indietro

-

Freccia destra / D Destra

-

Freccia sinistra / A Sinistra

-

Mouse Punto di vista

+
+

Freccia su / W Avanti

+

Freccia giù / S Indietro

+

Freccia destra / D Destra

+

Freccia sinistra / A Sinistra

+

Mouse Punto di vista

+
-
-
- Clicca per giocare -
-
-
+ +
+
Clicca per giocare
+
+
+

Istruzioni

-

Obiettivo: raccogliere tutti i rifiuti sull’isola

+

Obiettivo: raccogliere tutti i rifiuti sull’isola

Attenzione allo scadere del tempo!

Usa i comandi per esplorare e ripulire

-
-
+ +
Rifiuti: 0
+
FPS: 0
Tempo: XX:XX
+
+ \ No newline at end of file diff --git a/pages/fase2.html b/pages/fase2.html index cb85c98..435bf44 100644 --- a/pages/fase2.html +++ b/pages/fase2.html @@ -8,7 +8,7 @@
- Punti: 0 | Tempo: s + Punti: 0 | Tempo: :
diff --git a/pages/istruzioniFase2.html b/pages/istruzioniFase2.html index e69de29..76b58bd 100644 --- a/pages/istruzioniFase2.html +++ b/pages/istruzioniFase2.html @@ -0,0 +1,60 @@ + + + + + + Istruzioni fase 2 + + + +
+
+
+
+

Istruzioni fase 2

+
+
+
+
+

Controlli

+

Mouse Per trascinare i rifiuti nei cestini

+
+
+
+ Clicca per giocare +
+
+
+

Istruzioni

+

+ Hai -- secondi per completare il livello +
+ Hai raccolto -- rifiuti nella fase precedente +
+ Obiettivo: separare correttamente i rifiuti nei cestini corrispondenti +

+
+
+
+
+
+ + + \ No newline at end of file diff --git a/pages/risultatiFinali.html b/pages/risultatiFinali.html deleted file mode 100644 index e69de29..0000000 diff --git a/pages/risultatiFinali.php b/pages/risultatiFinali.php new file mode 100644 index 0000000..c3043e2 --- /dev/null +++ b/pages/risultatiFinali.php @@ -0,0 +1,88 @@ + Posizione) +$rankMap = getRankMap(); +// Carico i dati in base all'ordinamento scelto +$leaderboard = getTop10byScore(); +?> + + + + + + Schermata Finale + + + + + +
+
+
+
+
+

MISSIONE COMPIUTA

+
+
+
+ + +
+
+

+ Punteggi: +
+ Prima fase: /180 +
+ Seconda fase: / +
+ Totale: /100 +

+
+
+
+
+

Top 10

+ + + + + + + + + + + + + + + + + + + + + + +
NomePunteggio
Nessun punteggio registrato.
°%
+
+
+
+ + + \ No newline at end of file diff --git a/php/db.php b/php/db.php index 11123ae..e00d059 100644 --- a/php/db.php +++ b/php/db.php @@ -1,35 +1,10 @@ connect_error) { + die("Connection failed: " . $conn->connect_error); } -} -$db_test = [ - [ - 'nome' => 's1', - 'p1' => 95, - 'p2' => 90, - 'pt' => 50, - 'g' => '24-11-2025' - ], - [ - 'nome' => 's1', - 'p1' => 95, - 'p2' => 90, - 'pt' => 50, - 'g' => '24-11-2025' - ] -]; -$classifica = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; -function riga($pos, $data) { - $pos++; - $nome = $data['nome']; - $p1 = $data['p1']; - $p2 = $data['p2']; - $pt = $data['pt']; - $g = $data['g']; - echo ''.$pos.''.$nome.''.$p1.''.$p2.''.$pt.''.$g.''; -} ?> \ No newline at end of file diff --git a/php/leaderboard_utils.php b/php/leaderboard_utils.php index e69de29..2fee05c 100644 --- a/php/leaderboard_utils.php +++ b/php/leaderboard_utils.php @@ -0,0 +1,48 @@ + Posizione] basata sullo scoreT + * Utile per sapere la posizione di una partita a prescindere dall'ordinamento visivo + */ +function getRankMap() { + global $conn; + $result = $conn->query("SELECT id FROM " . TABLE_NAME . " ORDER BY scoreT DESC"); + $orderedIds = array_column($result->fetch_all(MYSQLI_ASSOC), 'id'); + // array_flip trasforma [0 => id1, 1 => id2] in [id1 => 0, id2 => 1] + $rankMap = array_flip($orderedIds); + return $rankMap; +} + +function getSortedLeaderboardByDate() { + global $conn; + $result = $conn->query("SELECT * FROM " . TABLE_NAME . " ORDER BY data_partita DESC, id DESC"); + return $result->fetch_all(MYSQLI_ASSOC); +} + +function getSortedLeaderboardByScore() { + global $conn; + $result = $conn->query("SELECT * FROM " . TABLE_NAME . " ORDER BY scoreT DESC"); + return $result->fetch_all(MYSQLI_ASSOC); +} + +// Altre funzioni di utility se necessarie... +function getTop10byScore() { + global $conn; + $result = $conn->query("SELECT * FROM " . TABLE_NAME . " ORDER BY scoreT DESC LIMIT 10"); + return $result->fetch_all(MYSQLI_ASSOC); +} +?> \ No newline at end of file diff --git a/php/save_score.php b/php/save_score.php index e69de29..194619c 100644 --- a/php/save_score.php +++ b/php/save_score.php @@ -0,0 +1,15 @@ +prepare("INSERT INTO punteggi_test (data_partita, score1, score2, scoreT, nome) VALUES (?, ?, ?, ?, ?)"); + $stmt->bind_param("siiis", $data_partita, $score1, $score2, $scoreT, $nome); + $stmt->execute(); + $stmt->close(); + } +?> \ No newline at end of file diff --git a/test.php b/test.php new file mode 100644 index 0000000..0447752 --- /dev/null +++ b/test.php @@ -0,0 +1,30 @@ + 'TEST', + 'score1' => 120, + 'score2' => 118, + 'scoreT' => 6611, + 'data_partita' => date("Y-m-d") +]; +// richiesta post a save_score.php con i dati richiesti +$options = [ + 'http' => [ + 'header' => "Content-type: application/x-www-form-urlencoded\r\n", + 'method' => 'POST', + 'content' => http_build_query($data), + ], +]; +$context = stream_context_create($options); +$result = file_get_contents('http://localhost:8888/php/save_score.php', false, $context); +if ($result === FALSE) { + echo "Errore nella richiesta"; +} else { + echo "Punteggio salvato con successo"; +} +?> \ No newline at end of file