From e770ef286de2fb78fc450eb02f71bf4628b99237 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 11 Jul 2025 14:10:57 +0000 Subject: [PATCH] Create Mobile Fighter game with 1v1 combat, weapons, and mobile controls Co-authored-by: fynnschicker12 --- MOBILE_FIGHTER_README.md | 106 +++++++++ game.js | 458 +++++++++++++++++++++++++++++++++++++++ index.html | 99 +++++++++ style.css | 343 +++++++++++++++++++++++++++++ 4 files changed, 1006 insertions(+) create mode 100644 MOBILE_FIGHTER_README.md create mode 100644 game.js create mode 100644 index.html create mode 100644 style.css diff --git a/MOBILE_FIGHTER_README.md b/MOBILE_FIGHTER_README.md new file mode 100644 index 0000000..d12c0c7 --- /dev/null +++ b/MOBILE_FIGHTER_README.md @@ -0,0 +1,106 @@ +# 🗡️ Mobile Fighter - 1v1 Kampfspiel 🛡️ + +Ein aufregendes Handy-Kampfspiel für zwei Spieler mit verschiedenen Waffen und taktischem Gameplay! + +## 🎮 Spielübersicht + +Mobile Fighter ist ein rasantes 1v1 Kampfspiel, das speziell für mobile Geräte entwickelt wurde. Zwei Spieler kämpfen gegeneinander mit verschiedenen Waffen auf demselben Bildschirm. + +## ✨ Features + +- 🎯 **1v1 Kampf**: Direkter Kampf zwischen zwei Spielern +- ⚔️ **4 verschiedene Waffen**: Schwert, Bogen, Axt und Dolch mit einzigartigen Eigenschaften +- 📱 **Mobile-optimiert**: Touch-Controls perfekt für Handys +- 🎨 **Moderne Grafiken**: Schöne Partikeleffekte und Animationen +- 💯 **Echtzeit-Kampf**: Schnelle Action mit Gesundheitsanzeigen +- 🔄 **Waffen wechseln**: Während des Spiels die Waffe ändern + +## 🗡️ Waffen-System + +### ⚔️ Schwert +- **Schaden**: Mittel (25) +- **Geschwindigkeit**: Schnell (1.2x) +- **Reichweite**: Mittel (40px) +- **Abklingzeit**: 500ms + +### 🏹 Bogen +- **Schaden**: Gering (15) +- **Geschwindigkeit**: Langsam (0.8x) +- **Reichweite**: Hoch (120px) - Fernkampf! +- **Abklingzeit**: 800ms + +### 🪓 Axt +- **Schaden**: Hoch (40) +- **Geschwindigkeit**: Sehr langsam (0.6x) +- **Reichweite**: Kurz (35px) +- **Abklingzeit**: 1000ms + +### 🗡️ Dolch +- **Schaden**: Sehr gering (12) +- **Geschwindigkeit**: Sehr schnell (1.8x) +- **Reichweite**: Sehr kurz (25px) +- **Abklingzeit**: 300ms + +## 🎮 Steuerung + +### Spieler 1 (Blau) +- **⬅️➡️⬆️⬇️**: Bewegung +- **🗡️ Angriff**: Attacke ausführen +- **🔄 Waffe**: Waffe wechseln + +### Spieler 2 (Rot) +- **⬅️➡️⬆️⬇️**: Bewegung +- **🏹 Angriff**: Attacke ausführen +- **🔄 Waffe**: Waffe wechseln + +### Tastatur (für Desktop-Test) +- **Spieler 1**: WASD für Bewegung, F für Angriff +- **Spieler 2**: Pfeiltasten für Bewegung, Leertaste für Angriff + +## 🎯 Spielregeln + +1. **Ziel**: Reduziere die Gesundheit des Gegners auf 0 +2. **Gesundheit**: Jeder Spieler startet mit 100 HP +3. **Waffen**: Verschiedene Waffen haben unterschiedliche Schadens-, Geschwindigkeits- und Reichweiten-Werte +4. **Abklingzeit**: Nach einem Angriff musst du warten, bevor du wieder angreifen kannst +5. **Bewegung**: Bewege dich strategisch, um Angriffen auszuweichen +6. **Fernkampf**: Der Bogen schießt Projektile, die anderen Waffen sind Nahkampfwaffen + +## 🚀 Wie man spielt + +1. Öffne `index.html` in einem mobilen Browser +2. Wähle deine Waffen aus dem Waffen-Menü +3. Verwende die Touch-Controls, um dich zu bewegen und anzugreifen +4. Der erste Spieler, der die Gesundheit des Gegners auf 0 reduziert, gewinnt! + +## 💡 Strategien + +- **Schwert**: Ausgewogene Waffe, gut für Anfänger +- **Bogen**: Bleibe auf Distanz und schieße Pfeile +- **Axt**: Warte auf den perfekten Moment für maximalen Schaden +- **Dolch**: Sei schnell und aggressiv mit häufigen Angriffen + +## 🔧 Technische Details + +- **HTML5 Canvas**: Für smooth 2D-Grafiken +- **Responsive Design**: Funktioniert auf allen Bildschirmgrößen +- **Touch-optimiert**: Spezielle Touch-Events für mobile Geräte +- **Partikel-System**: Coole Effekte für Angriffe und Treffer +- **Echtzeit-Updates**: 60 FPS Gameplay + +## 📱 Mobile Optimierungen + +- Touch-Action Manipulation verhindert Zooming +- Große, gut positionierte Buttons +- Responsive Layout für verschiedene Bildschirmgrößen +- Verhindert Text-Selektion und andere störende Browser-Features + +## 🎨 Visuelle Features + +- Gradient-Hintergründe und moderne UI +- Animierte Gesundheitsbalken +- Partikeleffekte bei Angriffen und Treffern +- Waffen-Emojis und Angriffsanimationen +- Schöne Schatten und Beleuchtungseffekte + +Viel Spaß beim Kämpfen! 🥊 \ No newline at end of file diff --git a/game.js b/game.js new file mode 100644 index 0000000..02d87d0 --- /dev/null +++ b/game.js @@ -0,0 +1,458 @@ +class MobileFighter { + constructor() { + this.canvas = document.getElementById('gameCanvas'); + this.ctx = this.canvas.getContext('2d'); + this.gameState = 'playing'; // 'playing', 'gameOver', 'menu' + + this.setupCanvas(); + this.initializeGame(); + this.setupEventListeners(); + this.gameLoop(); + } + + setupCanvas() { + const updateCanvasSize = () => { + const container = this.canvas.parentElement; + const rect = container.getBoundingClientRect(); + this.canvas.width = Math.min(rect.width - 20, 800); + this.canvas.height = Math.min(this.canvas.width * 0.6, 400); + }; + + updateCanvasSize(); + window.addEventListener('resize', updateCanvasSize); + } + + initializeGame() { + this.weapons = { + sword: { name: 'Schwert', emoji: '⚔️', damage: 25, speed: 1.2, range: 40, cooldown: 500 }, + bow: { name: 'Bogen', emoji: '🏹', damage: 15, speed: 0.8, range: 120, cooldown: 800 }, + axe: { name: 'Axt', emoji: '🪓', damage: 40, speed: 0.6, range: 35, cooldown: 1000 }, + dagger: { name: 'Dolch', emoji: '🗡️', damage: 12, speed: 1.8, range: 25, cooldown: 300 } + }; + + this.players = { + 1: { + x: 80, + y: this.canvas.height / 2, + health: 100, + maxHealth: 100, + weapon: 'sword', + lastAttack: 0, + size: 25, + color: '#4a90e2', + direction: 1, + attacking: false, + speed: 3 + }, + 2: { + x: this.canvas.width - 80, + y: this.canvas.height / 2, + health: 100, + maxHealth: 100, + weapon: 'bow', + lastAttack: 0, + size: 25, + color: '#e74c3c', + direction: -1, + attacking: false, + speed: 3 + } + }; + + this.projectiles = []; + this.particles = []; + this.keys = {}; + this.updateUI(); + } + + setupEventListeners() { + // Touch and click controls + document.querySelectorAll('.control-btn').forEach(btn => { + const action = btn.dataset.action; + const player = parseInt(btn.dataset.player); + + const handleAction = (e) => { + e.preventDefault(); + this.handlePlayerAction(player, action); + btn.classList.add('attacking'); + setTimeout(() => btn.classList.remove('attacking'), 200); + }; + + btn.addEventListener('touchstart', handleAction); + btn.addEventListener('click', handleAction); + }); + + // Menu controls + document.getElementById('restartBtn').addEventListener('click', () => { + this.initializeGame(); + this.gameState = 'playing'; + this.hideMenu(); + }); + + document.getElementById('weaponSelectBtn').addEventListener('click', () => { + this.showWeaponMenu(); + }); + + document.getElementById('closeWeaponMenu').addEventListener('click', () => { + this.hideWeaponMenu(); + }); + + // Weapon selection + document.querySelectorAll('.weapon-option').forEach(option => { + option.addEventListener('click', () => { + document.querySelectorAll('.weapon-option').forEach(opt => opt.classList.remove('selected')); + option.classList.add('selected'); + + const weapon = option.dataset.weapon; + const player = option.closest('#weaponMenu').dataset.currentPlayer || '1'; + this.players[player].weapon = weapon; + this.updateUI(); + }); + }); + + // Keyboard controls for desktop testing + document.addEventListener('keydown', (e) => { + this.keys[e.key] = true; + }); + + document.addEventListener('keyup', (e) => { + this.keys[e.key] = false; + }); + } + + handlePlayerAction(player, action) { + if (this.gameState !== 'playing') return; + + const p = this.players[player]; + const speed = p.speed; + + switch (action) { + case 'moveLeft': + p.x = Math.max(p.size, p.x - speed * 8); + p.direction = -1; + break; + case 'moveRight': + p.x = Math.min(this.canvas.width - p.size, p.x + speed * 8); + p.direction = 1; + break; + case 'moveUp': + p.y = Math.max(p.size, p.y - speed * 8); + break; + case 'moveDown': + p.y = Math.min(this.canvas.height - p.size, p.y + speed * 8); + break; + case 'attack': + this.attack(player); + break; + case 'switchWeapon': + this.switchWeapon(player); + break; + } + } + + switchWeapon(player) { + const weaponKeys = Object.keys(this.weapons); + const currentIndex = weaponKeys.indexOf(this.players[player].weapon); + const nextIndex = (currentIndex + 1) % weaponKeys.length; + this.players[player].weapon = weaponKeys[nextIndex]; + this.updateUI(); + } + + attack(playerId) { + const player = this.players[playerId]; + const weapon = this.weapons[player.weapon]; + const now = Date.now(); + + if (now - player.lastAttack < weapon.cooldown) return; + + player.lastAttack = now; + player.attacking = true; + + setTimeout(() => { + player.attacking = false; + }, 300); + + // Create attack effect + this.createAttackEffect(player, weapon); + + // Check for hits + const opponent = this.players[playerId === 1 ? 2 : 1]; + const distance = Math.sqrt( + Math.pow(player.x - opponent.x, 2) + + Math.pow(player.y - opponent.y, 2) + ); + + if (weapon.name === 'Bogen') { + // Projectile weapon + this.createProjectile(player, weapon, playerId); + } else if (distance <= weapon.range + player.size + opponent.size) { + // Melee weapon + this.hitPlayer(opponent, weapon.damage); + } + } + + createProjectile(player, weapon, playerId) { + const projectile = { + x: player.x + player.direction * player.size, + y: player.y, + vx: player.direction * 8, + vy: 0, + damage: weapon.damage, + owner: playerId, + size: 6, + lifetime: 100 + }; + this.projectiles.push(projectile); + } + + createAttackEffect(player, weapon) { + for (let i = 0; i < 8; i++) { + const angle = (Math.PI * 2 * i) / 8; + const particle = { + x: player.x + Math.cos(angle) * weapon.range, + y: player.y + Math.sin(angle) * weapon.range, + vx: Math.cos(angle) * 3, + vy: Math.sin(angle) * 3, + life: 20, + maxLife: 20, + color: weapon.name === 'Bogen' ? '#8e44ad' : '#f39c12' + }; + this.particles.push(particle); + } + } + + hitPlayer(player, damage) { + player.health = Math.max(0, player.health - damage); + + // Create hit effect + for (let i = 0; i < 6; i++) { + const angle = Math.random() * Math.PI * 2; + const particle = { + x: player.x, + y: player.y, + vx: Math.cos(angle) * 5, + vy: Math.sin(angle) * 5, + life: 15, + maxLife: 15, + color: '#e74c3c' + }; + this.particles.push(particle); + } + + this.updateUI(); + + if (player.health <= 0) { + this.endGame(); + } + } + + updateProjectiles() { + this.projectiles = this.projectiles.filter(projectile => { + projectile.x += projectile.vx; + projectile.y += projectile.vy; + projectile.lifetime--; + + // Check collision with opponent + const opponent = this.players[projectile.owner === 1 ? 2 : 1]; + const distance = Math.sqrt( + Math.pow(projectile.x - opponent.x, 2) + + Math.pow(projectile.y - opponent.y, 2) + ); + + if (distance <= projectile.size + opponent.size) { + this.hitPlayer(opponent, projectile.damage); + return false; // Remove projectile + } + + // Remove if out of bounds or lifetime expired + return projectile.x > 0 && projectile.x < this.canvas.width && + projectile.y > 0 && projectile.y < this.canvas.height && + projectile.lifetime > 0; + }); + } + + updateParticles() { + this.particles = this.particles.filter(particle => { + particle.x += particle.vx; + particle.y += particle.vy; + particle.vx *= 0.95; + particle.vy *= 0.95; + particle.life--; + return particle.life > 0; + }); + } + + handleKeyboardInput() { + if (this.gameState !== 'playing') return; + + // Player 1 controls (WASD + F for attack) + if (this.keys['a'] || this.keys['A']) this.handlePlayerAction(1, 'moveLeft'); + if (this.keys['d'] || this.keys['D']) this.handlePlayerAction(1, 'moveRight'); + if (this.keys['w'] || this.keys['W']) this.handlePlayerAction(1, 'moveUp'); + if (this.keys['s'] || this.keys['S']) this.handlePlayerAction(1, 'moveDown'); + if (this.keys['f'] || this.keys['F']) this.handlePlayerAction(1, 'attack'); + + // Player 2 controls (Arrow keys + Space for attack) + if (this.keys['ArrowLeft']) this.handlePlayerAction(2, 'moveLeft'); + if (this.keys['ArrowRight']) this.handlePlayerAction(2, 'moveRight'); + if (this.keys['ArrowUp']) this.handlePlayerAction(2, 'moveUp'); + if (this.keys['ArrowDown']) this.handlePlayerAction(2, 'moveDown'); + if (this.keys[' ']) this.handlePlayerAction(2, 'attack'); + } + + render() { + // Clear canvas + this.ctx.fillStyle = 'rgba(44, 82, 52, 0.1)'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + + // Draw grid pattern + this.ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)'; + this.ctx.lineWidth = 1; + for (let x = 0; x < this.canvas.width; x += 30) { + this.ctx.beginPath(); + this.ctx.moveTo(x, 0); + this.ctx.lineTo(x, this.canvas.height); + this.ctx.stroke(); + } + for (let y = 0; y < this.canvas.height; y += 30) { + this.ctx.beginPath(); + this.ctx.moveTo(0, y); + this.ctx.lineTo(this.canvas.width, y); + this.ctx.stroke(); + } + + // Draw players + Object.keys(this.players).forEach(id => { + this.drawPlayer(this.players[id], id); + }); + + // Draw projectiles + this.projectiles.forEach(projectile => { + this.ctx.fillStyle = '#9b59b6'; + this.ctx.beginPath(); + this.ctx.arc(projectile.x, projectile.y, projectile.size, 0, Math.PI * 2); + this.ctx.fill(); + }); + + // Draw particles + this.particles.forEach(particle => { + const alpha = particle.life / particle.maxLife; + this.ctx.fillStyle = particle.color + Math.floor(alpha * 255).toString(16).padStart(2, '0'); + this.ctx.beginPath(); + this.ctx.arc(particle.x, particle.y, 2, 0, Math.PI * 2); + this.ctx.fill(); + }); + } + + drawPlayer(player, id) { + const weapon = this.weapons[player.weapon]; + + // Draw player shadow + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.3)'; + this.ctx.beginPath(); + this.ctx.arc(player.x, player.y + 5, player.size, 0, Math.PI * 2); + this.ctx.fill(); + + // Draw player + this.ctx.fillStyle = player.attacking ? '#f1c40f' : player.color; + this.ctx.strokeStyle = '#fff'; + this.ctx.lineWidth = 3; + this.ctx.beginPath(); + this.ctx.arc(player.x, player.y, player.size, 0, Math.PI * 2); + this.ctx.fill(); + this.ctx.stroke(); + + // Draw weapon + this.ctx.save(); + this.ctx.translate(player.x, player.y); + this.ctx.rotate(player.direction > 0 ? 0 : Math.PI); + + this.ctx.font = '20px Arial'; + this.ctx.textAlign = 'center'; + this.ctx.fillText(weapon.emoji, weapon.range * 0.7, 5); + + if (player.attacking) { + // Draw attack range + this.ctx.strokeStyle = 'rgba(255, 255, 0, 0.5)'; + this.ctx.lineWidth = 2; + this.ctx.beginPath(); + this.ctx.arc(0, 0, weapon.range + player.size, 0, Math.PI * 2); + this.ctx.stroke(); + } + + this.ctx.restore(); + + // Draw player label + this.ctx.fillStyle = '#fff'; + this.ctx.font = '12px Arial'; + this.ctx.textAlign = 'center'; + this.ctx.fillText(`P${id}`, player.x, player.y - player.size - 10); + } + + updateUI() { + // Update health bars + const player1HealthPercent = (this.players[1].health / this.players[1].maxHealth) * 100; + const player2HealthPercent = (this.players[2].health / this.players[2].maxHealth) * 100; + + document.getElementById('player1Health').style.width = player1HealthPercent + '%'; + document.getElementById('player2Health').style.width = player2HealthPercent + '%'; + + // Update weapon displays + const weapon1 = this.weapons[this.players[1].weapon]; + const weapon2 = this.weapons[this.players[2].weapon]; + + document.getElementById('player1Weapon').textContent = `${weapon1.emoji} ${weapon1.name}`; + document.getElementById('player2Weapon').textContent = `${weapon2.emoji} ${weapon2.name}`; + } + + endGame() { + this.gameState = 'gameOver'; + const winner = this.players[1].health > 0 ? 'Spieler 1' : 'Spieler 2'; + document.getElementById('gameResult').textContent = `🏆 ${winner} gewinnt! 🏆`; + this.showMenu(); + } + + showMenu() { + document.getElementById('gameMenu').classList.remove('hidden'); + } + + hideMenu() { + document.getElementById('gameMenu').classList.add('hidden'); + } + + showWeaponMenu() { + document.getElementById('weaponMenu').classList.remove('hidden'); + } + + hideWeaponMenu() { + document.getElementById('weaponMenu').classList.add('hidden'); + } + + gameLoop() { + this.handleKeyboardInput(); + + if (this.gameState === 'playing') { + this.updateProjectiles(); + this.updateParticles(); + } + + this.render(); + requestAnimationFrame(() => this.gameLoop()); + } +} + +// Initialize the game when the page loads +document.addEventListener('DOMContentLoaded', () => { + new MobileFighter(); +}); + +// Prevent default touch behaviors that might interfere with the game +document.addEventListener('touchmove', (e) => { + e.preventDefault(); +}, { passive: false }); + +document.addEventListener('touchstart', (e) => { + if (e.target.tagName !== 'BUTTON') { + e.preventDefault(); + } +}, { passive: false }); \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..c214cd4 --- /dev/null +++ b/index.html @@ -0,0 +1,99 @@ + + + + + + Mobile Fighter - 1v1 Weapon Game + + + +
+
+

