// ========================================== // INPUT HANDLING // ========================================== function handleInput(action, active) { if (isGameOver) { if(active) location.reload(); return; } // JUMP if (action === "JUMP" && active) { if (player.grounded && !isCrouching) { player.vy = JUMP_POWER; player.grounded = false; if (typeof playSound === 'function') playSound('jump'); if (typeof spawnParticles === 'function') spawnParticles(player.x + 15, player.y + 50, 'dust', 5); if (typeof sendInput === "function") sendInput("input", "JUMP"); } } // DUCK if (action === "DUCK") { const wasCrouching = isCrouching; isCrouching = active; if (wasCrouching !== isCrouching) { if (typeof sendInput === "function") { sendInput("input", active ? "DUCK_START" : "DUCK_END"); } } } } // ========================================== // EVENT LISTENERS (KEYBOARD) // ========================================== window.addEventListener('keydown', (e) => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; if (e.code === 'Space' || e.code === 'ArrowUp') handleInput("JUMP", true); if (e.code === 'ArrowDown' || e.code === 'KeyS') handleInput("DUCK", true); }); window.addEventListener('keyup', (e) => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; if (e.code === 'ArrowDown' || e.code === 'KeyS') handleInput("DUCK", false); }); window.addEventListener('mousedown', (e) => { if (e.target.tagName === 'BUTTON' || e.target.tagName === 'INPUT') return; if (e.button === 0) handleInput("JUMP", true); }); // ========================================== // TOUCH HANDLING (INSTANT RESPONSE) // ========================================== let touchStartY = 0; let isSwiping = false; // 1. TOUCH START -> SOFORT SPRINGEN window.addEventListener('touchstart', (e) => { // UI Buttons ignorieren if (e.target.tagName === 'BUTTON' || e.target.tagName === 'INPUT') return; e.preventDefault(); touchStartY = e.touches[0].clientY; isSwiping = false; // FIX: Wir springen SOFORT, ohne zu warten! // Das gibt das "Snappy" Gefühl. handleInput("JUMP", true); }, { passive: false }); // 2. TOUCH MOVE -> DUCKEN ERKENNEN window.addEventListener('touchmove', (e) => { if (e.target.tagName === 'BUTTON') return; e.preventDefault(); if (isSwiping) return; // Nur einmal pro Swipe auslösen const currentY = e.touches[0].clientY; const diff = currentY - touchStartY; // Wenn wir mehr als 30px nach UNTEN wischen... if (diff > 30) { // ... korrigieren wir den Sprung in ein Ducken! // Da wir im Spiel eine Physik haben, wo Ducken in der Luft // zu "Fast Fall" (schnellem Fallen) führt, fühlt sich das gut an. handleInput("DUCK", true); isSwiping = true; // Sperren bis zum nächsten Touch // Automatisch aufstehen nach kurzer Zeit setTimeout(() => handleInput("DUCK", false), 800); } }, { passive: false }); // 3. TOUCH END -> RESET // (Hier müssen wir nichts mehr tun, da der Jump schon beim Start passiert ist) window.addEventListener('touchend', (e) => { if (e.target.tagName === 'BUTTON') return; e.preventDefault(); // Ggf. Ducken beenden falls man gedrückt hält? // Hier lassen wir den Timeout regeln. }, { passive: false });