Add initial game setup with Three.js, including scene, camera, and controls
@@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="it">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Semplice Island FPS</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="start">
|
||||||
|
<img src="./img/titolo.png" alt="titolo" />
|
||||||
|
<div class="container">
|
||||||
|
<div class="left">ISTRUZIONI</div>
|
||||||
|
<div class="center">Clicca per giocare</div>
|
||||||
|
<div class="right"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="punti">Rifiuti: <span id="score">0</span></div>
|
||||||
|
<div id="tempo">Tempo: <span id="time">XX:XX</span></div>
|
||||||
|
<script type="importmap">
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"three": "https://unpkg.com/three@0.160.0/build/three.module.js",
|
||||||
|
"three/addons/": "https://unpkg.com/three@0.160.0/examples/jsm/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script type="module" src="script.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
TODO:
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
<mxfile host="simonez-cloud.ddns.net" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36" version="29.5.2">
|
||||||
|
<diagram name="Page-1" id="i5RDAsyKeYJ5rP6QEPLP">
|
||||||
|
<mxGraphModel dx="1026" dy="507" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||||
|
<root>
|
||||||
|
<mxCell id="0" />
|
||||||
|
<mxCell id="1" parent="0" />
|
||||||
|
<mxCell id="hKNONnDbWQ7ccftNSymI-2" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" value="" vertex="1">
|
||||||
|
<mxGeometry height="440" width="680" x="80" y="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="hKNONnDbWQ7ccftNSymI-5" parent="1" style="ellipse;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" value="" vertex="1">
|
||||||
|
<mxGeometry height="370" width="440" x="190" y="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="hKNONnDbWQ7ccftNSymI-3" parent="1" style="ellipse;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" value="" vertex="1">
|
||||||
|
<mxGeometry height="340" width="400" x="220" y="80" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="hKNONnDbWQ7ccftNSymI-4" parent="1" style="ellipse;whiteSpace=wrap;html=1;fillColor=#AEBEAD;strokeColor=#567441;" value="" vertex="1">
|
||||||
|
<mxGeometry height="90" width="134" x="400" y="190" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="hKNONnDbWQ7ccftNSymI-6" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="N° rifiuti" vertex="1">
|
||||||
|
<mxGeometry height="50" width="90" x="80" y="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="hKNONnDbWQ7ccftNSymI-7" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="tempo" vertex="1">
|
||||||
|
<mxGeometry height="50" width="70" x="690" y="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="hKNONnDbWQ7ccftNSymI-8" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontColor=#333333;" value="" vertex="1">
|
||||||
|
<mxGeometry height="440" width="680" x="80" y="600" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="hKNONnDbWQ7ccftNSymI-9" parent="1" style="whiteSpace=wrap;html=1;aspect=fixed;" value="plastica" vertex="1">
|
||||||
|
<mxGeometry height="110" width="110" x="100" y="810" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="hKNONnDbWQ7ccftNSymI-10" parent="1" style="whiteSpace=wrap;html=1;aspect=fixed;" value="umido" vertex="1">
|
||||||
|
<mxGeometry height="110" width="110" x="230" y="810" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="hKNONnDbWQ7ccftNSymI-11" parent="1" style="whiteSpace=wrap;html=1;aspect=fixed;" value="indifferenziata" vertex="1">
|
||||||
|
<mxGeometry height="110" width="110" x="365" y="810" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="hKNONnDbWQ7ccftNSymI-12" parent="1" style="whiteSpace=wrap;html=1;aspect=fixed;" value="vetro" vertex="1">
|
||||||
|
<mxGeometry height="110" width="110" x="500" y="810" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="hKNONnDbWQ7ccftNSymI-13" parent="1" style="whiteSpace=wrap;html=1;aspect=fixed;" value="carta" vertex="1">
|
||||||
|
<mxGeometry height="110" width="110" x="630" y="810" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="hKNONnDbWQ7ccftNSymI-14" parent="1" style="whiteSpace=wrap;html=1;aspect=fixed;" value="aulliminio" vertex="1">
|
||||||
|
<mxGeometry height="80" width="80" x="115" y="940" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="hKNONnDbWQ7ccftNSymI-15" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="tempo" vertex="1">
|
||||||
|
<mxGeometry height="30" width="60" x="390" y="610" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="hKNONnDbWQ7ccftNSymI-16" parent="1" style="whiteSpace=wrap;html=1;aspect=fixed;" value="immagine rifiuto" vertex="1">
|
||||||
|
<mxGeometry height="120" width="120" x="360" y="650" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="hKNONnDbWQ7ccftNSymI-17" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="punteggio" vertex="1">
|
||||||
|
<mxGeometry height="30" width="60" x="90" y="610" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</root>
|
||||||
|
</mxGraphModel>
|
||||||
|
</diagram>
|
||||||
|
</mxfile>
|
||||||
|
After Width: | Height: | Size: 59 KiB |
@@ -0,0 +1,6 @@
|
|||||||
|
posizioni: 20 posizioni predefinite scelte random
|
||||||
|
tempo 1° fase: 1m
|
||||||
|
tempo 2° fase: 5s * punteggio
|
||||||
|
schermata iniziale: click + controlli + bckg trailer (loop video) + titolo
|
||||||
|
schermata intermedia: istruzioni
|
||||||
|
schermata finale: punteggio finale + record + classifica(?)
|
||||||
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,87 @@
|
|||||||
|
import * as THREE from 'three';
|
||||||
|
import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js';
|
||||||
|
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
|
||||||
|
|
||||||
|
// 1. SCENA E CAMERA
|
||||||
|
const scene = new THREE.Scene();
|
||||||
|
scene.background = new THREE.Color(0x87ceeb);
|
||||||
|
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
||||||
|
const renderer = new THREE.WebGLRenderer();
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
|
document.body.appendChild(renderer.domElement);
|
||||||
|
window.addEventListener('resize', function () {
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 2. LUCI E AMBIENTE
|
||||||
|
scene.add(new THREE.AmbientLight(0xffffff, 1));
|
||||||
|
const island = new THREE.Mesh(new THREE.CircleGeometry(20, 32), new THREE.MeshStandardMaterial({ color: 0x4df556 })); // #4df555
|
||||||
|
island.rotation.x = -Math.PI / 2;
|
||||||
|
scene.add(island);
|
||||||
|
|
||||||
|
// 3. CONTROLLI
|
||||||
|
function lock() {
|
||||||
|
document.getElementById('start').style.display = 'none';
|
||||||
|
document.getElementById('punti').style.display = 'block';
|
||||||
|
document.getElementById('tempo').style.display = 'block';
|
||||||
|
}
|
||||||
|
function unlock() {
|
||||||
|
document.getElementById('start').style.display = 'flex';
|
||||||
|
document.getElementById('punti').style.display = 'none';
|
||||||
|
document.getElementById('tempo').style.display = 'none';
|
||||||
|
}
|
||||||
|
const controls = new PointerLockControls(camera, document.body);
|
||||||
|
document.getElementById('start').addEventListener('click', () => controls.lock());
|
||||||
|
controls.addEventListener('lock', lock);
|
||||||
|
controls.addEventListener('unlock', unlock);
|
||||||
|
|
||||||
|
// 4. GESTIONE RIFIUTI (20 pezzi)
|
||||||
|
const trashArray = [];
|
||||||
|
let score = 0;
|
||||||
|
const loader = new GLTFLoader();
|
||||||
|
|
||||||
|
loader.load('models/rifiuto.glb', (gltf) => {
|
||||||
|
const mesh = gltf.scene.getObjectByName("Trash_Pile_03_GEO");
|
||||||
|
mesh.geometry.center(); // Centra l'oggetto per collisioni precise
|
||||||
|
for (let i = 0; i < 20; i++) {
|
||||||
|
const clone = mesh.clone();
|
||||||
|
scene.add(clone);
|
||||||
|
trashArray.push(clone);
|
||||||
|
spawn(clone);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function spawn(obj) {
|
||||||
|
const a = Math.random() * Math.PI * 2;
|
||||||
|
const r = Math.random() * 18;
|
||||||
|
obj.position.set(Math.cos(a) * r, 0.3, Math.sin(a) * r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. MOVIMENTO E COLLISIONI
|
||||||
|
const keys = {};
|
||||||
|
document.onkeydown = (e) => keys[e.code] = true;
|
||||||
|
document.onkeyup = (e) => keys[e.code] = false;
|
||||||
|
|
||||||
|
function 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
|
||||||
|
const pPos = camera.position.clone();
|
||||||
|
pPos.y -= 1.0;
|
||||||
|
trashArray.forEach(t => {
|
||||||
|
if (new THREE.Box3().setFromObject(t).expandByScalar(0.3).containsPoint(pPos)) {
|
||||||
|
score++;
|
||||||
|
document.getElementById('score').innerText = score;
|
||||||
|
spawn(t);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
}
|
||||||
|
animate();
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
:root {
|
||||||
|
--top: 10px;
|
||||||
|
--border: 20px;
|
||||||
|
--text: 1.5rem;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
#punti {
|
||||||
|
position: absolute;
|
||||||
|
top: var(--top);
|
||||||
|
left: var(--border);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#start {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0,0,0,0.5);
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 16 MiB |
|
After Width: | Height: | Size: 16 MiB |
|
After Width: | Height: | Size: 4.7 MiB |
|
After Width: | Height: | Size: 14 MiB |
|
After Width: | Height: | Size: 13 MiB |