🗡️ Mobile Fighter 🛡️

+
+
+ Player 1 +
+
+
+ ⚔️ Schwert +
+
+ Player 2 +
+
+
+ 🏹 Bogen +
+
+
+ + + +
+
+

Spieler 1

+
+ + + + + + +
+
+ +
+

Spieler 2

+
+ + + + + + +
+
+
+ + + + +
+ + + + \ No newline at end of file diff --git a/style.css b/style.css new file mode 100644 index 0000000..28aed8b --- /dev/null +++ b/style.css @@ -0,0 +1,343 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + -webkit-tap-highlight-color: transparent; +} + +body { + font-family: 'Arial', sans-serif; + background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%); + min-height: 100vh; + overflow-x: hidden; + color: white; + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; +} + +#gameContainer { + max-width: 100vw; + min-height: 100vh; + display: flex; + flex-direction: column; + position: relative; +} + +header { + background: rgba(0, 0, 0, 0.8); + backdrop-filter: blur(10px); + padding: 10px; + text-align: center; + border-bottom: 2px solid #ffd700; +} + +header h1 { + font-size: 1.8rem; + margin-bottom: 10px; + text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); +} + +#gameStats { + display: flex; + justify-content: space-between; + align-items: center; + max-width: 600px; + margin: 0 auto; + gap: 20px; +} + +#player1Stats, #player2Stats { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + gap: 5px; +} + +.health-bar { + width: 100%; + max-width: 150px; + height: 20px; + background: rgba(255, 0, 0, 0.3); + border: 2px solid #fff; + border-radius: 10px; + overflow: hidden; +} + +.health-fill { + height: 100%; + width: 100%; + background: linear-gradient(90deg, #ff4444, #ffaa00, #44ff44); + transition: width 0.3s ease; +} + +#gameCanvas { + flex: 1; + background: linear-gradient(45deg, #2c5234 0%, #4a7c59 50%, #2c5234 100%); + border: 3px solid #ffd700; + margin: 10px; + border-radius: 10px; + min-height: 300px; + max-height: 400px; + display: block; + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3); +} + +#gameControls { + display: flex; + justify-content: space-between; + padding: 10px; + gap: 10px; + background: rgba(0, 0, 0, 0.6); + backdrop-filter: blur(5px); +} + +.control-panel { + flex: 1; + background: rgba(255, 255, 255, 0.1); + border-radius: 15px; + padding: 15px; + border: 2px solid rgba(255, 215, 0, 0.5); +} + +.control-panel h3 { + text-align: center; + margin-bottom: 10px; + color: #ffd700; + font-size: 1.1rem; +} + +.controls-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 8px; + max-width: 200px; + margin: 0 auto; +} + +.control-btn { + background: linear-gradient(145deg, #667eea 0%, #764ba2 100%); + border: none; + border-radius: 12px; + color: white; + font-size: 1rem; + font-weight: bold; + padding: 12px 8px; + cursor: pointer; + transition: all 0.2s ease; + border: 2px solid transparent; + text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5); + min-height: 50px; + display: flex; + align-items: center; + justify-content: center; + touch-action: manipulation; +} + +.control-btn:active { + transform: scale(0.95); + background: linear-gradient(145deg, #5a6fd8 0%, #6a4190 100%); + border-color: #ffd700; + box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.3); +} + +.attack-btn { + background: linear-gradient(145deg, #ff6b6b 0%, #ee5a24 100%); + grid-column: span 2; +} + +.attack-btn:active { + background: linear-gradient(145deg, #e55555 0%, #d4461e 100%); +} + +.weapon-btn { + background: linear-gradient(145deg, #ffa726 0%, #f57c00 100%); + grid-column: span 1; +} + +.weapon-btn:active { + background: linear-gradient(145deg, #ff9800 0%, #e65100 100%); +} + +.hidden { + display: none !important; +} + +#gameMenu, #weaponMenu { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.9); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; +} + +.menu-content { + background: linear-gradient(145deg, #1e3c72 0%, #2a5298 100%); + border-radius: 20px; + padding: 30px; + text-align: center; + border: 3px solid #ffd700; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); + max-width: 90vw; + max-height: 90vh; + overflow-y: auto; +} + +.menu-content h2 { + margin-bottom: 20px; + color: #ffd700; + font-size: 1.5rem; +} + +.menu-btn { + background: linear-gradient(145deg, #667eea 0%, #764ba2 100%); + border: none; + border-radius: 12px; + color: white; + font-size: 1.1rem; + font-weight: bold; + padding: 15px 25px; + margin: 10px; + cursor: pointer; + transition: all 0.2s ease; + border: 2px solid transparent; + min-width: 200px; +} + +.menu-btn:hover, .menu-btn:active { + transform: scale(0.98); + border-color: #ffd700; + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); +} + +.weapon-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); + gap: 15px; + margin: 20px 0; +} + +.weapon-option { + background: rgba(255, 255, 255, 0.1); + border-radius: 15px; + padding: 20px; + cursor: pointer; + transition: all 0.3s ease; + border: 2px solid transparent; + text-align: center; +} + +.weapon-option:hover, .weapon-option.selected { + background: rgba(255, 215, 0, 0.2); + border-color: #ffd700; + transform: scale(1.05); +} + +.weapon-option span { + font-size: 2rem; + display: block; + margin-bottom: 10px; +} + +.weapon-option p { + font-weight: bold; + margin-bottom: 5px; + color: #ffd700; +} + +.weapon-option small { + color: #ccc; + font-size: 0.8rem; +} + +/* Mobile-specific optimizations */ +@media (max-width: 768px) { + header h1 { + font-size: 1.5rem; + } + + #gameStats { + flex-direction: column; + gap: 10px; + } + + #player1Stats, #player2Stats { + width: 100%; + } + + #gameControls { + flex-direction: column; + gap: 15px; + } + + .controls-grid { + grid-template-columns: repeat(3, 1fr); + gap: 6px; + } + + .control-btn { + font-size: 0.9rem; + padding: 10px 6px; + min-height: 45px; + } + + .weapon-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 480px) { + header h1 { + font-size: 1.3rem; + } + + .control-btn { + font-size: 0.8rem; + padding: 8px 4px; + min-height: 40px; + } + + .menu-content { + padding: 20px; + } + + .weapon-grid { + grid-template-columns: 1fr; + } +} + +/* Touch feedback */ +.control-btn:active, +.weapon-option:active, +.menu-btn:active { + background-color: rgba(255, 215, 0, 0.3) !important; +} + +/* Prevent zooming on double tap */ +.control-btn, .weapon-option, .menu-btn { + touch-action: manipulation; +} + +/* Animation for game elements */ +@keyframes pulse { + 0% { transform: scale(1); } + 50% { transform: scale(1.05); } + 100% { transform: scale(1); } +} + +.attacking { + animation: pulse 0.3s ease-in-out; +} + +/* Game canvas responsive sizing */ +#gameCanvas { + width: calc(100vw - 20px); + height: auto; + aspect-ratio: 4/3; +} \ No newline at end of file