Mobile First Overhaul: Touch gestures, dual tap/drag, instant responsiveness and ergonomic controls across all mini games

This commit is contained in:
Maxi
2026-09-22 19:57:56 +02:00
parent 2ce944d1cd
commit 5551c4e54f
13 changed files with 443 additions and 319 deletions
+28 -17
View File
@@ -1,4 +1,4 @@
// Wichtel-Panik / Cornish Pixies Arcade Engine
// Wichtel-Panik / Cornish Pixies Arcade Engine (Mobile First)
(function() {
let score = 0;
const targetScore = 10;
@@ -10,12 +10,12 @@
// DOM Elements
const scoreEl = document.getElementById('pixieScore');
const timerEl = document.getElementById('pixieTimer');
const startBtn = document.getElementById('startPixieBtn');
const startOverlay = document.getElementById('startOverlay');
const startBtn = document.getElementById('startPixieBtn');
const successPanel = document.getElementById('pixieSuccess');
const holes = document.querySelectorAll('.pixie-hole');
const activeTargets = new Map(); // holeIndex -> { type: 'pixie'|'neville', timer: id }
const activeTargets = new Map(); // holeIndex -> { isNeville: bool, timer: id, clicked: bool }
window.startPixieHunt = function() {
if (gameRunning) return;
@@ -25,10 +25,11 @@
scoreEl.innerText = score;
timerEl.innerText = timeLeft;
startOverlay.style.display = 'none';
if (startOverlay) startOverlay.style.display = 'none';
if (successPanel) successPanel.style.display = 'none';
if (window.soundFX) window.soundFX.playWhoosh();
if (window.navigator && window.navigator.vibrate) window.navigator.vibrate(30);
// Start countdown
timerInterval = setInterval(() => {
@@ -45,7 +46,7 @@
function scheduleNextSpawn() {
if (!gameRunning) return;
const delay = Math.random() * 400 + 400; // 400ms - 800ms
const delay = Math.random() * 350 + 400; // 400ms - 750ms
spawnTimeout = setTimeout(() => {
spawnTarget();
scheduleNextSpawn();
@@ -66,13 +67,13 @@
const targetEl = document.getElementById(`target${holeIdx}`);
if (!targetEl) return;
// 15% chance Neville, 85% chance Pixie
const isNeville = Math.random() < 0.15;
// 12% chance Neville, 88% chance Pixie
const isNeville = Math.random() < 0.12;
targetEl.className = 'pixie-target active';
targetEl.innerText = isNeville ? '👦' : '🧚';
if (isNeville) targetEl.classList.add('neville');
const stayTime = Math.random() * 400 + 850; // 850ms - 1250ms
const stayTime = Math.random() * 450 + 900; // 900ms - 1350ms (forgiving for mobile)
const hideTimer = setTimeout(() => {
hideTarget(holeIdx);
@@ -95,11 +96,11 @@
activeTargets.delete(holeIdx);
}
// Touch / Click Handler on holes
// Pointerdown handler on holes (zero delay on touch devices!)
holes.forEach(hole => {
const idx = parseInt(hole.dataset.idx, 10);
function handleTap(e) {
function onHoleTrigger(e) {
if (!gameRunning) return;
e.preventDefault();
@@ -113,10 +114,12 @@
if (targetData.isNeville) {
// Clicked Neville -> Penalty!
if (window.soundFX) window.soundFX.playWhoosh();
if (window.navigator && window.navigator.vibrate) window.navigator.vibrate([40, 40]);
score = Math.max(0, score - 2);
scoreEl.innerText = score;
targetEl.style.transform = 'scale(1.3) rotate(15deg)';
targetEl.style.transform = 'scale(1.25) rotate(15deg)';
if (window.showFloatingToast) {
window.showFloatingToast("🤕 <strong>Neville:</strong> »Aua! Ich bin doch kein Wichtel!« (-2 Pkt)");
}
@@ -132,6 +135,9 @@
if (window.soundFX) {
window.soundFX.playKeyChime();
}
if (window.navigator && window.navigator.vibrate) {
window.navigator.vibrate(35);
}
score++;
scoreEl.innerText = score;
@@ -139,13 +145,13 @@
if (score >= targetScore) {
endGame(true);
} else {
setTimeout(() => hideTarget(idx), 400);
setTimeout(() => hideTarget(idx), 380);
}
}
}
hole.addEventListener('click', handleTap);
hole.addEventListener('touchstart', handleTap, { passive: false });
// Use pointerdown for instant touch & mouse response without delay
hole.addEventListener('pointerdown', onHoleTrigger);
});
async function endGame(won) {
@@ -159,6 +165,9 @@
if (won) {
if (window.soundFX) window.soundFX.playMagicSuccess();
if (window.navigator && window.navigator.vibrate) {
window.navigator.vibrate([50, 100, 150]);
}
try {
const res = await fetch('/api/pixies/complete', {
@@ -178,10 +187,12 @@
} else {
if (window.soundFX) window.soundFX.playWhoosh();
startOverlay.style.display = 'block';
startBtn.innerText = "Erneut versuchen 🔄";
if (startOverlay) {
startOverlay.style.display = 'flex';
if (startBtn) startBtn.innerText = "Erneut versuchen 🔄";
}
if (window.showFloatingToast) {
window.showFloatingToast("⏰ Die Zeit ist abgelaufen! Die Wichtel haben gewonnen. Versuch es noch einmal!");
window.showFloatingToast("⏰ Die Zeit ist abgelaufen! Versuch es noch einmal.");
}
}
}