Add platform-specific implementations for assets, audio, WebSocket, and rendering on Desktop and WebAssembly platforms. Introduce embedded assets for WebAssembly and native file handling for Desktop. Add platform-specific chunk loading and game state synchronization.
This commit is contained in:
341
cmd/client/web/game.js
Normal file
341
cmd/client/web/game.js
Normal file
@@ -0,0 +1,341 @@
|
||||
// Game State
|
||||
let wasmReady = false;
|
||||
let gameStarted = false;
|
||||
let audioMuted = false;
|
||||
|
||||
// Initialize WASM
|
||||
async function initWASM() {
|
||||
const go = new Go();
|
||||
|
||||
try {
|
||||
const result = await WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject);
|
||||
go.run(result.instance);
|
||||
wasmReady = true;
|
||||
|
||||
// Hide loading screen
|
||||
document.getElementById('loading').style.display = 'none';
|
||||
|
||||
console.log('✅ WASM loaded successfully');
|
||||
|
||||
// Load initial leaderboard
|
||||
setTimeout(() => {
|
||||
if (window.requestLeaderboard) {
|
||||
window.requestLeaderboard();
|
||||
}
|
||||
}, 500);
|
||||
} catch (err) {
|
||||
console.error('❌ Failed to load WASM:', err);
|
||||
document.getElementById('loading').innerHTML = '<div class="spinner"></div><p>Fehler beim Laden: ' + err.message + '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
// Menu Navigation
|
||||
function showMainMenu() {
|
||||
hideAllScreens();
|
||||
document.getElementById('menu').classList.remove('hidden');
|
||||
}
|
||||
|
||||
function showCoopMenu() {
|
||||
hideAllScreens();
|
||||
document.getElementById('coopMenu').classList.remove('hidden');
|
||||
}
|
||||
|
||||
function showSettings() {
|
||||
hideAllScreens();
|
||||
document.getElementById('settingsMenu').classList.remove('hidden');
|
||||
}
|
||||
|
||||
function showLeaderboard() {
|
||||
hideAllScreens();
|
||||
document.getElementById('leaderboardMenu').classList.remove('hidden');
|
||||
loadLeaderboard();
|
||||
}
|
||||
|
||||
function hideAllScreens() {
|
||||
document.querySelectorAll('.overlay-screen').forEach(screen => {
|
||||
screen.classList.add('hidden');
|
||||
});
|
||||
}
|
||||
|
||||
function hideMenu() {
|
||||
document.getElementById('menu').style.display = 'none';
|
||||
// Canvas sichtbar machen für Gameplay
|
||||
const canvas = document.querySelector('canvas');
|
||||
if (canvas) {
|
||||
canvas.classList.add('game-active');
|
||||
}
|
||||
}
|
||||
|
||||
function showMenu() {
|
||||
document.getElementById('menu').style.display = 'flex';
|
||||
document.getElementById('menu').classList.remove('hidden');
|
||||
showMainMenu();
|
||||
// Canvas verstecken im Menü
|
||||
const canvas = document.querySelector('canvas');
|
||||
if (canvas) {
|
||||
canvas.classList.remove('game-active');
|
||||
}
|
||||
}
|
||||
|
||||
// Game Functions
|
||||
function startSoloGame() {
|
||||
if (!wasmReady) {
|
||||
alert('Spiel wird noch geladen...');
|
||||
return;
|
||||
}
|
||||
|
||||
const playerName = document.getElementById('playerName').value || 'ANON';
|
||||
|
||||
// Store in localStorage for WASM to read
|
||||
localStorage.setItem('escape_player_name', playerName);
|
||||
localStorage.setItem('escape_game_mode', 'solo');
|
||||
localStorage.setItem('escape_room_id', '');
|
||||
|
||||
// Hide menu and show canvas
|
||||
hideAllScreens();
|
||||
gameStarted = true;
|
||||
|
||||
// Trigger WASM game start
|
||||
if (window.startGame) {
|
||||
window.startGame('solo', playerName, '');
|
||||
}
|
||||
|
||||
console.log('🎮 Solo game started:', playerName);
|
||||
}
|
||||
|
||||
function createRoom() {
|
||||
if (!wasmReady) {
|
||||
alert('Spiel wird noch geladen...');
|
||||
return;
|
||||
}
|
||||
|
||||
const playerName = document.getElementById('playerName').value || 'ANON';
|
||||
const roomID = 'R' + Math.random().toString(36).substr(2, 5).toUpperCase();
|
||||
const teamName = 'TEAM';
|
||||
|
||||
// Store in localStorage
|
||||
localStorage.setItem('escape_player_name', playerName);
|
||||
localStorage.setItem('escape_game_mode', 'coop');
|
||||
localStorage.setItem('escape_room_id', roomID);
|
||||
localStorage.setItem('escape_team_name', teamName);
|
||||
localStorage.setItem('escape_is_host', 'true');
|
||||
|
||||
// Hide menu and show canvas (Lobby wird vom WASM gezeichnet)
|
||||
hideAllScreens();
|
||||
gameStarted = true;
|
||||
|
||||
// Canvas sichtbar machen für Lobby
|
||||
const canvas = document.querySelector('canvas');
|
||||
if (canvas) {
|
||||
canvas.classList.add('game-active');
|
||||
}
|
||||
|
||||
// Trigger WASM game start
|
||||
if (window.startGame) {
|
||||
window.startGame('coop', playerName, roomID, teamName, true);
|
||||
}
|
||||
|
||||
console.log('🎮 Room created:', roomID);
|
||||
}
|
||||
|
||||
function joinRoom() {
|
||||
if (!wasmReady) {
|
||||
alert('Spiel wird noch geladen...');
|
||||
return;
|
||||
}
|
||||
|
||||
const playerName = document.getElementById('playerName').value || 'ANON';
|
||||
const roomID = document.getElementById('joinRoomCode').value.toUpperCase();
|
||||
const teamName = document.getElementById('teamNameJoin').value || 'TEAM';
|
||||
|
||||
if (!roomID || roomID.length < 4) {
|
||||
alert('Bitte gib einen gültigen Raum-Code ein!');
|
||||
return;
|
||||
}
|
||||
|
||||
// Store in localStorage
|
||||
localStorage.setItem('escape_player_name', playerName);
|
||||
localStorage.setItem('escape_game_mode', 'coop');
|
||||
localStorage.setItem('escape_room_id', roomID);
|
||||
localStorage.setItem('escape_team_name', teamName);
|
||||
localStorage.setItem('escape_is_host', 'false');
|
||||
|
||||
// Hide menu and show canvas
|
||||
hideAllScreens();
|
||||
gameStarted = true;
|
||||
|
||||
// Canvas sichtbar machen für Lobby
|
||||
const canvas = document.querySelector('canvas');
|
||||
if (canvas) {
|
||||
canvas.classList.add('game-active');
|
||||
}
|
||||
|
||||
// Trigger WASM game start
|
||||
if (window.startGame) {
|
||||
window.startGame('coop', playerName, roomID, teamName, false);
|
||||
}
|
||||
|
||||
console.log('🎮 Joining room:', roomID);
|
||||
}
|
||||
|
||||
function loadLeaderboard() {
|
||||
const list = document.getElementById('leaderboardList');
|
||||
list.innerHTML = '<div style="text-align:center; padding:20px;">Lädt Leaderboard...</div>';
|
||||
|
||||
// Request leaderboard from WASM
|
||||
if (window.requestLeaderboard) {
|
||||
window.requestLeaderboard();
|
||||
}
|
||||
|
||||
// Fallback timeout
|
||||
setTimeout(() => {
|
||||
if (list.innerHTML.includes('Lädt')) {
|
||||
list.innerHTML = '<div style="text-align:center; padding:20px; color:#888;">Keine Daten verfügbar</div>';
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// Called by WASM to update leaderboard
|
||||
function updateLeaderboard(entries) {
|
||||
// Update main leaderboard page
|
||||
const list = document.getElementById('leaderboardList');
|
||||
|
||||
// Update start screen leaderboard
|
||||
const startList = document.getElementById('startLeaderboardList');
|
||||
|
||||
if (!entries || entries.length === 0) {
|
||||
const emptyMsg = '<div style="text-align:center; padding:20px; color:#888;">Noch keine Einträge</div>';
|
||||
if (list) list.innerHTML = emptyMsg;
|
||||
if (startList) startList.innerHTML = emptyMsg;
|
||||
return;
|
||||
}
|
||||
|
||||
const html = entries.slice(0, 10).map((entry, index) => {
|
||||
const medal = index === 0 ? '🥇' : index === 1 ? '🥈' : index === 2 ? '🥉' : `${index + 1}.`;
|
||||
return `
|
||||
<div class="leaderboard-item">
|
||||
<div class="leaderboard-rank">${medal}</div>
|
||||
<div class="leaderboard-name">${entry.player_name}</div>
|
||||
<div class="leaderboard-score">${entry.score}</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
if (list) list.innerHTML = html;
|
||||
if (startList) startList.innerHTML = html;
|
||||
|
||||
console.log('📊 Leaderboard updated with', entries.length, 'entries');
|
||||
}
|
||||
|
||||
// Audio Toggle
|
||||
function toggleAudio() {
|
||||
audioMuted = !audioMuted;
|
||||
const btn = document.getElementById('mute-btn');
|
||||
|
||||
if (audioMuted) {
|
||||
btn.textContent = '🔇';
|
||||
if (window.setMusicVolume) window.setMusicVolume(0);
|
||||
if (window.setSFXVolume) window.setSFXVolume(0);
|
||||
} else {
|
||||
btn.textContent = '🔊';
|
||||
const musicVol = parseInt(localStorage.getItem('escape_music_volume') || 70) / 100;
|
||||
const sfxVol = parseInt(localStorage.getItem('escape_sfx_volume') || 70) / 100;
|
||||
if (window.setMusicVolume) window.setMusicVolume(musicVol);
|
||||
if (window.setSFXVolume) window.setSFXVolume(sfxVol);
|
||||
}
|
||||
}
|
||||
|
||||
// Settings Volume Sliders
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const musicSlider = document.getElementById('musicVolume');
|
||||
const sfxSlider = document.getElementById('sfxVolume');
|
||||
const musicValue = document.getElementById('musicValue');
|
||||
const sfxValue = document.getElementById('sfxValue');
|
||||
|
||||
if (musicSlider) {
|
||||
musicSlider.addEventListener('input', (e) => {
|
||||
const value = e.target.value;
|
||||
musicValue.textContent = value + '%';
|
||||
localStorage.setItem('escape_music_volume', value);
|
||||
|
||||
if (window.setMusicVolume && !audioMuted) {
|
||||
window.setMusicVolume(value / 100);
|
||||
}
|
||||
});
|
||||
|
||||
// Load saved value
|
||||
const savedMusic = localStorage.getItem('escape_music_volume') || 70;
|
||||
musicSlider.value = savedMusic;
|
||||
musicValue.textContent = savedMusic + '%';
|
||||
}
|
||||
|
||||
if (sfxSlider) {
|
||||
sfxSlider.addEventListener('input', (e) => {
|
||||
const value = e.target.value;
|
||||
sfxValue.textContent = value + '%';
|
||||
localStorage.setItem('escape_sfx_volume', value);
|
||||
|
||||
if (window.setSFXVolume && !audioMuted) {
|
||||
window.setSFXVolume(value / 100);
|
||||
}
|
||||
});
|
||||
|
||||
// Load saved value
|
||||
const savedSFX = localStorage.getItem('escape_sfx_volume') || 70;
|
||||
sfxSlider.value = savedSFX;
|
||||
sfxValue.textContent = savedSFX + '%';
|
||||
}
|
||||
|
||||
// Load saved player name
|
||||
const savedName = localStorage.getItem('escape_player_name');
|
||||
if (savedName) {
|
||||
document.getElementById('playerName').value = savedName;
|
||||
}
|
||||
|
||||
// Load local highscore
|
||||
const highscore = localStorage.getItem('escape_local_highscore') || 0;
|
||||
const hsElement = document.getElementById('localHighscore');
|
||||
if (hsElement) {
|
||||
hsElement.textContent = highscore;
|
||||
}
|
||||
});
|
||||
|
||||
// Keyboard shortcuts
|
||||
document.addEventListener('keydown', (e) => {
|
||||
// ESC to show menu (only if game is started)
|
||||
if (e.key === 'Escape' && gameStarted) {
|
||||
showMenu();
|
||||
gameStarted = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Show Game Over Screen (called by WASM)
|
||||
function showGameOver(score) {
|
||||
hideAllScreens();
|
||||
document.getElementById('gameOverScreen').classList.remove('hidden');
|
||||
document.getElementById('finalScore').textContent = score;
|
||||
|
||||
// Update local highscore
|
||||
const currentHS = parseInt(localStorage.getItem('escape_local_highscore') || 0);
|
||||
if (score > currentHS) {
|
||||
localStorage.setItem('escape_local_highscore', score);
|
||||
}
|
||||
|
||||
// Request leaderboard
|
||||
if (window.requestLeaderboard) {
|
||||
window.requestLeaderboard();
|
||||
}
|
||||
|
||||
console.log('💀 Game Over! Score:', score);
|
||||
}
|
||||
|
||||
// Export functions for WASM to call
|
||||
window.showMenu = showMenu;
|
||||
window.hideMenu = hideMenu;
|
||||
window.updateLeaderboard = updateLeaderboard;
|
||||
window.showGameOver = showGameOver;
|
||||
|
||||
// Initialize on load
|
||||
initWASM();
|
||||
|
||||
console.log('🎮 Game.js loaded - Retro Edition');
|
||||
Reference in New Issue
Block a user