mirror of
https://github.com/cmclark00/tetris-3d.git
synced 2025-05-17 23:25:21 +01:00
Fine-tune touch controls: improve swipe responsiveness, prevent accidental hard drops, enhance instructions
This commit is contained in:
parent
9e04ffc20a
commit
089a2db310
2 changed files with 90 additions and 25 deletions
92
script.js
92
script.js
|
@ -2182,14 +2182,17 @@ function clearPreviousPiecePosition() {
|
||||||
let touchStartX = 0;
|
let touchStartX = 0;
|
||||||
let touchStartY = 0;
|
let touchStartY = 0;
|
||||||
let touchStartTime = 0;
|
let touchStartTime = 0;
|
||||||
const SWIPE_THRESHOLD = 30;
|
const SWIPE_THRESHOLD = 15; // Reduced threshold for more responsive movement
|
||||||
const TAP_THRESHOLD = 200; // milliseconds
|
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 lastTapTime = 0;
|
||||||
let lastMoveTime = 0;
|
let lastMoveTime = 0;
|
||||||
let touchIdentifier = null;
|
let touchIdentifier = null;
|
||||||
let multiTouchDetected = false;
|
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
|
// Initialize touch controls
|
||||||
function initTouchControls() {
|
function initTouchControls() {
|
||||||
|
@ -2232,7 +2235,6 @@ function handleTouchMove(event) {
|
||||||
if (multiTouchDetected || event.touches.length > 1) return;
|
if (multiTouchDetected || event.touches.length > 1) return;
|
||||||
|
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
if (now - lastMoveTime < MOVE_COOLDOWN) return;
|
|
||||||
|
|
||||||
if (!event.touches.length) return;
|
if (!event.touches.length) return;
|
||||||
|
|
||||||
|
@ -2247,25 +2249,27 @@ function handleTouchMove(event) {
|
||||||
const absX = Math.abs(diffX);
|
const absX = Math.abs(diffX);
|
||||||
const absY = Math.abs(diffY);
|
const absY = Math.abs(diffY);
|
||||||
|
|
||||||
if (absX > SWIPE_THRESHOLD || absY > SWIPE_THRESHOLD) {
|
if (absX > SWIPE_THRESHOLD) {
|
||||||
// Determine direction of swipe - if more horizontal than vertical
|
// Horizontal movement has priority and a shorter cooldown
|
||||||
if (absX > absY) {
|
if (now - lastMoveTime >= MOVE_COOLDOWN) {
|
||||||
if (diffX > 0) {
|
if (diffX > 0) {
|
||||||
p.moveRight();
|
p.moveRight();
|
||||||
} else {
|
} else {
|
||||||
p.moveLeft();
|
p.moveLeft();
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Only handle downward swipes for soft drop
|
// Reset touch start to allow for continuous movement
|
||||||
if (diffY > 0) {
|
touchStartX = touch.clientX;
|
||||||
p.moveDown();
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset touch start to allow for continuous movement
|
|
||||||
touchStartX = touch.clientX;
|
|
||||||
touchStartY = touch.clientY;
|
|
||||||
lastMoveTime = now;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2289,16 +2293,30 @@ function handleTouchEnd(event) {
|
||||||
const touchEndTime = Date.now();
|
const touchEndTime = Date.now();
|
||||||
const touchDuration = touchEndTime - touchStartTime;
|
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)
|
// Check for tap (quick touch)
|
||||||
if (touchDuration < TAP_THRESHOLD) {
|
if (touchDuration < TAP_THRESHOLD) {
|
||||||
// Check for double tap (for hard drop)
|
// 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();
|
p.hardDrop();
|
||||||
lastTapTime = 0; // Reset to prevent triple-tap detection
|
lastTapTime = 0; // Reset to prevent triple-tap detection
|
||||||
} else {
|
} else {
|
||||||
// Single tap rotates piece
|
// Single tap rotates piece
|
||||||
p.rotate('right');
|
p.rotate('right');
|
||||||
lastTapTime = touchEndTime;
|
lastTapTime = touchEndTime;
|
||||||
|
lastTapX = touchX;
|
||||||
|
lastTapY = touchY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2314,11 +2332,12 @@ function createTouchControlButtons() {
|
||||||
const touchInstructions = document.createElement('div');
|
const touchInstructions = document.createElement('div');
|
||||||
touchInstructions.className = 'touch-instructions';
|
touchInstructions.className = 'touch-instructions';
|
||||||
touchInstructions.innerHTML = `
|
touchInstructions.innerHTML = `
|
||||||
<p>Swipe left/right: Move piece</p>
|
<h3>Touch Controls</h3>
|
||||||
<p>Swipe down: Soft drop</p>
|
<p><b>Swipe left/right:</b> Move piece</p>
|
||||||
<p>Tap: Rotate right</p>
|
<p><b>Swipe down:</b> Soft drop</p>
|
||||||
<p>Double tap: Hard drop</p>
|
<p><b>Tap anywhere:</b> Rotate right</p>
|
||||||
<p>Two-finger tap: 3D rotate</p>
|
<p><b>Double-tap:</b> Hard drop</p>
|
||||||
|
<p><b>Two-finger tap:</b> 3D rotate</p>
|
||||||
`;
|
`;
|
||||||
document.body.appendChild(touchInstructions);
|
document.body.appendChild(touchInstructions);
|
||||||
|
|
||||||
|
@ -2326,9 +2345,36 @@ function createTouchControlButtons() {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
touchInstructions.classList.add('fade-out');
|
touchInstructions.classList.add('fade-out');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
// Keep element in DOM but hidden, so it can be shown again later
|
||||||
|
touchInstructions.style.opacity = '0';
|
||||||
touchInstructions.style.display = 'none';
|
touchInstructions.style.display = 'none';
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}, 5000);
|
}, 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
|
// Set active piece to next piece and create new next piece
|
||||||
|
|
23
style.css
23
style.css
|
@ -658,7 +658,7 @@ input[type=range]::-moz-range-thumb {
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, -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: 2px solid rgba(0, 255, 255, 0.7);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
|
@ -666,6 +666,14 @@ input[type=range]::-moz-range-thumb {
|
||||||
box-shadow: 0 0 20px rgba(0, 255, 255, 0.5);
|
box-shadow: 0 0 20px rgba(0, 255, 255, 0.5);
|
||||||
transition: opacity 1s ease;
|
transition: opacity 1s ease;
|
||||||
text-align: center;
|
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 {
|
.mobile-mode .touch-instructions {
|
||||||
|
@ -674,10 +682,21 @@ input[type=range]::-moz-range-thumb {
|
||||||
|
|
||||||
.touch-instructions p {
|
.touch-instructions p {
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
font-size: 14px;
|
font-size: 13px;
|
||||||
color: #fff;
|
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 {
|
.touch-instructions.fade-out {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.instructions-btn {
|
||||||
|
margin-top: 15px;
|
||||||
|
background: linear-gradient(45deg, #ff9900, #ff5500);
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue