- Ein Klick faengt die Maus ein, danach dreht die blosse Mausbewegung den Blick. Maus nach rechts oben heisst Blick nach rechts oben. Esc gibt die Maus wieder frei, das Fadenkreuz zeigt den Zustand an. - Ohne Mausfang (direkt nach Esc oder wo er gesperrt ist, etwa in eingebetteten Vorschauen) dreht Ziehen den Blick in derselben Richtung - vorher zog man die Szene, was sich verkehrt anfuehlte. - Am Handy wischt man jetzt ebenfalls in die Blickrichtung statt dagegen. - Mit gefangener Maus fuehrt ein Klick zu dem Punkt unter dem Fadenkreuz, ohne Mausfang weiterhin zum angeklickten Punkt. - Beim Wechsel in die Uebersicht wird der Mausfang freigegeben. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -249,10 +249,16 @@ ursprünglichen Rechenzeit.
|
||||
|
||||
### Rundgang
|
||||
|
||||
Bewusst einfach: **auf den Boden klicken** (am Handy tippen), dann läuft man
|
||||
dorthin; **ziehen** zum Umsehen. Tastatur geht weiterhin (`W A S D`, `Shift`,
|
||||
`Leertaste` springt). Es gibt keinen Mausfang mehr – der Zeiger bleibt frei
|
||||
für die Bedienelemente.
|
||||
Umsehen wie in einem Ego-Shooter: **ein Klick fängt die Maus ein**, danach dreht
|
||||
schon die blosse Mausbewegung den Blick – Maus nach rechts oben heisst Blick
|
||||
nach rechts oben. `Esc` gibt die Maus wieder frei. Solange sie frei ist (direkt
|
||||
nach `Esc`, oder wenn der Mausfang gesperrt ist, etwa in eingebetteten
|
||||
Vorschauen), dreht **Ziehen** den Blick auf dieselbe Weise. Am Handy wischt man
|
||||
in die Richtung, in die man schauen will.
|
||||
|
||||
Gehen: `W A S D` oder Pfeiltasten, `Shift` rennt, `Leertaste` springt, am Handy
|
||||
der Joystick. Ein **Klick auf den Boden** (am Handy tippen) läuft dorthin – mit
|
||||
gefangener Maus zu dem Punkt unter dem Fadenkreuz.
|
||||
|
||||
Damit es nicht ruppig wirkt:
|
||||
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@
|
||||
<div id="crosshair"></div>
|
||||
|
||||
<div id="hint">
|
||||
<span class="desktop">Auf den Boden klicken: dorthin gehen · Ziehen: umsehen · <kbd>W</kbd><kbd>A</kbd><kbd>S</kbd><kbd>D</kbd> gehen · <kbd>Leertaste</kbd> springen</span>
|
||||
<span class="desktop">Klicken: Maus übernimmt den Blick · <kbd>W</kbd><kbd>A</kbd><kbd>S</kbd><kbd>D</kbd> gehen · <kbd>Leertaste</kbd> springen · <kbd>Esc</kbd> Maus freigeben</span>
|
||||
<span class="touch">Auf den Boden tippen: dorthin gehen · rechts wischen: umsehen</span>
|
||||
</div>
|
||||
|
||||
|
||||
+55
-18
@@ -1,11 +1,16 @@
|
||||
/**
|
||||
* Begehen des Gartens.
|
||||
*
|
||||
* Bewusst einfach gehalten:
|
||||
* - Umsehen: mit der Maus ziehen (am Handy rechts wischen). Kein Mausfang,
|
||||
* der Mauszeiger bleibt frei fuer die Bedienelemente.
|
||||
* - Gehen: W A S D oder Pfeiltasten, am Handy der Joystick - oder einfach
|
||||
* auf den Boden klicken bzw. tippen, dann laeuft man dorthin.
|
||||
* Umsehen wie in einem Ego-Shooter: ein Klick faengt die Maus ein, danach
|
||||
* dreht schon die blosse Mausbewegung den Blick - nach rechts oben heisst
|
||||
* nach rechts oben. `Esc` gibt die Maus wieder frei; solange sie frei ist,
|
||||
* dreht Ziehen mit gedrueckter Taste den Blick auf dieselbe Weise. Am Handy
|
||||
* wischt man in die Richtung, in die man schauen will.
|
||||
*
|
||||
* Weiter:
|
||||
* - Gehen: W A S D oder Pfeiltasten, am Handy der Joystick - oder auf den
|
||||
* Boden klicken bzw. tippen, dann laeuft man dorthin. Mit gefangener Maus
|
||||
* gilt der Klick dem Punkt unter dem Fadenkreuz.
|
||||
* - Leertaste springt.
|
||||
*
|
||||
* Damit es sich nicht ruppig anfuehlt, beschleunigt und bremst der Spieler
|
||||
@@ -62,12 +67,15 @@ export class Walker {
|
||||
private joystick = { x: 0, y: 0, active: false };
|
||||
private lookDelta = { x: 0, y: 0 };
|
||||
private enabled = true;
|
||||
private gefangen = false;
|
||||
/** Ziel fuer Klick-zum-Gehen. */
|
||||
private target: { x: number; z: number } | null = null;
|
||||
private stuck = 0;
|
||||
|
||||
/** Wird bei jedem neuen Gehziel aufgerufen (null = kein Ziel mehr). */
|
||||
onTarget?: (t: { x: number; z: number } | null) => void;
|
||||
/** Meldet, ob die Maus gerade gefangen ist (fuer Fadenkreuz und Hinweis). */
|
||||
onPointerLockChange?: (gefangen: boolean) => void;
|
||||
|
||||
constructor(camera: PerspectiveCamera, options: WalkerOptions) {
|
||||
this.camera = camera;
|
||||
@@ -84,7 +92,10 @@ export class Walker {
|
||||
|
||||
setEnabled(on: boolean) {
|
||||
this.enabled = on;
|
||||
if (!on) this.setTarget(null);
|
||||
if (!on) {
|
||||
this.setTarget(null);
|
||||
if (document.pointerLockElement) document.exitPointerLock();
|
||||
}
|
||||
}
|
||||
|
||||
teleport(x: number, z: number, yawDeg: number) {
|
||||
@@ -113,34 +124,61 @@ export class Walker {
|
||||
window.addEventListener('keyup', (e) => this.keys.delete(e.code));
|
||||
window.addEventListener('blur', () => this.keys.clear());
|
||||
|
||||
// Maus: ziehen = umsehen, kurzer Klick = dorthin gehen.
|
||||
// Maus: ein Klick faengt sie ein, danach dreht die Bewegung den Blick.
|
||||
// Ohne Mausfang (etwa direkt nach Esc oder in eingebetteten Vorschauen)
|
||||
// dreht Ziehen mit gedrueckter Taste genauso.
|
||||
const drehen = (dx: number, dy: number, staerke: number) => {
|
||||
// Nach rechts bewegen dreht nach rechts, nach oben hebt den Blick.
|
||||
this.lookDelta.x -= dx * staerke;
|
||||
this.lookDelta.y -= dy * staerke;
|
||||
};
|
||||
|
||||
document.addEventListener('pointerlockchange', () => {
|
||||
this.gefangen = document.pointerLockElement === dom;
|
||||
dom.style.cursor = this.gefangen ? 'none' : '';
|
||||
this.onPointerLockChange?.(this.gefangen);
|
||||
});
|
||||
document.addEventListener('mousemove', (e) => {
|
||||
if (!this.gefangen || !this.enabled) return;
|
||||
drehen(e.movementX, e.movementY, 0.0024);
|
||||
});
|
||||
|
||||
let down: { x: number; y: number; id: number } | null = null;
|
||||
let dragged = false;
|
||||
dom.addEventListener('pointerdown', (e) => {
|
||||
if (!this.enabled || e.pointerType !== 'mouse' || e.button !== 0) return;
|
||||
if (this.gefangen) { down = { x: 0, y: 0, id: e.pointerId }; dragged = false; return; }
|
||||
down = { x: e.clientX, y: e.clientY, id: e.pointerId };
|
||||
dragged = false;
|
||||
dom.setPointerCapture(e.pointerId);
|
||||
});
|
||||
dom.addEventListener('pointermove', (e) => {
|
||||
if (!down || e.pointerId !== down.id) return;
|
||||
if (this.gefangen || !down || e.pointerId !== down.id) return;
|
||||
if (!dragged && Math.hypot(e.clientX - down.x, e.clientY - down.y) > 5) dragged = true;
|
||||
if (dragged) {
|
||||
this.lookDelta.x += e.movementX * 0.0042;
|
||||
this.lookDelta.y += e.movementY * 0.0042;
|
||||
drehen(e.movementX, e.movementY, 0.0032);
|
||||
dom.style.cursor = 'grabbing';
|
||||
}
|
||||
});
|
||||
const up = (e: PointerEvent) => {
|
||||
if (!down || e.pointerId !== down.id) return;
|
||||
if (!dragged) this.walkTo(e.clientX, e.clientY);
|
||||
down = null;
|
||||
dom.style.cursor = '';
|
||||
dom.style.cursor = this.gefangen ? 'none' : '';
|
||||
if (dragged) return;
|
||||
if (this.gefangen) {
|
||||
// Mit gefangener Maus zielt das Fadenkreuz in der Bildmitte.
|
||||
this.walkTo(window.innerWidth / 2, window.innerHeight / 2);
|
||||
} else if (!isTouch()) {
|
||||
// In eingebetteten Vorschauen ist der Mausfang gesperrt - dann bleibt
|
||||
// es beim Ziehen, und der Klick fuehrt zum angeklickten Punkt.
|
||||
Promise.resolve(dom.requestPointerLock()).catch(() => this.walkTo(e.clientX, e.clientY));
|
||||
}
|
||||
};
|
||||
dom.addEventListener('pointerup', up);
|
||||
dom.addEventListener('pointercancel', () => { down = null; dom.style.cursor = ''; });
|
||||
dom.addEventListener('pointercancel', () => { down = null; dom.style.cursor = this.gefangen ? 'none' : ''; });
|
||||
|
||||
// Touch: rechts wischen = umsehen, tippen = dorthin gehen
|
||||
// Touch: rechts wischen = umsehen (in die Richtung, in die man schaut),
|
||||
// tippen = dorthin gehen
|
||||
let touchId: number | null = null;
|
||||
let last = { x: 0, y: 0 };
|
||||
let start = { x: 0, y: 0, t: 0 };
|
||||
@@ -158,8 +196,7 @@ export class Walker {
|
||||
if (!this.enabled) { touchId = null; return; }
|
||||
for (const t of Array.from(e.changedTouches)) {
|
||||
if (t.identifier !== touchId) continue;
|
||||
this.lookDelta.x += (t.clientX - last.x) * 0.006;
|
||||
this.lookDelta.y += (t.clientY - last.y) * 0.006;
|
||||
drehen(t.clientX - last.x, t.clientY - last.y, 0.006);
|
||||
last = { x: t.clientX, y: t.clientY };
|
||||
}
|
||||
}, { passive: true });
|
||||
@@ -190,8 +227,8 @@ export class Walker {
|
||||
update(dt: number) {
|
||||
if (!this.enabled) return;
|
||||
|
||||
// Blick: man zieht die Szene - wie in der Uebersicht und bei Street View.
|
||||
// Nach rechts ziehen dreht den Blick nach links, nach unten ziehen hebt ihn.
|
||||
// Blick: die Richtung wird in `drehen` gesetzt - Maus oder Finger nach
|
||||
// rechts dreht nach rechts, nach oben hebt den Blick.
|
||||
this.euler.y += this.lookDelta.x;
|
||||
this.euler.x += this.lookDelta.y;
|
||||
this.euler.x = Math.max(-1.3, Math.min(1.3, this.euler.x));
|
||||
|
||||
@@ -300,6 +300,7 @@ async function main() {
|
||||
marke.visible = false;
|
||||
marke.renderOrder = 5;
|
||||
scene.add(marke);
|
||||
walker.onPointerLockChange = (gefangen) => hud.setPointerLocked(gefangen);
|
||||
walker.onTarget = (ziel) => {
|
||||
marke.visible = !!ziel;
|
||||
if (ziel) marke.position.set(ziel.x, walkHeight(ziel.x, ziel.z) + 0.03, ziel.z);
|
||||
|
||||
+5
-2
@@ -171,8 +171,11 @@ export function setupHud(opts: HudOptions): Hud {
|
||||
|
||||
<h3>Bedienung</h3>
|
||||
<ul>
|
||||
<li>Rundgang: auf den Boden klicken, dann läuft man dorthin. Mit der Maus ziehen
|
||||
zum Umsehen.</li>
|
||||
<li>Rundgang: einmal klicken, dann übernimmt die Maus den Blick – Maus nach
|
||||
rechts oben heisst Blick nach rechts oben, wie im Spiel. <kbd>Esc</kbd> gibt die
|
||||
Maus wieder frei.</li>
|
||||
<li>Ein Klick mit gefangener Maus läuft zu dem Punkt unter dem Fadenkreuz; ohne
|
||||
Mausfang zu dem angeklickten Punkt.</li>
|
||||
<li>Oder mit <kbd>W</kbd> <kbd>A</kbd> <kbd>S</kbd> <kbd>D</kbd> gehen, <kbd>Shift</kbd> zum Rennen,
|
||||
<kbd>Leertaste</kbd> zum Springen</li>
|
||||
<li>Treppen, Stufen und Sitzmauern sind begehbar. Das Gartentor öffnet sich,
|
||||
|
||||
Reference in New Issue
Block a user