Fine-tune touch controls: improve swipe responsiveness, prevent accidental hard drops, enhance instructions

This commit is contained in:
cmclark00 2025-03-25 17:16:06 -04:00
parent 9e04ffc20a
commit 089a2db310
2 changed files with 90 additions and 25 deletions

View file

@ -2182,14 +2182,17 @@ function clearPreviousPiecePosition() {
let touchStartX = 0;
let touchStartY = 0;
let touchStartTime = 0;
const SWIPE_THRESHOLD = 30;
const SWIPE_THRESHOLD = 15; // Reduced threshold for more responsive movement
const TAP_THRESHOLD = 200; // milliseconds
const DOUBLE_TAP_THRESHOLD = 300; // milliseconds
const DOUBLE_TAP_THRESHOLD = 400; // Increased to prevent accidental double-taps
let lastTapTime = 0;
let lastMoveTime = 0;
let touchIdentifier = null;
let multiTouchDetected = false;
const MOVE_COOLDOWN = 100; // ms between moves to prevent too rapid movement
const MOVE_COOLDOWN = 60; // Reduced cooldown for smoother movement
let lastTapX = 0;
let lastTapY = 0;
const TAP_DISTANCE_THRESHOLD = 20; // Maximum distance to consider as same-position tap
// Initialize touch controls
function initTouchControls() {
@ -2232,7 +2235,6 @@ function handleTouchMove(event) {
if (multiTouchDetected || event.touches.length > 1) return;
const now = Date.now();
if (now - lastMoveTime < MOVE_COOLDOWN) return;
if (!event.touches.length) return;
@ -2247,26 +2249,28 @@ function handleTouchMove(event) {
const absX = Math.abs(diffX);
const absY = Math.abs(diffY);
if (absX > SWIPE_THRESHOLD || absY > SWIPE_THRESHOLD) {
// Determine direction of swipe - if more horizontal than vertical
if (absX > absY) {
if (absX > SWIPE_THRESHOLD) {
// Horizontal movement has priority and a shorter cooldown
if (now - lastMoveTime >= MOVE_COOLDOWN) {
if (diffX > 0) {
p.moveRight();
} else {
p.moveLeft();
}
} else {
// Only handle downward swipes for soft drop
if (diffY > 0) {
p.moveDown();
}
}
// Reset touch start to allow for continuous movement
touchStartX = touch.clientX;
lastMoveTime = now;
}
}
// Only handle downward swipes for soft drop - if no horizontal movement is detected
else if (absY > SWIPE_THRESHOLD * 2 && absY > absX && diffY > 0) {
if (now - lastMoveTime >= MOVE_COOLDOWN * 2) { // Use longer cooldown for down movement
p.moveDown();
touchStartY = touch.clientY;
lastMoveTime = now;
}
}
}
// Handle touch end event
@ -2289,16 +2293,30 @@ function handleTouchEnd(event) {
const touchEndTime = Date.now();
const touchDuration = touchEndTime - touchStartTime;
// Get touch coordinates
const touch = event.changedTouches[0];
const touchX = touch.clientX;
const touchY = touch.clientY;
// Check for tap (quick touch)
if (touchDuration < TAP_THRESHOLD) {
// Check for double tap (for hard drop)
if (touchEndTime - lastTapTime < DOUBLE_TAP_THRESHOLD) {
// Must be within time threshold AND close to the same position
const timeBetweenTaps = touchEndTime - lastTapTime;
const distanceBetweenTaps = Math.sqrt(
Math.pow(touchX - lastTapX, 2) +
Math.pow(touchY - lastTapY, 2)
);
if (timeBetweenTaps < DOUBLE_TAP_THRESHOLD && distanceBetweenTaps < TAP_DISTANCE_THRESHOLD) {
p.hardDrop();
lastTapTime = 0; // Reset to prevent triple-tap detection
} else {
// Single tap rotates piece
p.rotate('right');
lastTapTime = touchEndTime;
lastTapX = touchX;
lastTapY = touchY;
}
}
@ -2314,11 +2332,12 @@ function createTouchControlButtons() {
const touchInstructions = document.createElement('div');
touchInstructions.className = 'touch-instructions';
touchInstructions.innerHTML = `
<p>Swipe left/right: Move piece</p>
<p>Swipe down: Soft drop</p>
<p>Tap: Rotate right</p>
<p>Double tap: Hard drop</p>
<p>Two-finger tap: 3D rotate</p>
<h3>Touch Controls</h3>
<p><b>Swipe left/right:</b> Move piece</p>
<p><b>Swipe down:</b> Soft drop</p>
<p><b>Tap anywhere:</b> Rotate right</p>
<p><b>Double-tap:</b> Hard drop</p>
<p><b>Two-finger tap:</b> 3D rotate</p>
`;
document.body.appendChild(touchInstructions);
@ -2326,9 +2345,36 @@ function createTouchControlButtons() {
setTimeout(() => {
touchInstructions.classList.add('fade-out');
setTimeout(() => {
// Keep element in DOM but hidden, so it can be shown again later
touchInstructions.style.opacity = '0';
touchInstructions.style.display = 'none';
}, 1000);
}, 5000);
// Add instruction toggle button to score container
const instructionsBtn = document.createElement('button');
instructionsBtn.className = 'game-btn instructions-btn';
instructionsBtn.innerHTML = 'Controls';
instructionsBtn.addEventListener('click', function() {
// Show instructions again
touchInstructions.style.display = 'block';
touchInstructions.style.opacity = '1';
touchInstructions.classList.remove('fade-out');
// Fade out after 5 seconds
setTimeout(() => {
touchInstructions.classList.add('fade-out');
setTimeout(() => {
touchInstructions.style.display = 'none';
}, 1000);
}, 5000);
});
// Add button to score container
const scoreContainer = document.querySelector('.score-container');
if (scoreContainer) {
scoreContainer.appendChild(instructionsBtn);
}
}
// Set active piece to next piece and create new next piece

View file

@ -658,7 +658,7 @@ input[type=range]::-moz-range-thumb {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.8);
background: rgba(0, 0, 0, 0.9);
border: 2px solid rgba(0, 255, 255, 0.7);
border-radius: 10px;
padding: 15px;
@ -666,6 +666,14 @@ input[type=range]::-moz-range-thumb {
box-shadow: 0 0 20px rgba(0, 255, 255, 0.5);
transition: opacity 1s ease;
text-align: center;
max-width: 90vw;
}
.touch-instructions h3 {
color: #00ffff;
text-shadow: 0 0 5px #00ffff, 0 0 10px #00ffff;
margin-bottom: 15px;
font-size: 16px;
}
.mobile-mode .touch-instructions {
@ -674,10 +682,21 @@ input[type=range]::-moz-range-thumb {
.touch-instructions p {
margin: 10px 0;
font-size: 14px;
font-size: 13px;
color: #fff;
text-align: left;
}
.touch-instructions p b {
color: #ff9900;
text-shadow: 0 0 5px rgba(255, 153, 0, 0.5);
}
.touch-instructions.fade-out {
opacity: 0;
}
.instructions-btn {
margin-top: 15px;
background: linear-gradient(45deg, #ff9900, #ff5500);
}