Add initial game setup with Three.js, including scene, camera, and controls

This commit is contained in:
Simone
2026-03-07 17:12:57 +01:00
parent 211b13e2fe
commit fcd3d1a7e5
14 changed files with 222 additions and 0 deletions
Executable
+29
View File
@@ -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>
BIN
View File
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
TODO:
+58
View File
@@ -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>
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

+6
View File
@@ -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(?)
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Executable
+87
View File
@@ -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();
Executable
+41
View File
@@ -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;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 MiB