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) <noreply@anthropic.com>
This commit is contained in:
@@ -399,7 +399,7 @@ html, body {
|
|||||||
.hidden { display: none !important; }
|
.hidden { display: none !important; }
|
||||||
.overlay .card {
|
.overlay .card {
|
||||||
position: static;
|
position: static;
|
||||||
width: min(440px, 88vw);
|
width: min(680px, 92vw); /* breiter: iPad-Text ohne Scroll-Zwang */
|
||||||
max-height: 80vh;
|
max-height: 80vh;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
|
|||||||
@@ -233,7 +233,9 @@ export class IsoRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resize() {
|
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.dpr = dpr;
|
||||||
this.canvas.width = innerWidth * dpr;
|
this.canvas.width = innerWidth * dpr;
|
||||||
this.canvas.height = innerHeight * dpr;
|
this.canvas.height = innerHeight * dpr;
|
||||||
@@ -307,6 +309,7 @@ export class IsoRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setBuildType(type) {
|
setBuildType(type) {
|
||||||
|
this.pendingTile = null; // Touch-Vorschau verwerfen bei Werkzeugwechsel
|
||||||
this.buildType = type;
|
this.buildType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,7 +364,7 @@ export class IsoRenderer {
|
|||||||
if (wasTap) {
|
if (wasTap) {
|
||||||
this.vel.x = 0; this.vel.y = 0;
|
this.vel.x = 0; this.vel.y = 0;
|
||||||
const t = this.screenToTile(e.clientX, e.clientY);
|
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)
|
// sonst: Schwung aus der letzten Bewegung mitnehmen (Momentum)
|
||||||
};
|
};
|
||||||
@@ -1003,6 +1006,15 @@ export class IsoRenderer {
|
|||||||
|
|
||||||
// ---------- Zeichnen ----------
|
// ---------- Zeichnen ----------
|
||||||
draw(now, dt, speed = 0) {
|
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.time = now;
|
||||||
this.simSpeed = speed;
|
this.simSpeed = speed;
|
||||||
const simDt = dt * speed; // Spielzeit: Figuren, Lift, Bus …
|
const simDt = dt * speed; // Spielzeit: Figuren, Lift, Bus …
|
||||||
@@ -2422,7 +2434,8 @@ export class IsoRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_drawPreview() {
|
_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;
|
if (!t || !this.buildType) return;
|
||||||
const tile = this.state.map[t.r]?.[t.c];
|
const tile = this.state.map[t.r]?.[t.c];
|
||||||
if (!tile) return;
|
if (!tile) return;
|
||||||
|
|||||||
@@ -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
|
// Ohne Bau-Werkzeug: Gebäude anklicken öffnet den Report
|
||||||
if (!ui.activeBuild) {
|
if (!ui.activeBuild) {
|
||||||
if (state.map[r]?.[c]?.building) inspectBuilding(c, r);
|
if (state.map[r]?.[c]?.building) inspectBuilding(c, r);
|
||||||
@@ -133,6 +133,22 @@ function onTileTap(c, r) {
|
|||||||
}
|
}
|
||||||
const type = ui.activeBuild;
|
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);
|
const check = canPlace(state, type, c, r);
|
||||||
if (!check.ok) {
|
if (!check.ok) {
|
||||||
// Ablehnung erklärt IMMER auch die Bauregeln des Gebäudes
|
// Ablehnung erklärt IMMER auch die Bauregeln des Gebäudes
|
||||||
|
|||||||
Reference in New Issue
Block a user