function handleInput(action, active) { if (isGameOver) { if(active) location.reload(); return; } const relativeTick = currentTick - lastSentTick; if (action === "JUMP" && active) { if (player.grounded && !isCrouching) { player.vy = JUMP_POWER; player.grounded = false; inputLog.push({ t: relativeTick, act: "JUMP" }); } } if (action === "DUCK") { isCrouching = active; } } // Event Listeners 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 === canvas && e.button === 0) handleInput("JUMP", true); }); // Touch Logic let touchStartY = 0; window.addEventListener('touchstart', (e) => { if(e.target === canvas) { e.preventDefault(); touchStartY = e.touches[0].clientY; } }, { passive: false }); window.addEventListener('touchend', (e) => { if(e.target === canvas) { e.preventDefault(); const diff = e.changedTouches[0].clientY - touchStartY; if (diff < -30) handleInput("JUMP", true); else if (diff > 30) { handleInput("DUCK", true); setTimeout(() => handleInput("DUCK", false), 800); } else if (Math.abs(diff) < 10) handleInput("JUMP", true); } });