| <!DOCTYPE html> |
| <html lang="ar" dir="rtl"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>لعبة الصراخ المتعددة اللاعبين</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| @import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@400;700;900&display=swap'); |
| |
| body { |
| font-family: 'Tajawal', sans-serif; |
| background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%); |
| min-height: 100vh; |
| color: white; |
| } |
| |
| .player-card { |
| transition: all 0.3s ease; |
| box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2); |
| } |
| |
| .player-card:hover { |
| transform: translateY(-5px); |
| } |
| |
| .volume-bar { |
| height: 10px; |
| background: rgba(255, 255, 255, 0.2); |
| border-radius: 5px; |
| overflow: hidden; |
| } |
| |
| .volume-level { |
| height: 100%; |
| background: linear-gradient(90deg, #4facfe 0%, #00f2fe 100%); |
| transition: width 0.1s ease; |
| } |
| |
| .pulse { |
| animation: pulse 1.5s infinite; |
| } |
| |
| @keyframes pulse { |
| 0% { transform: scale(1); } |
| 50% { transform: scale(1.05); } |
| 100% { transform: scale(1); } |
| } |
| |
| .winner-crown { |
| position: absolute; |
| top: -15px; |
| right: 50%; |
| transform: translateX(50%); |
| font-size: 24px; |
| color: gold; |
| text-shadow: 0 0 5px rgba(0, 0, 0, 0.5); |
| } |
| </style> |
| </head> |
| <body class="p-4"> |
| <div class="max-w-4xl mx-auto"> |
| <header class="text-center mb-8"> |
| <h1 class="text-4xl font-bold mb-2">🎤 لعبة الصراخ الجماعية</h1> |
| <p class="text-xl opacity-80">من يصرخ بأعلى صوت يفوز!</p> |
| </header> |
| |
| <div class="flex flex-col md:flex-row gap-6 mb-8"> |
| <div class="bg-white/10 backdrop-blur-md rounded-xl p-6 flex-1"> |
| <h2 class="text-2xl font-bold mb-4">إضافة لاعب جديد</h2> |
| |
| <div class="mb-4"> |
| <label for="playerName" class="block mb-2">اسم اللاعب</label> |
| <input type="text" id="playerName" class="w-full p-3 rounded-lg bg-white/20 border border-white/30 focus:outline-none focus:ring-2 focus:ring-blue-400"> |
| </div> |
| |
| <button id="addPlayerBtn" class="w-full bg-blue-500 hover:bg-blue-600 text-white font-bold py-3 px-4 rounded-lg transition flex items-center justify-center gap-2"> |
| <i class="fas fa-user-plus"></i> إضافة لاعب |
| </button> |
| |
| <div class="mt-6"> |
| <div class="flex items-center justify-between mb-2"> |
| <span>حساسية الصوت</span> |
| <span id="sensitivityValue">50%</span> |
| </div> |
| <input type="range" id="sensitivitySlider" min="1" max="100" value="50" class="w-full h-2 bg-white/20 rounded-lg appearance-none cursor-pointer"> |
| </div> |
| |
| <div class="mt-6 bg-black/20 p-4 rounded-lg"> |
| <h3 class="font-bold mb-2">تعليمات اللعبة:</h3> |
| <ul class="list-disc list-inside space-y-1 text-sm"> |
| <li>اضغط على زر إضافة لاعب لإدخال اسمك</li> |
| <li>اسمح للعبة باستخدام الميكروفون</li> |
| <li>صرخ بأعلى صوتك لتحصل على نقاط</li> |
| <li>اللاعب الذي يحصل على أعلى نقاط يفوز</li> |
| </ul> |
| </div> |
| </div> |
| |
| <div class="bg-white/10 backdrop-blur-md rounded-xl p-6 flex-1"> |
| <div class="flex justify-between items-center mb-4"> |
| <h2 class="text-2xl font-bold">النتائج</h2> |
| <div class="flex items-center gap-2"> |
| <i class="fas fa-trophy text-yellow-400"></i> |
| <span id="gameTime">00:00</span> |
| </div> |
| </div> |
| |
| <div id="playersContainer" class="space-y-4"> |
| <div class="text-center py-8 text-white/40"> |
| <i class="fas fa-users text-4xl mb-2"></i> |
| <p>لا يوجد لاعبين بعد. أضف لاعبين لبدء اللعبة!</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| <div class="bg-white/10 backdrop-blur-md rounded-xl p-6 text-center"> |
| <h2 class="text-2xl font-bold mb-4">حالة الميكروفون</h2> |
| <div class="flex flex-col items-center"> |
| <div class="w-24 h-24 bg-blue-500/20 rounded-full flex items-center justify-center mb-4 relative" id="micVisual"> |
| <i class="fas fa-microphone text-3xl"></i> |
| <div id="volumeIndicator" class="absolute inset-0 rounded-full border-4 border-blue-400 opacity-0"></div> |
| </div> |
| <p id="micStatus" class="mb-4">جارٍ طلب إذن استخدام الميكروفون...</p> |
| <div class="w-full max-w-xs mx-auto"> |
| <div class="volume-bar mb-2"> |
| <div id="volumeLevel" class="volume-level" style="width: 0%"></div> |
| </div> |
| <div class="flex justify-between text-sm"> |
| <span>هادئ</span> |
| <span>صاخب</span> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| |
| const playersContainer = document.getElementById('playersContainer'); |
| const addPlayerBtn = document.getElementById('addPlayerBtn'); |
| const playerNameInput = document.getElementById('playerName'); |
| const micStatus = document.getElementById('micStatus'); |
| const volumeLevel = document.getElementById('volumeLevel'); |
| const micVisual = document.getElementById('micVisual'); |
| const volumeIndicator = document.getElementById('volumeIndicator'); |
| const sensitivitySlider = document.getElementById('sensitivitySlider'); |
| const sensitivityValue = document.getElementById('sensitivityValue'); |
| const gameTime = document.getElementById('gameTime'); |
| |
| |
| let players = []; |
| let audioContext; |
| let analyser; |
| let microphone; |
| let isMicAllowed = false; |
| let gameInterval; |
| let seconds = 0; |
| let sensitivity = 0.5; |
| |
| |
| sensitivitySlider.addEventListener('input', function() { |
| sensitivity = this.value / 100; |
| sensitivityValue.textContent = `${this.value}%`; |
| }); |
| |
| |
| addPlayerBtn.addEventListener('click', function() { |
| const name = playerNameInput.value.trim(); |
| |
| if (!name) { |
| alert('الرجاء إدخال اسم اللاعب'); |
| return; |
| } |
| |
| if (players.length >= 6) { |
| alert('يمكنك إضافة 6 لاعبين كحد أقصى'); |
| return; |
| } |
| |
| const player = { |
| id: Date.now(), |
| name: name, |
| score: 0, |
| isActive: false |
| }; |
| |
| players.push(player); |
| renderPlayers(); |
| playerNameInput.value = ''; |
| |
| |
| if (players.length > 0 && !gameInterval) { |
| startGame(); |
| } |
| |
| |
| if (!isMicAllowed) { |
| initMicrophone(); |
| } |
| }); |
| |
| |
| function renderPlayers() { |
| if (players.length === 0) { |
| playersContainer.innerHTML = ` |
| <div class="text-center py-8 text-white/40"> |
| <i class="fas fa-users text-4xl mb-2"></i> |
| <p>لا يوجد لاعبين بعد. أضف لاعبين لبدء اللعبة!</p> |
| </div> |
| `; |
| return; |
| } |
| |
| |
| const sortedPlayers = [...players].sort((a, b) => b.score - a.score); |
| |
| playersContainer.innerHTML = sortedPlayers.map((player, index) => { |
| const isWinner = index === 0 && player.score > 0; |
| |
| return ` |
| <div class="player-card bg-white/5 rounded-lg p-4 relative ${isWinner ? 'border-2 border-yellow-400' : ''}"> |
| ${isWinner ? '<div class="winner-crown"><i class="fas fa-crown"></i></div>' : ''} |
| <div class="flex justify-between items-center mb-2"> |
| <h3 class="font-bold text-xl">${player.name}</h3> |
| <span class="text-2xl font-bold ${isWinner ? 'text-yellow-400' : ''}">${player.score}</span> |
| </div> |
| <div class="flex items-center gap-2 text-sm"> |
| <span>مستوى الصوت:</span> |
| <div class="flex-1 bg-white/10 rounded-full h-2"> |
| <div class="bg-blue-400 h-2 rounded-full" style="width: ${player.isActive ? '100%' : '0%'}; transition: width 0.3s ease;"></div> |
| </div> |
| <button onclick="removePlayer(${player.id})" class="text-red-400 hover:text-red-300"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| </div> |
| `; |
| }).join(''); |
| } |
| |
| |
| window.removePlayer = function(id) { |
| players = players.filter(player => player.id !== id); |
| renderPlayers(); |
| |
| |
| if (players.length === 0 && gameInterval) { |
| stopGame(); |
| } |
| }; |
| |
| |
| function startGame() { |
| seconds = 0; |
| updateGameTime(); |
| gameInterval = setInterval(() => { |
| seconds++; |
| updateGameTime(); |
| |
| |
| if (players.length > 0) { |
| |
| players.forEach(player => player.isActive = false); |
| |
| |
| const randomIndex = Math.floor(Math.random() * players.length); |
| players[randomIndex].isActive = true; |
| |
| renderPlayers(); |
| } |
| }, 5000); |
| } |
| |
| |
| function stopGame() { |
| clearInterval(gameInterval); |
| gameInterval = null; |
| gameTime.textContent = "00:00"; |
| } |
| |
| |
| function updateGameTime() { |
| const mins = Math.floor(seconds / 60).toString().padStart(2, '0'); |
| const secs = (seconds % 60).toString().padStart(2, '0'); |
| gameTime.textContent = `${mins}:${secs}`; |
| } |
| |
| |
| async function initMicrophone() { |
| try { |
| micStatus.textContent = 'جارٍ الاتصال بالميكروفون...'; |
| |
| audioContext = new (window.AudioContext || window.webkitAudioContext)(); |
| analyser = audioContext.createAnalyser(); |
| analyser.fftSize = 32; |
| |
| const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); |
| isMicAllowed = true; |
| microphone = audioContext.createMediaStreamSource(stream); |
| microphone.connect(analyser); |
| |
| micStatus.textContent = 'الميكروفون جاهز! ابدأ بالصراخ!'; |
| micVisual.classList.add('pulse'); |
| |
| |
| analyzeSound(); |
| } catch (error) { |
| console.error('Error accessing microphone:', error); |
| micStatus.textContent = 'فشل في الوصول إلى الميكروفون. يرجى التحقق من الأذونات.'; |
| micVisual.classList.add('text-red-400'); |
| } |
| } |
| |
| |
| function analyzeSound() { |
| const bufferLength = analyser.frequencyBinCount; |
| const dataArray = new Uint8Array(bufferLength); |
| |
| function checkVolume() { |
| analyser.getByteFrequencyData(dataArray); |
| |
| let sum = 0; |
| for (let i = 0; i < bufferLength; i++) { |
| sum += dataArray[i]; |
| } |
| |
| const average = sum / bufferLength; |
| const normalizedVolume = Math.min(average / 255, 1); |
| const scaledVolume = Math.pow(normalizedVolume, 2) * 100; |
| |
| |
| volumeLevel.style.width = `${scaledVolume}%`; |
| |
| |
| if (scaledVolume > 30) { |
| volumeIndicator.style.opacity = '1'; |
| volumeIndicator.style.borderWidth = '8px'; |
| volumeIndicator.style.borderColor = `rgba(74, 144, 226, ${normalizedVolume})`; |
| |
| |
| micVisual.style.transform = `scale(${1 + normalizedVolume * 0.2})`; |
| } else { |
| volumeIndicator.style.opacity = '0'; |
| micVisual.style.transform = 'scale(1)'; |
| } |
| |
| |
| if (gameInterval) { |
| const activePlayer = players.find(player => player.isActive); |
| if (activePlayer && scaledVolume > 20) { |
| |
| const pointsToAdd = Math.floor(scaledVolume * sensitivity); |
| activePlayer.score += pointsToAdd; |
| |
| |
| if (pointsToAdd > 5) { |
| renderPlayers(); |
| } |
| } |
| } |
| |
| requestAnimationFrame(checkVolume); |
| } |
| |
| checkVolume(); |
| } |
| |
| |
| renderPlayers(); |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=moadfande/mick-fn" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |