From 6ca643f6285c8a12dc97de8024caaad32720ef2a Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 12 Jul 2026 16:55:35 +0200 Subject: [PATCH] Tourismustal: iPad-Runde 3 - Performance, Touch-Bauvorschau, breite Overlays - Performance ohne Sichtverlust: Retina-Faktor auf 1.5 gecappt (~45 % weniger GPU-Pixel), Framerate auf ~30 fps (Pause ohne Interaktion ~10 fps) - Simulation exakt, uebersprungene Zeit wird akkumuliert. iPad sollte deutlich kuehler bleiben. - Touch-Bauvorschau: erster Tipp heftet die volle Vorschau (gruen/rot, Pisten-/Strecken-Korridor, Einflusskreise) an die Kachel, zweiter Tipp auf DIESELBE Kachel baut. Maus behaelt Hover + Sofortbau. - Info-Overlays breiter (680px statt 440px) - weniger Scrollen. Co-Authored-By: Claude Opus 4.8 (1M context) --- App/sims/tourismustal/css/style.css | 2 +- App/sims/tourismustal/js/iso.js | 19 ++++++++++++++++--- App/sims/tourismustal/js/main.js | 18 +++++++++++++++++- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/App/sims/tourismustal/css/style.css b/App/sims/tourismustal/css/style.css index 2a447c5..aac948c 100644 --- a/App/sims/tourismustal/css/style.css +++ b/App/sims/tourismustal/css/style.css @@ -399,7 +399,7 @@ html, body { .hidden { display: none !important; } .overlay .card { position: static; - width: min(440px, 88vw); + width: min(680px, 92vw); /* breiter: iPad-Text ohne Scroll-Zwang */ max-height: 80vh; overflow-y: auto; padding: 24px; diff --git a/App/sims/tourismustal/js/iso.js b/App/sims/tourismustal/js/iso.js index 2f2f87e..b798c43 100644 --- a/App/sims/tourismustal/js/iso.js +++ b/App/sims/tourismustal/js/iso.js @@ -233,7 +233,9 @@ export class IsoRenderer { } resize() { - const dpr = window.devicePixelRatio || 1; + // Performance: Retina-Faktor auf 1.5 cappen – bei Flat-Design ohne + // sichtbaren Verlust, spart auf dem iPad fast die halbe GPU-Last. + const dpr = Math.min(1.5, window.devicePixelRatio || 1); this.dpr = dpr; this.canvas.width = innerWidth * dpr; this.canvas.height = innerHeight * dpr; @@ -307,6 +309,7 @@ export class IsoRenderer { } setBuildType(type) { + this.pendingTile = null; // Touch-Vorschau verwerfen bei Werkzeugwechsel this.buildType = type; } @@ -361,7 +364,7 @@ export class IsoRenderer { if (wasTap) { this.vel.x = 0; this.vel.y = 0; const t = this.screenToTile(e.clientX, e.clientY); - if (t) this.cb.onTileTap(t.c, t.r); + if (t) this.cb.onTileTap(t.c, t.r, e.pointerType); } // sonst: Schwung aus der letzten Bewegung mitnehmen (Momentum) }; @@ -1003,6 +1006,15 @@ export class IsoRenderer { // ---------- Zeichnen ---------- draw(now, dt, speed = 0) { + // Performance: ~30 fps reichen völlig (Pause: ~10 fps) – Simulation + // bleibt exakt, weil die übersprungene Zeit akkumuliert wird. + this._frameAcc = (this._frameAcc || 0) + dt; + const busy = this.pointers.size > 0 || this.zoomTarget + || Math.abs(this.vel.x) > 0.3 || Math.abs(this.vel.y) > 0.3; + const minInt = (speed === 0 && !busy) ? 95 : 31; + if (this._frameAcc < minInt) return; + dt = this._frameAcc; + this._frameAcc = 0; this.time = now; this.simSpeed = speed; const simDt = dt * speed; // Spielzeit: Figuren, Lift, Bus … @@ -2422,7 +2434,8 @@ export class IsoRenderer { } _drawPreview() { - const t = this.hoverTile; + // Touch: angeheftete Vorschau (erster Tipp) hat Vorrang vor Maus-Hover + const t = this.pendingTile || this.hoverTile; if (!t || !this.buildType) return; const tile = this.state.map[t.r]?.[t.c]; if (!tile) return; diff --git a/App/sims/tourismustal/js/main.js b/App/sims/tourismustal/js/main.js index 3c472cf..e3e1430 100644 --- a/App/sims/tourismustal/js/main.js +++ b/App/sims/tourismustal/js/main.js @@ -125,7 +125,7 @@ function inspectBuilding(c, r) { }); } -function onTileTap(c, r) { +function onTileTap(c, r, pointerType) { // Ohne Bau-Werkzeug: Gebäude anklicken öffnet den Report if (!ui.activeBuild) { if (state.map[r]?.[c]?.building) inspectBuilding(c, r); @@ -133,6 +133,22 @@ function onTileTap(c, r) { } const type = ui.activeBuild; + // Touch (iPad): erster Tipp heftet die VORSCHAU an die Kachel (grün/rot, + // Pisten-/Strecken-Korridor, Einflusskreis) – erst der zweite Tipp auf + // DIESELBE Kachel baut. Mit Maus bleibt der Sofort-Bau (Hover zeigt ja). + if (pointerType !== 'mouse') { + const p = renderer.pendingTile; + if (!p || p.c !== c || p.r !== r) { + renderer.pendingTile = { c, r }; + if (!state.firedEvents.has('touch-build-hint')) { + state.firedEvents.add('touch-build-hint'); + ui.toast('👆 Vorschau gesetzt – tippe dieselbe Stelle nochmal an, um zu bauen.', 5000); + } + return; + } + renderer.pendingTile = null; + } + const check = canPlace(state, type, c, r); if (!check.ok) { // Ablehnung erklärt IMMER auch die Bauregeln des Gebäudes