Implement DAS/ARR for smooth horizontal piece movement
This commit is contained in:
+77
-12
@@ -4,6 +4,17 @@ let localGame = null;
|
||||
let renderer = null;
|
||||
let lastTime = 0;
|
||||
|
||||
// Keyboard state for continuous movement (DAS - Delayed Auto Shift)
|
||||
const keyState = {
|
||||
ArrowLeft: false,
|
||||
ArrowRight: false,
|
||||
ArrowDown: false,
|
||||
};
|
||||
|
||||
let dasCounter = 0;
|
||||
const DAS_DELAY = 100; // ms before auto-repeat starts
|
||||
const ARR_SPEED = 30; // ms between auto-repeat moves
|
||||
|
||||
// Initialize when DOM is ready
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Connect to server
|
||||
@@ -26,10 +37,18 @@ function setupNetworkListeners() {
|
||||
// Show lobby screen if we're on the login screen
|
||||
if (ui.screens.room.classList.contains('active')) {
|
||||
ui.showScreen('lobby');
|
||||
// Play lobby music when first entering lobby
|
||||
if (typeof audio !== 'undefined') {
|
||||
audio.playLobby();
|
||||
}
|
||||
}
|
||||
// Reset lobby state when returning from game over (player is null indicates game over reset)
|
||||
if (!player) {
|
||||
ui.resetLobbyState();
|
||||
// Resume lobby music after game ends
|
||||
if (typeof audio !== 'undefined') {
|
||||
audio.playLobby();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -43,6 +62,11 @@ function setupNetworkListeners() {
|
||||
ui.showScreen('game');
|
||||
ui.displays.gameRoomName.textContent = 'GLOBAL LOBBY';
|
||||
|
||||
// Start game music - will play continuously until game ends
|
||||
if (typeof audio !== 'undefined') {
|
||||
audio.playGame();
|
||||
}
|
||||
|
||||
// Clear old boards
|
||||
renderer.clearAll();
|
||||
|
||||
@@ -88,6 +112,11 @@ function setupNetworkListeners() {
|
||||
ui.showScreen('game');
|
||||
ui.showSpectatorMode();
|
||||
|
||||
// Start game music for spectators too
|
||||
if (typeof audio !== 'undefined') {
|
||||
audio.playGame();
|
||||
}
|
||||
|
||||
// Clear old boards
|
||||
renderer.clearAll();
|
||||
|
||||
@@ -122,19 +151,16 @@ function setupKeyboardControls() {
|
||||
if (network.isSpectator) return;
|
||||
|
||||
if (ui.screens.game.classList.contains('active') && localGame) {
|
||||
// Track held keys for movement
|
||||
if (keyState.hasOwnProperty(e.key)) {
|
||||
keyState[e.key] = true;
|
||||
dasCounter = 0; // Reset DAS counter when key pressed
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
// One-time actions
|
||||
switch (e.key) {
|
||||
case 'ArrowLeft':
|
||||
network.sendMove('left');
|
||||
e.preventDefault();
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
network.sendMove('right');
|
||||
e.preventDefault();
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
network.sendDrop();
|
||||
e.preventDefault();
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
network.sendRotate();
|
||||
e.preventDefault();
|
||||
@@ -147,10 +173,22 @@ function setupKeyboardControls() {
|
||||
network.sendHold();
|
||||
e.preventDefault();
|
||||
break;
|
||||
case 'a':
|
||||
case 'A':
|
||||
network.sendZoneActivate();
|
||||
e.preventDefault();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('keyup', (e) => {
|
||||
if (keyState.hasOwnProperty(e.key)) {
|
||||
keyState[e.key] = false;
|
||||
dasCounter = 0;
|
||||
}
|
||||
});
|
||||
|
||||
// Touch controls for mobile
|
||||
const btnLeft = document.getElementById('btn-left');
|
||||
const btnRight = document.getElementById('btn-right');
|
||||
@@ -158,6 +196,7 @@ function setupKeyboardControls() {
|
||||
const btnRotate = document.getElementById('btn-rotate');
|
||||
const btnDrop = document.getElementById('btn-drop');
|
||||
const btnHold = document.getElementById('btn-hold');
|
||||
const btnZone = document.getElementById('btn-zone');
|
||||
|
||||
const handleTouch = (e, action) => {
|
||||
e.preventDefault();
|
||||
@@ -176,6 +215,7 @@ function setupKeyboardControls() {
|
||||
btnRotate.addEventListener('pointerdown', (e) => handleTouch(e, () => network.sendRotate()));
|
||||
btnDrop.addEventListener('pointerdown', (e) => handleTouch(e, () => network.sendHardDrop()));
|
||||
btnHold.addEventListener('pointerdown', (e) => handleTouch(e, () => network.sendHold()));
|
||||
btnZone.addEventListener('pointerdown', (e) => handleTouch(e, () => network.sendZoneActivate()));
|
||||
|
||||
// Prevent double-tap zoom
|
||||
btnLeft.addEventListener('touchstart', (e) => e.preventDefault());
|
||||
@@ -184,6 +224,7 @@ function setupKeyboardControls() {
|
||||
btnRotate.addEventListener('touchstart', (e) => e.preventDefault());
|
||||
btnDrop.addEventListener('touchstart', (e) => e.preventDefault());
|
||||
btnHold.addEventListener('touchstart', (e) => e.preventDefault());
|
||||
btnZone.addEventListener('touchstart', (e) => e.preventDefault());
|
||||
}
|
||||
|
||||
function updateBattleGridLayout(playerCount) {
|
||||
@@ -224,6 +265,8 @@ function endGame(states) {
|
||||
}
|
||||
});
|
||||
|
||||
// Game music will continue during game over screen, then transition back to lobby music via resetLobbyState
|
||||
|
||||
// Reset spectator mode for next round
|
||||
network.isSpectator = false;
|
||||
ui.hideSpectatorMode();
|
||||
@@ -239,6 +282,21 @@ function gameLoop(currentTime) {
|
||||
const deltaTime = currentTime - lastTime;
|
||||
lastTime = currentTime;
|
||||
|
||||
// Handle DAS (Delayed Auto Shift) for continuous movement
|
||||
if (!network.isSpectator && (keyState.ArrowLeft || keyState.ArrowRight || keyState.ArrowDown)) {
|
||||
dasCounter += deltaTime;
|
||||
|
||||
// Send initial move immediately, then auto-repeat after DAS_DELAY
|
||||
if (dasCounter >= DAS_DELAY) {
|
||||
const autoRepeatCounter = (dasCounter - DAS_DELAY) % ARR_SPEED;
|
||||
if (autoRepeatCounter < (deltaTime || 0)) {
|
||||
if (keyState.ArrowLeft) network.sendMove('left');
|
||||
if (keyState.ArrowRight) network.sendMove('right');
|
||||
if (keyState.ArrowDown) network.sendDrop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update local game
|
||||
if (localGame) {
|
||||
localGame.update(deltaTime);
|
||||
@@ -250,6 +308,13 @@ function gameLoop(currentTime) {
|
||||
renderer.renderPlayer(state.playerId, state);
|
||||
});
|
||||
|
||||
// Update Zone button state for current player
|
||||
const btnZone = document.getElementById('btn-zone');
|
||||
const localState = allStates[network.currentPlayerId];
|
||||
if (btnZone && localState) {
|
||||
btnZone.disabled = localState.zoneMeter < 100 || localState.zoneActive;
|
||||
}
|
||||
|
||||
// Set active player highlight (or null for spectators to show all boards equally)
|
||||
renderer.setActivePlayer(network.isSpectator ? null : network.currentPlayerId);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user