integrazione fase1 completa e schermata principale
This commit is contained in:
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
Binary file not shown.
+60
-24
@@ -65,7 +65,7 @@ body {
|
|||||||
/* Queste 4 righe garantiscono la centratura totale */
|
/* Queste 4 righe garantiscono la centratura totale */
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
z-index: 100; /* Assicurati che sia sopra al renderer di Three.js */
|
z-index: 100; /* Assicurati che sia sopra al renderer di Three.js */
|
||||||
}
|
}
|
||||||
@@ -110,10 +110,11 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.main-title {
|
.main-title {
|
||||||
max-width: 80%;
|
width: 25%;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Divisione 50% Sotto */
|
/* Divisione 50% Sotto */
|
||||||
.bottom-section {
|
.bottom-section {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@@ -132,37 +133,72 @@ body {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Styling dei Controlli (KBD) */
|
/* Styling dei Controlli */
|
||||||
.controls-box {
|
.controls-box {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
justify-content: center;
|
||||||
.controls-box h3 {
|
height: 100%;
|
||||||
margin-bottom: 10px;
|
color: white;
|
||||||
font-size: 1.2rem;
|
text-shadow: 2px 2px 4px rgba(0,0,0,0.8);
|
||||||
text-transform: uppercase;
|
font-family: 'Press Start 2P', cursive;
|
||||||
}
|
|
||||||
.controls-box h3, .controls-box p, .pulse-text {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kbd {
|
.controls-box h3 {
|
||||||
background-color: #eee;
|
margin-bottom: 10px;
|
||||||
border-radius: 3px;
|
font-size: 1.4rem;
|
||||||
border: 1px solid #b4b4b4;
|
text-transform: uppercase;
|
||||||
box-shadow: 0 1px 1px rgba(0,0,0,0.2), 0 2px 0 0 rgba(255,255,255,0.7) inset;
|
text-align: center;
|
||||||
color: #333;
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 0.85em;
|
|
||||||
font-weight: 700;
|
|
||||||
line-height: 1;
|
|
||||||
padding: 2px 4px;
|
|
||||||
white-space: nowrap;
|
|
||||||
margin: 0 2px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.controls-box p {
|
||||||
|
margin: 6px 0;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stile dei tasti */
|
||||||
|
.controls-box kbd {
|
||||||
|
background-color: #5e5d5d;
|
||||||
|
color: #fff;
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-family: monospace;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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" */
|
/* Animazione per "Clicca per giocare" */
|
||||||
.pulse-text {
|
.pulse-text {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
|
|||||||
@@ -12,5 +12,5 @@
|
|||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
$p = 'error';
|
$p = 'error';
|
||||||
}
|
}
|
||||||
include $__DIR__ . '/pages/' . $route[$p];
|
include __DIR__ . '/pages/' . $route[$p];
|
||||||
?>
|
?>
|
||||||
+267
-27
@@ -2,9 +2,33 @@ 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(0x87ceeb);
|
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);
|
||||||
const renderer = new THREE.WebGLRenderer();
|
const renderer = new THREE.WebGLRenderer();
|
||||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
@@ -12,14 +36,115 @@ document.body.appendChild(renderer.domElement);
|
|||||||
window.addEventListener('resize', function () {
|
window.addEventListener('resize', function () {
|
||||||
renderer.setSize(window.innerWidth, window.innerHeight)
|
renderer.setSize(window.innerWidth, window.innerHeight)
|
||||||
})
|
})
|
||||||
|
// AGGIUNTA MARE
|
||||||
|
const oceanGeometry = new THREE.PlaneGeometry(2000, 2000);
|
||||||
|
const oceanMaterial = new THREE.MeshStandardMaterial({
|
||||||
|
color: 0x0077be,
|
||||||
|
transparent: true,
|
||||||
|
opacity: 0.8
|
||||||
|
});
|
||||||
|
const ocean = new THREE.Mesh(oceanGeometry, oceanMaterial);
|
||||||
|
ocean.rotation.x = -Math.PI / 2;
|
||||||
|
ocean.position.y = -0.2; // Leggermente sotto l'isola
|
||||||
|
scene.add(ocean);
|
||||||
|
|
||||||
// 2. LUCI E AMBIENTE
|
// 2. LUCI E AMBIENTE
|
||||||
scene.add(new THREE.AmbientLight(0xffffff, 1));
|
scene.add(new THREE.AmbientLight(0xffffff, 0.8));
|
||||||
const island = new THREE.Mesh(new THREE.CircleGeometry(20, 32), new THREE.MeshStandardMaterial({ color: 0x4df556 })); // #4df555
|
const sunLight = new THREE.DirectionalLight(0xffffff, 1);
|
||||||
island.rotation.x = -Math.PI / 2;
|
sunLight.position.set(10, 20, 10);
|
||||||
scene.add(island);
|
scene.add(sunLight);
|
||||||
|
|
||||||
|
const islandGroup = new THREE.Group();
|
||||||
|
|
||||||
|
const altezzaIsola = 0.5; // Quanto sta il prato sopra il livello del mare (0.0)
|
||||||
|
const altezzaOcchi = 1.6; // L'altezza standard della telecamera
|
||||||
|
|
||||||
|
// --- IL FONDALE (Sabbia scura sul fondo) ---
|
||||||
|
const floorGeo = new THREE.PlaneGeometry(1000, 1000);
|
||||||
|
const floorMat = new THREE.MeshStandardMaterial({ color: 0x1a1a1a }); // Grigio scuro/Fondale
|
||||||
|
const floor = new THREE.Mesh(floorGeo, floorMat);
|
||||||
|
floor.rotation.x = -Math.PI / 2;
|
||||||
|
floor.position.y = -3; // 5 metri sotto il livello del mare
|
||||||
|
scene.add(floor);
|
||||||
|
|
||||||
|
// --- IL PRATO ---
|
||||||
|
const raggioPrato = 19;
|
||||||
|
const grassGeo = new THREE.CircleGeometry(raggioPrato, 64);
|
||||||
|
const grassMat = new THREE.MeshStandardMaterial({ color: 0x4df556 });
|
||||||
|
const grass = new THREE.Mesh(grassGeo, grassMat);
|
||||||
|
grass.rotation.x = -Math.PI / 2;
|
||||||
|
|
||||||
|
// Posizioniamo il prato all'altezza desiderata
|
||||||
|
grass.position.y = altezzaIsola;
|
||||||
|
islandGroup.add(grass);
|
||||||
|
|
||||||
|
// --- LA SABBIA (Cilindro Svasato) ---
|
||||||
|
const altezzaSabbia = 1.5; // Altezza totale del blocco sabbia
|
||||||
|
const sandGeo = new THREE.CylinderGeometry(raggioPrato, 22 + 10, altezzaSabbia + 3, 64, 1, true);
|
||||||
|
const sandMat = new THREE.MeshStandardMaterial({ color: 0xedc9af, side: THREE.DoubleSide });
|
||||||
|
const sand = new THREE.Mesh(sandGeo, sandMat);
|
||||||
|
|
||||||
|
// Per far combaciare la cima del cilindro con il prato:
|
||||||
|
// L'altezza è 1.5, il centro del cilindro deve stare a (AltezzaIsola - metà altezza cilindro)
|
||||||
|
sand.position.y = altezzaIsola - (altezzaSabbia / 2) - 1.5;
|
||||||
|
islandGroup.add(sand);
|
||||||
|
|
||||||
|
scene.add(islandGroup);
|
||||||
|
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("punteggioFase1", document.getElementById("score").innerHTML.trim());
|
||||||
|
window.location = "?pagina=mid";
|
||||||
|
}, 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';
|
||||||
@@ -27,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 RIFIUTI (20 pezzi)
|
// 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('assets/models/rifiuto.glb', (gltf) => {
|
loader.load('assets/models/rifiuto.glb', (gltf) => {
|
||||||
const mesh = gltf.scene.getObjectByName("Trash_Pile_03_GEO");
|
const mesh = gltf.scene.getObjectByName("Trash_Pile_03_GEO");
|
||||||
@@ -51,41 +181,151 @@ loader.load('assets/models/rifiuto.glb', (gltf) => {
|
|||||||
const clone = mesh.clone();
|
const clone = mesh.clone();
|
||||||
scene.add(clone);
|
scene.add(clone);
|
||||||
trashArray.push(clone);
|
trashArray.push(clone);
|
||||||
spawn(clone);
|
spawn(clone, 0.2);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
loader.load('assets/models/tree.glb', (gltf) => {
|
||||||
|
const mesh = gltf.scene;
|
||||||
|
mesh.scale.set(4, 4, 4);
|
||||||
|
console.log(mesh);
|
||||||
|
|
||||||
|
function spawn(obj, radius, minDistance) {
|
||||||
|
const points = [];
|
||||||
|
const attempts = 1000; // Numero massimo di tentativi per trovare un punto valido
|
||||||
|
for (let i = 0; i < attempts; i++) {
|
||||||
|
let angle = Math.random() * 2 * Math.PI;
|
||||||
|
let dist = Math.random() * radius;
|
||||||
|
let x = dist * Math.cos(angle);
|
||||||
|
let z = dist * Math.sin(angle);
|
||||||
|
let valid = true;
|
||||||
|
for (let j = 0; j < points.length; j++) {
|
||||||
|
const dx = x - points[j].x;
|
||||||
|
const dz = z - points[j].z;
|
||||||
|
const distance = Math.sqrt(dx * dx + dz * dz);
|
||||||
|
if (distance < minDistance) {
|
||||||
|
valid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (valid) {
|
||||||
|
points.push({ x: x, z: z });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawna gli alberi nei punti generati
|
||||||
|
for (let i = 0; i < points.length; i++) {
|
||||||
|
const clone = obj.clone();
|
||||||
|
const a = Math.random() * Math.PI * 2;
|
||||||
|
const r = Math.random() * 18;
|
||||||
|
const x = Math.cos(a) * r;
|
||||||
|
const z = Math.sin(a) * r;
|
||||||
|
// Y deve essere altezzaIsola + un piccolo offset
|
||||||
|
clone.position.set(points[i].x, altezzaIsola - 0.1, points[i].z);
|
||||||
|
clone.rotation.y = Math.random() * Math.PI * 2; // Rotazione tra 0 e 360 gradi
|
||||||
|
scene.add(clone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spawn(mesh, 18, 8); // Raggio 18, distanza minima 5
|
||||||
|
});
|
||||||
|
console.log(scene)
|
||||||
|
|
||||||
function spawn(obj) {
|
function spawn(obj) {
|
||||||
const a = Math.random() * Math.PI * 2;
|
const a = Math.random() * Math.PI * 2;
|
||||||
const r = Math.random() * 18;
|
const r = Math.random() * 18;
|
||||||
obj.position.set(Math.cos(a) * r, 0.3, Math.sin(a) * r);
|
const x = Math.cos(a) * r;
|
||||||
|
const z = Math.sin(a) * r;
|
||||||
|
// Y deve essere altezzaIsola + un piccolo offset
|
||||||
|
obj.position.set(x, altezzaIsola + 0.1, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. MOVIMENTO E COLLISIONI
|
// 5. MOVIMENTO E COLLISIONI
|
||||||
|
const arrow = false;
|
||||||
const keys = {};
|
const keys = {};
|
||||||
document.onkeydown = (e) => keys[e.code] = true;
|
document.onkeydown = (e) => keys[e.code] = true;
|
||||||
document.onkeyup = (e) => keys[e.code] = false;
|
document.onkeyup = (e) => keys[e.code] = false;
|
||||||
|
|
||||||
|
// Setup Raycaster (fuori dal loop animate)
|
||||||
|
const raycaster = new THREE.Raycaster();
|
||||||
|
const downVector = new THREE.Vector3(0, -1, 0);
|
||||||
|
|
||||||
|
// --- CONFIGURAZIONE MOVIMENTO ---
|
||||||
|
let canLeaveIsland = false; // Se false, l'acqua blocca il movimento.
|
||||||
|
let lastSafePosition = camera.position.clone();
|
||||||
|
|
||||||
function animate() {
|
function animate() {
|
||||||
requestAnimationFrame(animate);
|
requestAnimationFrame(animate);
|
||||||
if (controls.isLocked) {
|
|
||||||
if (keys['KeyW']) controls.moveForward(0.15);
|
|
||||||
if (keys['KeyS']) controls.moveForward(-0.15);
|
|
||||||
if (keys['KeyA']) controls.moveRight(-0.15);
|
|
||||||
if (keys['KeyD']) controls.moveRight(0.15);
|
|
||||||
camera.position.y = 1.6;
|
|
||||||
|
|
||||||
// Controllo collisioni
|
if (controls.isLocked) {
|
||||||
const pPos = camera.position.clone();
|
// 1. Salva la posizione attuale prima del movimento
|
||||||
pPos.y -= 1.0;
|
const oldPos = camera.position.clone();
|
||||||
|
|
||||||
|
// 2. Esegui il movimento WASD
|
||||||
|
if (arrow) {
|
||||||
|
if (keys['ArrowUp']) controls.moveForward(0.15);
|
||||||
|
if (keys['ArrowDown']) controls.moveForward(-0.15);
|
||||||
|
if (keys['ArrowLeft']) controls.moveRight(-0.15);
|
||||||
|
if (keys['ArrowRight']) controls.moveRight(0.15);
|
||||||
|
} else {
|
||||||
|
if (keys['KeyW']) controls.moveForward(0.15);
|
||||||
|
if (keys['KeyS']) controls.moveForward(-0.15);
|
||||||
|
if (keys['KeyA']) controls.moveRight(-0.15);
|
||||||
|
if (keys['KeyD']) controls.moveRight(0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. --- GESTIONE ALTEZZA DINAMICA ---
|
||||||
|
const rayOrigin = camera.position.clone();
|
||||||
|
rayOrigin.y = 10; // Spara dall'alto verso il basso
|
||||||
|
raycaster.set(rayOrigin, downVector);
|
||||||
|
|
||||||
|
// Controlliamo Prato e Sabbia
|
||||||
|
const intersects = raycaster.intersectObjects([grass, sand]);
|
||||||
|
|
||||||
|
if (intersects.length > 0) {
|
||||||
|
// Logica del "Punto più alto":
|
||||||
|
// Se il raggio colpisce sia prato che sabbia, prendiamo il prato.
|
||||||
|
let highestPoint = -Infinity;
|
||||||
|
for (let i = 0; i < intersects.length; i++) {
|
||||||
|
if (intersects[i].point.y > highestPoint) {
|
||||||
|
highestPoint = intersects[i].point.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Applichiamo l'altezza alla camera
|
||||||
|
camera.position.y = highestPoint + altezzaOcchi;
|
||||||
|
|
||||||
|
// --- CONTROLLO BARRIERA ACQUA ---
|
||||||
|
// Se il punto più alto è sotto il livello del mare (0)
|
||||||
|
// e non possiamo uscire, blocchiamo il movimento
|
||||||
|
if (!canLeaveIsland && highestPoint < 0) {
|
||||||
|
camera.position.x = oldPos.x;
|
||||||
|
camera.position.z = oldPos.z;
|
||||||
|
camera.position.y = oldPos.y;
|
||||||
|
} else {
|
||||||
|
// Posizione valida, la salviamo
|
||||||
|
lastSafePosition.copy(camera.position);
|
||||||
|
camera.position.y = camera.position.y > (-2.25 + altezzaOcchi) ? camera.position.y : (-2.25 + altezzaOcchi);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// --- FUORI DALL'ISOLA (VUOTO) ---
|
||||||
|
if (!canLeaveIsland) {
|
||||||
|
camera.position.copy(oldPos);
|
||||||
|
} else {
|
||||||
|
camera.position.y = -2.25 + altezzaOcchi; // Volo sull'acqua
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- COLLISIONI RIFIUTI ---
|
||||||
trashArray.forEach(t => {
|
trashArray.forEach(t => {
|
||||||
if (new THREE.Box3().setFromObject(t).expandByScalar(0.3).containsPoint(pPos)) {
|
if (camera.position.distanceTo(t.position) < 1.8) {
|
||||||
score++;
|
score++;
|
||||||
document.getElementById('score').innerText = score;
|
document.getElementById('score').innerText = score;
|
||||||
spawn(t);
|
spawn(t);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.render(scene, camera);
|
renderer.render(scene, camera);
|
||||||
}
|
}
|
||||||
animate();
|
document.getElementById("minuti").innerHTML = String(Math.floor(window.totalTime / 60)).padStart(2, '0');
|
||||||
|
document.getElementById("secondi").innerHTML = String(window.totalTime % 60).padStart(2, '0');
|
||||||
@@ -75,6 +75,9 @@ Workflow del gioco:
|
|||||||
```
|
```
|
||||||
Inizio -> 60s per raccogliere i rifiuti -> Salvataggio del punteggio in localStorage -> Schermata intermedia -> <punteggio>*5s per separare i rifiuti -> Invio dati della partita al database (nome squadra, rifiuti raccolti nella fase 1, rifiuti separati correttamente nella fase 2, punteggio finale, data della partita) -> caricamento schermata finale con classifica ridotta (posizione, squadra, punteggio) e pulsanti per giocare ancora, impostazioni e la classifica completa (classifica.php) con tutti i dati e tutte le partite giocate (classifica ridotta: solo le prime 5/10 partite)
|
Inizio -> 60s per raccogliere i rifiuti -> Salvataggio del punteggio in localStorage -> Schermata intermedia -> <punteggio>*5s per separare i rifiuti -> Invio dati della partita al database (nome squadra, rifiuti raccolti nella fase 1, rifiuti separati correttamente nella fase 2, punteggio finale, data della partita) -> caricamento schermata finale con classifica ridotta (posizione, squadra, punteggio) e pulsanti per giocare ancora, impostazioni e la classifica completa (classifica.php) con tutti i dati e tutte le partite giocate (classifica ridotta: solo le prime 5/10 partite)
|
||||||
```
|
```
|
||||||
|
```
|
||||||
|
start -> mid -> sep -> end
|
||||||
|
```
|
||||||
|
|
||||||
Indirizzamento pagine in index.php
|
Indirizzamento pagine in index.php
|
||||||
```
|
```
|
||||||
|
|||||||
+28
-6
@@ -6,32 +6,54 @@
|
|||||||
<link rel="stylesheet" href="css/fase1.css">
|
<link rel="stylesheet" href="css/fase1.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="assets/media/video/background.mp4" type="video/mp4">
|
||||||
</video>
|
</video>
|
||||||
<div class="overlay"></div>
|
<div class="overlay"></div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="top-section">
|
<div class="top-section">
|
||||||
<img src="./img/titolo.png" alt="titolo" class="main-title" />
|
<img src="assets/media/img/titolo.png" alt="titolo" class="main-title" />
|
||||||
</div>
|
</div>
|
||||||
<div class="container bottom-section">
|
<div class="container bottom-section">
|
||||||
<div class="item left">
|
<div class="item left">
|
||||||
<div class="controls-box">
|
<div class="controls-box">
|
||||||
<h3>Controlli</h3>
|
<h3>Controlli</h3>
|
||||||
<p><kbd>W</kbd><kbd>A</kbd><kbd>S</kbd><kbd>D</kbd> Movimento</p>
|
<p>Movimento</p>
|
||||||
<p><kbd>Mouse</kbd> Camera</p>
|
<p><kbd>Freccia su / W</kbd> Avanti</p>
|
||||||
|
<p><kbd>Freccia giù / S</kbd> Indietro</p>
|
||||||
|
<p><kbd>Freccia destra / D</kbd> Destra</p>
|
||||||
|
<p><kbd>Freccia sinistra / A</kbd> Sinistra</p>
|
||||||
|
<p><kbd>Mouse</kbd> Punto di vista</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item center">
|
<div class="item center">
|
||||||
<span class="pulse-text">Clicca per giocare</span>
|
<span class="pulse-text">Clicca per giocare</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="item right"></div>
|
<div class="item right">
|
||||||
|
<div class="instructions-box">
|
||||||
|
<h3>Istruzioni</h3>
|
||||||
|
<p>Obiettivo: raccogliere tutti i rifiuti sull’isola</p>
|
||||||
|
<p>Attenzione allo scadere del tempo!</p>
|
||||||
|
<p>Usa i comandi per esplorare e ripulire</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</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">
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user