From ae3eb34c0ec45200301259932a3bd60f73a9d17a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Untersch=C3=BCtz?= Date: Thu, 4 Dec 2025 23:21:01 +0100 Subject: [PATCH] fix texturen --- static/js/main.js | 72 +++++++++++++++++++++++++++------------------ static/js/render.js | 61 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 102 insertions(+), 31 deletions(-) diff --git a/static/js/main.js b/static/js/main.js index 95aea8b..2b792d5 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -4,44 +4,60 @@ // ========================================== // 1. ASSETS LADEN (PIXI V8 KORREKT) // ========================================== +// ========================================== +// 1. ASSETS LADEN (FEHLERTOLERANT) +// ========================================== async function loadAssets() { - const keysToLoad = []; + const assetsToLoad = []; - // A. Player hinzufügen - PIXI.Assets.add({ alias: 'player', src: 'assets/player.png' }); - keysToLoad.push('player'); + // --- 1. REGISTRIEREN (Namen zu Pfaden zuordnen) --- - // B. Hintergründe aus Config - if (gameConfig.backgrounds) { - gameConfig.backgrounds.forEach(bg => { - // Alias = Dateiname (z.B. "school-background.jpg") - PIXI.Assets.add({ alias: bg, src: 'assets/' + bg }); - keysToLoad.push(bg); - }); + // A. Player + // Prüfen ob schon da, um Warnungen bei Hot-Reload zu vermeiden + if (!PIXI.Assets.cache.has('player')) { + PIXI.Assets.add({ alias: 'player', src: 'assets/player.png' }); + assetsToLoad.push('player'); } - // C. Hindernisse aus Config - if (gameConfig.obstacles) { - gameConfig.obstacles.forEach(def => { - if (def.image) { - // Alias = ID (z.B. "teacher") - // Checken ob Alias schon existiert (vermeidet Warnungen) - if (!PIXI.Assets.cache.has(def.id)) { - PIXI.Assets.add({ alias: def.id, src: 'assets/' + def.image }); - keysToLoad.push(def.id); - } + // B. Hintergründe + if (gameConfig.backgrounds) { + gameConfig.backgrounds.forEach(bg => { + if (!PIXI.Assets.cache.has(bg)) { + PIXI.Assets.add({ alias: bg, src: 'assets/' + bg }); + assetsToLoad.push(bg); } }); } - try { - console.log("Lade Assets...", keysToLoad); - // Alles auf einmal laden - await PIXI.Assets.load(keysToLoad); - console.log("✅ Alle Texturen geladen!"); - } catch (e) { - console.error("❌ Asset Fehler:", e); + // C. Hindernisse + if (gameConfig.obstacles) { + gameConfig.obstacles.forEach(def => { + if (def.image && !PIXI.Assets.cache.has(def.id)) { + PIXI.Assets.add({ alias: def.id, src: 'assets/' + def.image }); + assetsToLoad.push(def.id); + } + }); } + + // --- 2. LADEN (Mit Fehler-Abfangung) --- + console.log(`Lade ${assetsToLoad.length} Assets...`); + + // Wir erstellen für jedes Asset einen eigenen Lade-Versuch + const loadPromises = assetsToLoad.map(key => { + return PIXI.Assets.load(key) + .catch(err => { + // HIER IST DER TRICK: + // Wenn ein Fehler passiert, loggen wir ihn, aber werfen ihn NICHT weiter. + // Wir geben einfach null zurück. Damit gilt dieser Task als "erledigt". + console.warn(`⚠️ Asset Fehler bei '${key}': Datei fehlt oder defekt.`); + return null; + }); + }); + + // Wir warten, bis ALLE Versuche durch sind (egal ob Erfolg oder Fehler) + await Promise.all(loadPromises); + + console.log("✅ Ladevorgang abgeschlossen (vorhandene Assets sind bereit)."); } // ... (Rest der Datei: startGameClick, gameLoop etc. BLEIBT GLEICH) diff --git a/static/js/render.js b/static/js/render.js index 95451f7..3aca5cf 100644 --- a/static/js/render.js +++ b/static/js/render.js @@ -116,20 +116,37 @@ function syncSprites(dataList, cacheMap, type, alpha) { usedObjects.add(obj); let sprite = cacheMap.get(obj); - // A. Erstellen (wenn neu) if (!sprite) { sprite = createPixiSprite(obj, type); gameLayer.addChild(sprite); cacheMap.set(obj, sprite); } - // B. Updaten (Interpolation) const def = obj.def || {}; - // Position interpolieren const rX = (obj.prevX !== undefined) ? lerp(obj.prevX, obj.x, alpha) : obj.x; const rY = obj.y; + if (obj.speech) { + let bubble = sprite.children.find(c => c.label === "bubble"); + + if (!bubble) { + bubble = createSpeechBubble(obj.speech); + bubble.y = -10; + if (def.height) bubble.y = -5; + + sprite.addChild(bubble); + } + + } else { + // Keine Sprache mehr? Blase entfernen falls vorhanden + const bubble = sprite.children.find(c => c.label === "bubble"); + if (bubble) { + sprite.removeChild(bubble); + bubble.destroy(); + } + } + if (type === 'platform') { sprite.x = rX; sprite.y = rY; @@ -264,4 +281,42 @@ function drawDebugOverlay(alpha) { const rX = (o.prevX !== undefined) ? lerp(o.prevX, o.x, alpha) : o.x; g.rect(rX, o.y, def.width||30, def.height||30).stroke({ width: 1, color: 0x00FF00 }); }); +} + +// Helper: Erstellt eine Pixi-Sprechblase +function createSpeechBubble(text) { + const container = new PIXI.Container(); + + // 1. Text erstellen + const style = new PIXI.TextStyle({ + fontFamily: 'monospace', + fontSize: 12, + fontWeight: 'bold', + fill: '#000000', + align: 'center' + }); + + const pixiText = new PIXI.Text({ text: text, style: style }); + pixiText.anchor.set(0.5); // Text-Mitte ist Anker + + // Maße berechnen + const w = pixiText.width + 10; + const h = pixiText.height + 6; + + // 2. Hintergrund (Blase) + const g = new PIXI.Graphics(); + g.rect(-w/2, -h/2, w, h).fill(0xFFFFFF); // Weißer Kasten + g.rect(-w/2, -h/2, w, h).stroke({ width: 2, color: 0x000000 }); // Schwarzer Rand + + // Kleines Dreieck unten (optional, für den "Speech"-Look) + g.moveTo(-5, h/2).lineTo(0, h/2 + 5).lineTo(5, h/2).fill(0xFFFFFF); + + // Zusammenfügen + container.addChild(g); + container.addChild(pixiText); + + // Name setzen, damit wir es später wiederfinden + container.label = "bubble"; + + return container; } \ No newline at end of file