added mobile touch controls and responsive design

This commit is contained in:
2026-02-02 16:54:56 +00:00
parent abae53aae0
commit d5bd5a83df

View File

@@ -11,6 +11,23 @@
#score, #lives { font-size: 20px; margin: 10px 0; color: #ff0; } #score, #lives { font-size: 20px; margin: 10px 0; color: #ff0; }
#gameOver, #startScreen { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 24px; color: #ff0; text-align: center; } #gameOver, #startScreen { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 24px; color: #ff0; text-align: center; }
.controls { margin-top: 20px; text-align: center; color: #0ff; } .controls { margin-top: 20px; text-align: center; color: #0ff; }
.mobile-controls { display: none; position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); z-index: 1000; }
.mobile-controls.active { display: block; }
.dpad { position: relative; width: 150px; height: 150px; }
.dpad-btn { position: absolute; background: rgba(255, 255, 0, 0.3); border: 2px solid #ff0; border-radius: 10px; color: #ff0; font-size: 20px; font-weight: bold; display: flex; align-items: center; justify-content: center; cursor: pointer; user-select: none; -webkit-user-select: none; }
.dpad-btn:active { background: rgba(255, 255, 0, 0.6); }
.dpad-up { width: 50px; height: 50px; top: 0; left: 50px; }
.dpad-down { width: 50px; height: 50px; bottom: 0; left: 50px; }
.dpad-left { width: 50px; height: 50px; top: 50px; left: 0; }
.dpad-right { width: 50px; height: 50px; top: 50px; right: 0; }
.dpad-center { width: 50px; height: 50px; top: 50px; left: 50px; background: rgba(255, 255, 0, 0.1); }
.mobile-space-btn { position: fixed; bottom: 180px; left: 50%; transform: translateX(-50%); background: rgba(0, 255, 255, 0.3); border: 2px solid #0ff; border-radius: 10px; color: #0ff; font-size: 16px; font-weight: bold; padding: 10px 20px; cursor: pointer; user-select: none; -webkit-user-select: none; z-index: 1000; }
.mobile-space-btn:active { background: rgba(0, 255, 255, 0.6); }
@media (max-width: 768px) {
body { padding: 10px; }
#gameCanvas { max-width: 100%; height: auto; }
.desktop-controls { display: none; }
}
</style> </style>
</head> </head>
<body> <body>
@@ -28,11 +45,25 @@
<div style="font-size: 16px; margin-top: 10px;">PRESS SPACE TO RESTART</div> <div style="font-size: 16px; margin-top: 10px;">PRESS SPACE TO RESTART</div>
</div> </div>
</div> </div>
<div class="controls"> <div class="controls desktop-controls">
<div>↑ ↓ ← → : MOVE PAC-MAN</div> <div>↑ ↓ ← → : MOVE PAC-MAN</div>
<div>SPACE : START/RESTART GAME</div> <div>SPACE : START/RESTART GAME</div>
</div> </div>
<!-- Mobile Controls -->
<div id="mobileControls" class="mobile-controls">
<div class="dpad">
<div class="dpad-btn dpad-up" data-direction="UP"></div>
<div class="dpad-btn dpad-down" data-direction="DOWN"></div>
<div class="dpad-btn dpad-left" data-direction="LEFT"></div>
<div class="dpad-btn dpad-right" data-direction="RIGHT"></div>
<div class="dpad-btn dpad-center"></div>
</div>
</div>
<!-- Mobile Space Button -->
<button id="mobileSpaceBtn" class="mobile-space-btn" style="display: none;">SPACE</button>
<script> <script>
const canvas = document.getElementById('gameCanvas'); const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
@@ -40,6 +71,22 @@
const livesElement = document.getElementById('lives'); const livesElement = document.getElementById('lives');
const gameOverElement = document.getElementById('gameOver'); const gameOverElement = document.getElementById('gameOver');
const startScreenElement = document.getElementById('startScreen'); const startScreenElement = document.getElementById('startScreen');
const mobileControlsElement = document.getElementById('mobileControls');
const mobileSpaceBtnElement = document.getElementById('mobileSpaceBtn');
// Mobile detection
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ||
(window.innerWidth <= 768 && 'ontouchstart' in window);
// Show mobile controls if on mobile device
if (isMobile) {
mobileControlsElement.classList.add('active');
mobileSpaceBtnElement.style.display = 'block';
// Adjust canvas size for mobile
const scale = Math.min(window.innerWidth / 500, 1);
canvas.style.width = (448 * scale) + 'px';
canvas.style.height = (560 * scale) + 'px';
}
const CELL_SIZE = 14; const CELL_SIZE = 14;
const MAZE_WIDTH = 32; const MAZE_WIDTH = 32;
@@ -682,6 +729,82 @@
} }
}); });
// Mobile touch controls
function setupMobileControls() {
const dpadButtons = document.querySelectorAll('.dpad-btn');
dpadButtons.forEach(button => {
const direction = button.dataset.direction;
if (!direction) return; // Skip center button
// Touch start
button.addEventListener('touchstart', (e) => {
e.preventDefault();
if (gameState === 'PLAYING') {
pacman.nextDirection = direction;
}
});
// Mouse down (for testing on desktop)
button.addEventListener('mousedown', (e) => {
e.preventDefault();
if (gameState === 'PLAYING') {
pacman.nextDirection = direction;
}
});
// Touch end
button.addEventListener('touchend', (e) => {
e.preventDefault();
});
// Mouse up
button.addEventListener('mouseup', (e) => {
e.preventDefault();
});
});
// Mobile space button
mobileSpaceBtnElement.addEventListener('touchstart', (e) => {
e.preventDefault();
handleSpaceButton();
});
mobileSpaceBtnElement.addEventListener('mousedown', (e) => {
e.preventDefault();
handleSpaceButton();
});
}
function handleSpaceButton() {
if (gameState === 'ATTRACT') {
gameState = 'START';
attractModeTimer = 0;
soundSystem.play('ready');
} else if (gameState === 'START') {
gameState = 'READY';
readyTimer = 180;
startScreenElement.style.display = 'none';
resetPositions();
soundSystem.play('ready');
} else if (gameState === 'GAME_OVER') {
gameState = 'START';
gameOverElement.style.display = 'none';
score = 0;
lives = 3;
currentLevel = 1;
updateScore();
updateLives();
maze = JSON.parse(JSON.stringify(mazeLayout));
soundSystem.play('ready');
}
}
// Initialize mobile controls if needed
if (isMobile) {
setupMobileControls();
}
// Start with attract mode // Start with attract mode
gameState = 'ATTRACT'; gameState = 'ATTRACT';
attractModeTimer = 0; attractModeTimer = 0;