enhanced Chrome Android compatibility - improved touch events and audio
This commit is contained in:
196
pacman.html
196
pacman.html
@@ -87,10 +87,16 @@
|
||||
const gameStateStatusElement = document.getElementById('gameStateStatus');
|
||||
const controlsStatusElement = document.getElementById('controlsStatus');
|
||||
|
||||
// Mobile detection
|
||||
// Mobile detection - more comprehensive for Chrome Android
|
||||
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ||
|
||||
(window.innerWidth <= 768 && 'ontouchstart' in window);
|
||||
|
||||
// Chrome Android specific detection
|
||||
const isChromeAndroid = /Chrome/.test(navigator.userAgent) && /Android/.test(navigator.userAgent);
|
||||
console.log('Mobile detected:', isMobile);
|
||||
console.log('Chrome Android detected:', isChromeAndroid);
|
||||
console.log('User agent:', navigator.userAgent);
|
||||
|
||||
// Update debug info
|
||||
function updateDebugInfo() {
|
||||
if (isMobileStatusElement) isMobileStatusElement.textContent = isMobile ? 'Yes' : 'No';
|
||||
@@ -181,20 +187,35 @@
|
||||
mouthAngle: 0.2
|
||||
};
|
||||
|
||||
// Sound system based on assembly audio routines
|
||||
// Sound system based on assembly audio routines - enhanced for Chrome Android
|
||||
class SoundSystem {
|
||||
constructor() {
|
||||
this.audioContext = null;
|
||||
this.sounds = {};
|
||||
this.initialized = false;
|
||||
this.initAudio();
|
||||
}
|
||||
|
||||
initAudio() {
|
||||
try {
|
||||
this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
||||
this.createSounds();
|
||||
// Create audio context on first user interaction for Chrome Android
|
||||
if (typeof AudioContext !== 'undefined' || typeof webkitAudioContext !== 'undefined') {
|
||||
const AudioContextClass = window.AudioContext || window.webkitAudioContext;
|
||||
this.audioContext = new AudioContextClass();
|
||||
|
||||
// Resume audio context if suspended (Chrome Android requirement)
|
||||
if (this.audioContext.state === 'suspended') {
|
||||
this.audioContext.resume();
|
||||
}
|
||||
|
||||
this.createSounds();
|
||||
this.initialized = true;
|
||||
console.log('Audio system initialized for Chrome Android');
|
||||
} else {
|
||||
console.log('Web Audio API not supported');
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Audio not supported');
|
||||
console.log('Audio initialization failed:', e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,22 +230,31 @@
|
||||
}
|
||||
|
||||
playTone(frequency, duration) {
|
||||
if (!this.audioContext) return;
|
||||
if (!this.audioContext || !this.initialized) return;
|
||||
|
||||
const oscillator = this.audioContext.createOscillator();
|
||||
const gainNode = this.audioContext.createGain();
|
||||
|
||||
oscillator.connect(gainNode);
|
||||
gainNode.connect(this.audioContext.destination);
|
||||
|
||||
oscillator.frequency.value = frequency;
|
||||
oscillator.type = 'square';
|
||||
|
||||
gainNode.gain.setValueAtTime(0.1, this.audioContext.currentTime);
|
||||
gainNode.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + duration / 1000);
|
||||
|
||||
oscillator.start(this.audioContext.currentTime);
|
||||
oscillator.stop(this.audioContext.currentTime + duration / 1000);
|
||||
try {
|
||||
// Resume audio context if suspended (Chrome Android)
|
||||
if (this.audioContext.state === 'suspended') {
|
||||
this.audioContext.resume();
|
||||
}
|
||||
|
||||
const oscillator = this.audioContext.createOscillator();
|
||||
const gainNode = this.audioContext.createGain();
|
||||
|
||||
oscillator.connect(gainNode);
|
||||
gainNode.connect(this.audioContext.destination);
|
||||
|
||||
oscillator.frequency.value = frequency;
|
||||
oscillator.type = 'square';
|
||||
|
||||
gainNode.gain.setValueAtTime(0.1, this.audioContext.currentTime);
|
||||
gainNode.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + duration / 1000);
|
||||
|
||||
oscillator.start(this.audioContext.currentTime);
|
||||
oscillator.stop(this.audioContext.currentTime + duration / 1000);
|
||||
} catch (e) {
|
||||
console.log('Error playing tone:', e);
|
||||
}
|
||||
}
|
||||
|
||||
play(soundName) {
|
||||
@@ -765,9 +795,9 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Mobile touch controls
|
||||
// Mobile touch controls - enhanced for Chrome Android
|
||||
function setupMobileControls() {
|
||||
console.log('Setting up mobile controls...');
|
||||
console.log('Setting up mobile controls for Chrome Android...');
|
||||
const dpadButtons = document.querySelectorAll('.dpad-btn');
|
||||
|
||||
dpadButtons.forEach(button => {
|
||||
@@ -776,10 +806,15 @@
|
||||
|
||||
console.log('Setting up button for direction:', direction);
|
||||
|
||||
// Touch start
|
||||
// Enhanced touch events for Chrome Android
|
||||
button.addEventListener('touchstart', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
console.log('Touch start for direction:', direction, 'Game state:', gameState);
|
||||
|
||||
// Add visual feedback
|
||||
button.style.backgroundColor = 'rgba(255, 255, 0, 0.8)';
|
||||
|
||||
if (gameState === 'PLAYING') {
|
||||
pacman.nextDirection = direction;
|
||||
console.log('Set pacman direction to:', direction);
|
||||
@@ -788,47 +823,65 @@
|
||||
pacman.nextDirection = direction;
|
||||
console.log('Set pacman direction to:', direction, '(testing mode)');
|
||||
}
|
||||
});
|
||||
}, { passive: false });
|
||||
|
||||
// Mouse down (for testing on desktop)
|
||||
button.addEventListener('touchend', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
// Remove visual feedback
|
||||
button.style.backgroundColor = '';
|
||||
}, { passive: false });
|
||||
|
||||
// Mouse events for desktop testing
|
||||
button.addEventListener('mousedown', (e) => {
|
||||
e.preventDefault();
|
||||
console.log('Mouse down for direction:', direction, 'Game state:', gameState);
|
||||
button.style.backgroundColor = 'rgba(255, 255, 0, 0.8)';
|
||||
|
||||
if (gameState === 'PLAYING') {
|
||||
pacman.nextDirection = direction;
|
||||
console.log('Set pacman direction to:', direction);
|
||||
} else {
|
||||
// For testing, allow direction changes in any state
|
||||
pacman.nextDirection = direction;
|
||||
console.log('Set pacman direction to:', direction, '(testing mode)');
|
||||
}
|
||||
});
|
||||
|
||||
// Touch end
|
||||
button.addEventListener('touchend', (e) => {
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
// Mouse up
|
||||
button.addEventListener('mouseup', (e) => {
|
||||
e.preventDefault();
|
||||
button.style.backgroundColor = '';
|
||||
});
|
||||
});
|
||||
|
||||
// Mobile space button
|
||||
// Enhanced space button for Chrome Android
|
||||
mobileSpaceBtnElement.addEventListener('touchstart', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
console.log('Mobile space button touched');
|
||||
mobileSpaceBtnElement.style.backgroundColor = 'rgba(0, 255, 255, 0.8)';
|
||||
handleSpaceButton();
|
||||
});
|
||||
}, { passive: false });
|
||||
|
||||
mobileSpaceBtnElement.addEventListener('touchend', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
mobileSpaceBtnElement.style.backgroundColor = '';
|
||||
}, { passive: false });
|
||||
|
||||
// Mouse events for testing
|
||||
mobileSpaceBtnElement.addEventListener('mousedown', (e) => {
|
||||
e.preventDefault();
|
||||
console.log('Mobile space button clicked');
|
||||
mobileSpaceBtnElement.style.backgroundColor = 'rgba(0, 255, 255, 0.8)';
|
||||
handleSpaceButton();
|
||||
});
|
||||
|
||||
console.log('Mobile controls setup complete');
|
||||
mobileSpaceBtnElement.addEventListener('mouseup', (e) => {
|
||||
e.preventDefault();
|
||||
mobileSpaceBtnElement.style.backgroundColor = '';
|
||||
});
|
||||
|
||||
console.log('Mobile controls setup complete for Chrome Android');
|
||||
}
|
||||
|
||||
function handleSpaceButton() {
|
||||
@@ -851,21 +904,39 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize mobile controls if needed
|
||||
if (isMobile || window.innerWidth <= 768) {
|
||||
setupMobileControls();
|
||||
// Initialize game for Chrome Android
|
||||
function initializeGame() {
|
||||
console.log('Initializing game for Chrome Android...');
|
||||
|
||||
// Force show mobile controls
|
||||
mobileControlsElement.classList.add('active');
|
||||
mobileSpaceBtnElement.style.display = 'block';
|
||||
|
||||
// Show start screen
|
||||
startScreenElement.style.display = 'block';
|
||||
|
||||
// Set initial game state
|
||||
gameState = 'START';
|
||||
attractModeTimer = 0;
|
||||
|
||||
// Update debug info
|
||||
updateDebugInfo();
|
||||
|
||||
// Setup mobile controls
|
||||
if (isMobile || window.innerWidth <= 768) {
|
||||
setupMobileControls();
|
||||
}
|
||||
|
||||
console.log('Game initialized successfully');
|
||||
console.log('Game state:', gameState);
|
||||
console.log('Mobile controls visible:', mobileControlsElement.classList.contains('active'));
|
||||
console.log('Start screen visible:', startScreenElement.style.display);
|
||||
|
||||
// Start game loop
|
||||
gameLoop();
|
||||
gameLoopStarted = true;
|
||||
}
|
||||
|
||||
// Force show mobile controls for testing
|
||||
mobileControlsElement.classList.add('active');
|
||||
mobileSpaceBtnElement.style.display = 'block';
|
||||
updateDebugInfo();
|
||||
|
||||
console.log('Game initialized with mobile controls');
|
||||
console.log('Mobile detected:', isMobile);
|
||||
console.log('Window width:', window.innerWidth);
|
||||
console.log('Mobile controls visible:', mobileControlsElement.classList.contains('active'));
|
||||
|
||||
// Test function for mobile controls
|
||||
window.testMobileControls = function() {
|
||||
console.log('Testing mobile controls...');
|
||||
@@ -878,21 +949,24 @@
|
||||
handleSpaceButton();
|
||||
};
|
||||
|
||||
// Start with START state instead of ATTRACT for easier testing
|
||||
gameState = 'START';
|
||||
attractModeTimer = 0;
|
||||
let gameLoopStarted = false;
|
||||
|
||||
// Show start screen immediately
|
||||
startScreenElement.style.display = 'block';
|
||||
// Initialize on page load with fallback for Chrome Android
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initializeGame);
|
||||
} else {
|
||||
// DOM already loaded
|
||||
initializeGame();
|
||||
}
|
||||
|
||||
console.log('Game starting in START state');
|
||||
console.log('Start screen visible:', startScreenElement.style.display);
|
||||
|
||||
// Test if JavaScript is working
|
||||
alert('JavaScript is loaded! Click OK to continue.');
|
||||
|
||||
// Start game loop
|
||||
gameLoop();
|
||||
// Additional fallback for Chrome Android
|
||||
window.addEventListener('load', function() {
|
||||
console.log('Page fully loaded');
|
||||
if (!gameLoopStarted) {
|
||||
console.log('Fallback initialization');
|
||||
initializeGame();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user