Refactor app.js to improve readability and organization

This commit is contained in:
2025-05-28 03:15:51 +02:00
parent 85cbc28981
commit 3987000517

View File

@@ -8,7 +8,7 @@ import { UnrealBloomPass } from 'https://cdn.jsdelivr.net/npm/three@0.155.0/exam
import { GammaCorrectionShader } from 'https://cdn.jsdelivr.net/npm/three@0.155.0/examples/jsm/shaders/GammaCorrectionShader.js'; import { GammaCorrectionShader } from 'https://cdn.jsdelivr.net/npm/three@0.155.0/examples/jsm/shaders/GammaCorrectionShader.js';
import { VignetteShader } from "https://cdn.jsdelivr.net/npm/three@0.155.0/examples/jsm/shaders/VignetteShader.js"; import { VignetteShader } from "https://cdn.jsdelivr.net/npm/three@0.155.0/examples/jsm/shaders/VignetteShader.js";
// ---- BASIS Three.js Szene ---- // ---- Basis Three.js Szene ----
const scene = new THREE.Scene(); const scene = new THREE.Scene();
const ASPECT = 3/2, SCALE = 15; const ASPECT = 3/2, SCALE = 15;
const hw = SCALE/2, hh = (SCALE/ASPECT)/2; const hw = SCALE/2, hh = (SCALE/ASPECT)/2;
@@ -23,7 +23,7 @@ renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; renderer.shadowMap.type = THREE.PCFSoftShadowMap;
container.appendChild(renderer.domElement); container.appendChild(renderer.domElement);
// ---- POSTPROCESSING // ---- Postprocessing ----
const foliageTexture = new THREE.TextureLoader().load('assets/sprites/foliage.png'); const foliageTexture = new THREE.TextureLoader().load('assets/sprites/foliage.png');
foliageTexture.colorSpace = THREE.SRGBColorSpace; foliageTexture.colorSpace = THREE.SRGBColorSpace;
const FoliageOverlayShader = { const FoliageOverlayShader = {
@@ -63,7 +63,7 @@ vignettePass.uniforms['darkness'].value = 1.35;
composer.addPass(vignettePass); composer.addPass(vignettePass);
composer.addPass(new ShaderPass(GammaCorrectionShader)); composer.addPass(new ShaderPass(GammaCorrectionShader));
// ---- Resize // ---- Resize Handler ----
function onResize(){ function onResize(){
const W=container.clientWidth, H=container.clientHeight, winA=W/H; const W=container.clientWidth, H=container.clientHeight, winA=W/H;
let vw,vh,vx,vy; let vw,vh,vx,vy;
@@ -88,7 +88,7 @@ function onResize(){
window.addEventListener('resize',onResize); window.addEventListener('resize',onResize);
onResize(); onResize();
// ---- Environment Map // ---- Environment Map ----
const texLoader = new THREE.TextureLoader(); const texLoader = new THREE.TextureLoader();
const pmremGen = new THREE.PMREMGenerator(renderer); const pmremGen = new THREE.PMREMGenerator(renderer);
texLoader.load('assets/hdri/environment.jpg', tex => { texLoader.load('assets/hdri/environment.jpg', tex => {
@@ -119,7 +119,7 @@ draco.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.5.6/');
const gltfLoader = new GLTFLoader(); const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(draco); gltfLoader.setDRACOLoader(draco);
// ---- Utility: GLBs laden (für Grundszene) ---- // ---- Utility: GLBs laden ----
async function loadGLB(path, pos, rotDeg, {receiveShadow=false, castShadow=false, emissive=null, visible=true, shadowOnly=false} = {}) { async function loadGLB(path, pos, rotDeg, {receiveShadow=false, castShadow=false, emissive=null, visible=true, shadowOnly=false} = {}) {
const { scene: obj } = await gltfLoader.loadAsync(path); const { scene: obj } = await gltfLoader.loadAsync(path);
obj.position.set(pos[0], pos[1], pos[2]); obj.position.set(pos[0], pos[1], pos[2]);
@@ -209,8 +209,11 @@ const clock = new THREE.Clock();
animate(); animate();
})(); })();
// ---- SPIRIT-KLASSE (aus alter Version, leicht adaptiert) // ---- Spirit-Instanzen-Array (mehrere gleichzeitig!)
const MOVE_SPEED = 1; // wie im Original const activeSpirits = [];
// ---- Spirit-Klasse ----
const MOVE_SPEED = 1;
class Spirit { class Spirit {
constructor(obj3d, info) { constructor(obj3d, info) {
this.clock = new THREE.Clock(); this.clock = new THREE.Clock();
@@ -220,9 +223,8 @@ class Spirit {
this.info = info || {}; this.info = info || {};
this.grp.add(obj3d); this.grp.add(obj3d);
// Positionierung + Drehung wie im Original // Rotation & Position wie im Original
obj3d.rotation.x = -Math.PI; obj3d.rotation.x = -Math.PI;
// Setze Position unterhalb Spinner (nutze aktuelle Spinner-Position)
let y = spinnerRed ? spinnerRed.position.y - 1.5 : 15; let y = spinnerRed ? spinnerRed.position.y - 1.5 : 15;
this.grp.position.set(0, y, 0.88 - 0.6); this.grp.position.set(0, y, 0.88 - 0.6);
@@ -265,8 +267,9 @@ class Spirit {
} }
// Bewegung nach unten // Bewegung nach unten
this.grp.position.y -= MOVE_SPEED * dt; this.grp.position.y -= MOVE_SPEED * dt;
if (t > 15) { // LEBENSDAUER 20 Sekunden
scene.remove(this.grp); if (t > 20) {
this.dispose();
return false; return false;
} }
return true; return true;
@@ -285,11 +288,9 @@ class Spirit {
} }
// ---- Render-Loop ---- // ---- Render-Loop ----
let currentSpirit = null;
window.currentSpirit = null;
function animate(){ function animate(){
const dt = clock.getDelta(), t = clock.getElapsedTime(); const dt = clock.getDelta(), t = clock.getElapsedTime();
// Spinner Animation // Spinner Animation
const bob = Math.sin(t*1.2)*0.5; const bob = Math.sin(t*1.2)*0.5;
const baseY = 16.55 + bob; const baseY = 16.55 + bob;
@@ -318,42 +319,37 @@ function animate(){
lightZ lightZ
); );
} }
// Spirit animieren/entfernen // Update & Entfernen aller aktiven Spirits
if (currentSpirit && currentSpirit.update) { for (let i = activeSpirits.length - 1; i >= 0; i--) {
if (!currentSpirit.update(dt)) { if (!activeSpirits[i].update(dt)) {
currentSpirit = null; activeSpirits.splice(i, 1);
window.currentSpirit = null;
} }
} }
composer.render(scene, camera); composer.render(scene, camera);
requestAnimationFrame(animate); requestAnimationFrame(animate);
} }
// ---- WebSocket-basierter Spirit Spawn ---- // ---- WebSocket: Spirit erzeugen, Infobox updaten ----
const ws = new WebSocket(`ws://${location.host}`); const ws = new WebSocket(`ws://${location.host}`);
ws.addEventListener('message', async (event) => { ws.addEventListener('message', async (event) => {
const msg = JSON.parse(event.data); const msg = JSON.parse(event.data);
if (msg.type === 'spirit') { if (msg.type === 'spirit') {
await showSpirit(msg.data); await spawnSpirit(msg.data);
} }
}); });
async function showSpirit(spirit) { async function spawnSpirit(spirit) {
if (currentSpirit) {
currentSpirit.dispose();
currentSpirit = null;
window.currentSpirit = null;
}
console.log("Lade Spirit", spirit.modelUrl); console.log("Lade Spirit", spirit.modelUrl);
// Modell laden // Modell laden
const { scene: spiritObj } = await gltfLoader.loadAsync(spirit.modelUrl); const { scene: spiritObj } = await gltfLoader.loadAsync(spirit.modelUrl);
// Spirit-Objekt mit Animation/Fading/Motion erzeugen! // Spirit-Objekt mit Animation/Fading/Motion erzeugen!
currentSpirit = new Spirit(spiritObj, spirit); const s = new Spirit(spiritObj, spirit);
window.currentSpirit = currentSpirit; activeSpirits.push(s);
// Overlay zeigt immer den aktuellsten
updateSpiritOverlay(spirit); updateSpiritOverlay(spirit);
} }