City Runner Game body { font-family: 'Bungee', cursive; background-color: #1a202c; color: white; overflow: hidden; /* Screen ko scroll honay se rokein */ touch-action: manipulation; /* Mobile par tap events behtar banayein */ } #game-container { width: 100%; max-width: 450px; /* Mobile screen jaisa size */ height: 80vh; /* Lambai ko screen ke hisab se set karein */ max-height: 800px; cursor: pointer; border: 4px solid #4A5568; border-radius: 12px; box-shadow: 0 10px 20px rgba(0,0,0,0.5); } canvas { width: 100%; height: 100%; display: block; border-radius: 8px; } /* Ad Modal Styling */ #ad-modal { background-color: rgba(0, 0, 0, 0.85); z-index: 100; } .ad-box { background-color: #2d3748; width: 90%; max-width: 350px; min-height: 300px; /* Ad ke liye jagah */ } .spinner { border: 4px solid rgba(255, 255, 255, 0.3); border-radius: 50%; border-top: 4px solid #fff; width: 24px; height: 24px; animation: spin 1s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } City Runner Score: 0 | High: 0 City Runner Obstacles se bachein aur score banayein! "Aaj ki Tip" button dabayein! Start Game ✨ Aaj ki Tip Advertisement Ad ke baad game shuru ho jayegi... Continue Game const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); // UI Elements const scoreDisplay = document.getElementById('score-display'); const highScoreDisplay = document.getElementById('high-score-display'); const uiScreen = document.getElementById('ui-screen'); const uiTitle = document.getElementById('ui-title'); const uiSubtitle = document.getElementById('ui-subtitle'); const startButton = document.getElementById('start-button'); const geminiTipButton = document.getElementById('gemini-tip-button'); const tipText = document.getElementById('tip-text'); // Ad Elements const adModal = document.getElementById('ad-modal'); const closeAdButton = document.getElementById('close-ad-button'); // Game State let gameState = 'START'; let score = 0; let highScore = localStorage.getItem('cityRunnerHighScore') || 0; let lastAdScore = 0; // Player let player = { x: 50, y: 150, width: 30, height: 50, dy: 0, gravity: 0.5, jumpStrength: 12, isGrounded: true }; // Obstacles let obstacles = []; let gameSpeed = 3; let frameCount = 0; function resizeCanvas() { const container = document.getElementById('game-container'); canvas.width = container.clientWidth; canvas.height = container.clientHeight; player.y = canvas.height - player.height - 10; } // =================================== // === GEMINI API FUNCTION START === // =================================== async function getGamerTip() { tipText.innerHTML = ''; // Loading spinner geminiTipButton.disabled = true; const prompt = "Give a short, funny, or motivational tip for a player of an endless runner game. The tip should be in Roman Urdu (like 'Aage dekho, neeche nahi!'). Keep it under 15 words."; let chatHistory = [{ role: "user", parts: [{ text: prompt }] }]; const payload = { contents: chatHistory }; const apiKey = ""; // API key is handled by the environment const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`; try { const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (!response.ok) { throw new Error(`API request failed with status ${response.status}`); } const result = await response.json(); if (result.candidates && result.candidates.length > 0 && result.candidates[0].content && result.candidates[0].content.parts) { const text = result.candidates[0].content.parts[0].text; tipText.textContent = text; } else { tipText.textContent = "Thori der baad try karein."; } } catch (error) { console.error("Gemini API Error:", error); tipText.textContent = "Connection error. Tip nahi mil saki."; } finally { geminiTipButton.disabled = false; } } // ================================= // === GEMINI API FUNCTION END === // ================================= function showAd(nextStateAfterAd) { adModal.classList.remove('hidden'); adModal.classList.add('flex'); try { (adsbygoogle = window.adsbygoogle || []).push({}); } catch (e) { console.error("Ad request fail ho gayi:", e); } // ***FIX:*** "Continue" button ab foran show hoga. closeAdButton.classList.remove('hidden'); closeAdButton.onclick = () => { hideAd(); gameState = nextStateAfterAd; if (gameState === 'PLAYING') { if (!isGameOver()) requestAnimationFrame(gameLoop); } else if (gameState === 'START') { resetGame(); uiScreen.style.display = 'flex'; } }; } function hideAd() { adModal.classList.add('hidden'); adModal.classList.remove('flex'); } function drawPlayer() { ctx.fillStyle = '#4299E1'; ctx.fillRect(player.x, player.y, player.width, player.height); } function drawObstacles() { obstacles.forEach(obstacle => { ctx.fillStyle = '#F56565'; ctx.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height); }); } function drawGround() { ctx.fillStyle = '#4A5568'; ctx.fillRect(0, canvas.height - 10, canvas.width, 10); } function updateGame() { player.dy += player.gravity; player.y += player.dy; player.isGrounded = false; if (player.y > canvas.height - player.height - 10) { player.y = canvas.height - player.height - 10; player.dy = 0; player.isGrounded = true; } frameCount++; if(frameCount % 100 === 0) { const height = Math.random() * 50 + 20; obstacles.push({ x: canvas.width, y: canvas.height - height - 10, width: 25, height: height }); } obstacles.forEach(obstacle => { obstacle.x -= gameSpeed; }); obstacles = obstacles.filter(obs => obs.x + obs.width > 0); if (checkCollision()) { gameState = 'GAME_OVER'; } score++; gameSpeed += 0.001; if (score > 0 && score % 500 === 0) { // Har 500 score par ad lastAdScore = score; gameState = 'AD_DURING_GAME'; } } function checkCollision() { for (let obs of obstacles) { if ( player.x < obs.x + obs.width && player.x + player.width > obs.x && player.y < obs.y + obs.height && player.y + player.height > obs.y) { return true; } } return false; } function isGameOver() { return gameState === 'GAME_OVER' || gameState === 'AD_AFTER_GAME'; } function playerJump() { if (player.isGrounded && !isGameOver() && gameState === 'PLAYING') { player.dy = -player.jumpStrength; } } function resetGame() { if (score > highScore) { highScore = score; localStorage.setItem('cityRunnerHighScore', highScore); } score = 0; lastAdScore = 0; gameSpeed = 3; player.y = canvas.height - player.height - 10; player.dy = 0; obstacles = []; uiTitle.textContent = "Game Over"; uiSubtitle.textContent = `Aapka Score: ${Math.floor(highScore)}`; startButton.textContent = "Play Again"; } function gameLoop() { ctx.clearRect(0, 0, canvas.width, canvas.height); switch (gameState) { case 'AD_BEFORE_GAME': showAd('PLAYING'); return; case 'AD_DURING_GAME': showAd('PLAYING'); return; case 'GAME_OVER': gameState = 'AD_AFTER_GAME'; // Fall-through case 'AD_AFTER_GAME': showAd('START'); return; case 'PLAYING': drawGround(); drawPlayer(); drawObstacles(); updateGame(); break; } scoreDisplay.textContent = Math.floor(score); highScoreDisplay.textContent = Math.floor(highScore); if (!isGameOver()) { requestAnimationFrame(gameLoop); } } // --- Event Listeners --- startButton.addEventListener('click', () => { uiScreen.style.display = 'none'; gameState = 'AD_BEFORE_GAME'; gameLoop(); }); geminiTipButton.addEventListener('click', getGamerTip); window.addEventListener('keydown', (e) => { if (e.code === 'Space' || e.code === 'ArrowUp') playerJump(); }); document.body.addEventListener('touchstart', playerJump); document.getElementById('game-container').addEventListener('mousedown', playerJump); // --- Initial Setup --- window.addEventListener('resize', resizeCanvas); resizeCanvas(); highScoreDisplay.textContent = Math.floor(highScore);