
Arcade racing games
80s-style arcade racing games
Prompt
Create a fun arcade racer in JS. The game should be set in a city and be fast-paced
A system prompt was added to support web rendering
Here is a fun, fast-paced arcade racing game. Use the **Left** and **Right** arrow keys to dodge traffic. The longer you survive, the faster you go and the higher your score! ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>City Arcade Racer</title> <style> @import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap'); body { margin: 0; padding: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #1a1a2e; color: #e0e0e0; font-family: 'Press Start 2P', cursive; overflow: hidden; } #game-container { position: relative; box-shadow: 0 0 30px rgba(0, 255, 255, 0.5); border: 3px solid #00ffff; background-color: #0d0d1e; } canvas { display: block; background-color: #222; /* Road color */ } .ui-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; background-color: rgba(0, 0, 0, 0.7); color: #fff; cursor: pointer; backdrop-filter: blur(5px); } .ui-overlay h1 { font-size: 2.5em; color: #00ffff; text-shadow: 0 0 15px #00ffff; margin-bottom: 20px; } .ui-overlay p { font-size: 1.2em; margin-top: 20px; animation: blink 1.5s linear infinite; } #score-display { position: absolute; top: 15px; left: 15px; font-size: 1.5em; color: #ff00ff; text-shadow: 0 0 10px #ff00ff; } .hidden { display: none; } @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } </style> </head> <body> <div id="game-container"> <canvas id="gameCanvas"></canvas> <div id="score-display">SCORE: 0</div> <div id="startScreen" class="ui-overlay"> <h1>Neon Racer</h1> <p>Click to Start</p> <p style="font-size: 0.8em; margin-top: 40px; animation: none;">Use Arrow Keys to Dodge</p> </div> <div id="gameOverScreen" class="ui-overlay hidden"> <h1>Game Over</h1> <p id="finalScore"></p> <p>Click to Restart</p> </div> </div> <script> // --- Game Setup --- const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const scoreDisplay = document.getElementById('score-display'); const startScreen = document.getElementById('startScreen'); const gameOverScreen = document.getElementById('gameOverScreen'); const finalScoreDisplay = document.getElementById('finalScore'); const gameWidth = 400; const gameHeight = 600; canvas.width = gameWidth; canvas.height = gameHeight; let gameState = 'start'; // 'start', 'playing', 'gameOver' let keys = {}; let score = 0; let gameSpeed = 3; // --- Audio Setup (Web Audio API for no external files) --- let audioCtx; let engineSound, engineGain; const createAudio = () => { if (audioCtx) return; audioCtx = new (window.AudioContext || window.webkitAudioContext)(); // Engine Sound engineSound = audioCtx.createOscillator(); engineGain = audioCtx.createGain(); engineSound.type = 'sawtooth'; engineSound.frequency.setValueAtTime(50, audioCtx.currentTime); engineGain.gain.setValueAtTime(0, audioCtx.currentTime); engineSound.connect(engineGain).connect(audioCtx.destination); engineSound.start(); }; const playCrashSound = () => { if (!audioCtx) return; const crashGain = audioCtx.createGain(); crashGain.gain.setValueAtTime(0.5, audioCtx.currentTime); crashGain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 1); const noise = audioCtx.createBufferSource(); const buffer = audioCtx.createBuffer(1, audioCtx.sampleRate * 1, audioCtx.sampleRate); const data = buffer.getChannelData(0); for (let i = 0; i < data.length; i++) { data[i] = Math.random() * 2 - 1; } noise.buffer = buffer; noise.connect(crashGain).connect(audioCtx.destination); noise.start(); } // --- Game Objects --- const player = { width: 40, height: 60, x: gameWidth / 2 - 20, y: gameHeight - 80, speed: 5, color: '#00ffff', trail: [] }; let obstacles = []; let roadLines = []; let buildings = []; // --- Event Listeners --- window.addEventListener('keydown', (e) => { keys[e.key] = true; }); window.addEventListener('keyup', (e) => { keys[e.key] = false; }); window.addEventListener('click', () => { // Audio context must be started by user interaction createAudio(); if (gameState === 'start') { gameState = 'playing'; startScreen.classList.add('hidden'); scoreDisplay.classList.remove('hidden'); engineGain.gain.linearRampToValueAtTime(0.1, audioCtx.currentTime + 0.5); gameLoop(); } else if (gameState === 'gameOver') { resetGame(); gameState = 'playing'; gameOverScreen.classList.add('hidden'); scoreDisplay.classList.remove('hidden'); engineGain.gain.linearRampToValueAtTime(0.1, audioCtx.currentTime + 0.5); gameLoop(); } }); // --- Helper Functions --- const random = (min, max) => Math.random() * (max - min) + min; function resetGame() { score = 0; gameSpeed = 3; player.x = gameWidth / 2 - player.width / 2; player.trail = []; obstacles = []; roadLines = []; buildings = []; initScenery(); } function initScenery() { for (let i = 0; i < gameHeight / 50; i++) { createRoadLine(i * 60); } for (let i = 0; i < gameHeight / 80; i++) { createBuilding(i * 100); } } function isColliding(rect1, rect2) { return rect1.x < rect2.x + rect2.width && rect1.x + rect1.width > rect2.x && rect1.y < rect2.y + rect2.height && rect1.y + rect1.height > rect2.y; } // --- Object Creation --- function createObstacle() { const laneWidth = gameWidth / 4; const lane = Math.floor(random(0, 4)); const carWidth = 40; const carHeight = 60; const colors = ['#ff00ff', '#ff8c00', '#ffff00', '#7cfc00']; obstacles.push({ width: carWidth, height: carHeight, x: lane * laneWidth + (laneWidth - carWidth)/2, y: -carHeight, color: colors[Math.floor(random(0, colors.length))] }); } function createRoadLine(yPos) { roadLines.push({ x: gameWidth / 2 - 2.5, y: yPos, width: 5, height: 30 }); } function createBuilding(yPos) { const width = random(40, 80); const height = random(80, 200); const side = Math.random() > 0.5 ? 'left' : 'right'; buildings.push({ x: side === 'left' ? -10 : gameWidth - width + 10, y: yPos, width: width, height: height }); } // --- Update Logic --- function update() { // Player movement if (keys.ArrowLeft && player.x > 0) player.x -= player.speed; if (keys.ArrowRight && player.x < gameWidth - player.width) player.x += player.speed; // Player trail player.trail.push({ x: player.x, y: player.y, width: player.width, opacity: 1 }); player.trail.forEach(t => t.opacity -= 0.05); player.trail = player.trail.filter(t => t.opacity > 0); // Update road lines and buildings (scrolling) [...roadLines, ...buildings].forEach(item => { item.y += gameSpeed; }); if (roadLines[0] && roadLines[0].y > gameHeight) { roadLines.shift(); createRoadLine(-30); } if (buildings[0] && buildings[0].y > gameHeight) { buildings.shift(); createBuilding(-100); } // Update obstacles obstacles.forEach(obs => { obs.y += gameSpeed * 0.8; // Make obstacles slightly slower for better reaction time }); obstacles = obstacles.filter(obs => obs.y < gameHeight); // Spawn new obstacles if (Math.random() < 0.01 + gameSpeed * 0.005) { createObstacle(); } // Collision detection obstacles.forEach(obs => { const playerHitbox = { ...player, x: player.x + 5, width: player.width - 10 }; // Make hitbox slightly smaller if (isColliding(playerHitbox, obs)) { gameState = 'gameOver'; playCrashSound(); engineGain.gain.linearRampToValueAtTime(0, audioCtx.currentTime + 0.1); } }); // Update score and speed score += Math.floor(gameSpeed); gameSpeed += 0.003; if (audioCtx) { engineSound.frequency.linearRampToValueAtTime(50 + gameSpeed * 10, audioCtx.currentTime + 0.1); } } // --- Drawing Logic --- function draw() { // Clear canvas & draw road ctx.clearRect(0, 0, gameWidth, gameHeight); ctx.fillStyle = '#111'; // Sidewalk color ctx.fillRect(0, 0, gameWidth, gameHeight); ctx.fillStyle = '#222'; // Road color ctx.fillRect(40, 0, gameWidth - 80, gameHeight); // Draw Buildings buildings.forEach(b => { ctx.fillStyle = '#0d0d1e'; ctx.fillRect(b.x, b.y, b.width, b.height); ctx.strokeStyle = '#ff00ff'; ctx.lineWidth = 2; ctx.strokeRect(b.x, b.y, b.width, b.height); }); // Draw Road Lines ctx.fillStyle = '#666'; roadLines.forEach(line => { ctx.fillRect(line.x, line.y, line.width, line.height); }); // Draw Obstacles obstacles.forEach(obs => { ctx.fillStyle = obs.color; ctx.fillRect(obs.x, obs.y, obs.width, obs.height); ctx.fillStyle = 'rgba(255, 255, 255, 0.3)'; // Windshield ctx.fillRect(obs.x + 5, obs.y + 10, obs.width - 10, 15); }); // Draw Player Trail player.trail.forEach(t => { ctx.fillStyle = `rgba(0, 255, 255, ${t.opacity * 0.5})`; ctx.beginPath(); ctx.rect(t.x, t.y + player.height / 2, t.width, player.height / 2); ctx.fill(); }); // Draw Player ctx.fillStyle = player.color; ctx.fillRect(player.x, player.y, player.width, player.height); // Add some detail to player car ctx.fillStyle = '#fff'; // Windshield ctx.fillRect(player.x + 5, player.y + 10, player.width - 10, 15); ctx.fillStyle = '#ff4444'; // Tail lights ctx.fillRect(player.x + 4, player.y + player.height - 8, 8, 6); ctx.fillRect(player.x + player.width - 12, player.y + player.height - 8, 8, 6); // Update Score Display scoreDisplay.textContent = `SCORE: ${score}`; } function updateUI() { if (gameState === 'gameOver') { // Screen shake effect canvas.style.animation = 'shake 0.5s'; setTimeout(() => canvas.style.animation = '', 500); gameOverScreen.classList.remove('hidden'); scoreDisplay.classList.add('hidden'); finalScoreDisplay.textContent = `Final Score: ${score}`; } } // --- Main Game Loop --- function gameLoop() { if (gameState !== 'playing') { updateUI(); return; } update(); draw(); requestAnimationFrame(gameLoop); } // --- Initial Start --- resetGame(); draw(); // Draw initial state </script> </body> </html> ```
Drag to resize
Here's a fun, fast-paced arcade-style racer set in a city. This HTML5 game uses Canvas for rendering and includes simple controls (arrow keys) to dodge traffic: ```html <!DOCTYPE html> <html> <head> <title>City Arcade Racer</title> <style> body { margin: 0; overflow: hidden; background: #000; display: flex; justify-content: center; align-items: center; height: 100vh; font-family: Arial, sans-serif; } canvas { border: 2px solid #444; box-shadow: 0 0 20px #00f; } #gameOver { position: absolute; color: white; font-size: 48px; text-align: center; display: none; } #score { position: absolute; top: 10px; left: 10px; color: white; font-size: 24px; } </style> </head> <body> <canvas id="gameCanvas"></canvas> <div id="gameOver">GAME OVER<br><span style="font-size:24px">Press R to restart</span></div> <div id="score">Score: 0</div> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const gameOverDiv = document.getElementById('gameOver'); const scoreDiv = document.getElementById('score'); // Set canvas size canvas.width = 400; canvas.height = 600; // Game variables let score = 0; let gameSpeed = 3; let gameRunning = true; let roadWidth = canvas.width * 0.6; let roadX = (canvas.width - roadWidth) / 2; // Player car const player = { x: canvas.width / 2, y: canvas.height - 100, width: 30, height: 50, speed: 5, color: '#3498db' }; // Opponent cars let cars = []; const carColors = ['#e74c3c', '#f1c40f', '#2ecc71', '#9b59b6', '#1abc9c']; // Road markers let markers = []; for (let i = -50; i < canvas.height; i += 100) { markers.push(i); } // Background buildings let buildings = []; for (let i = 0; i < 10; i++) { buildings.push({ x: Math.random() < 0.5 ? 0 : canvas.width - 50, y: Math.random() * canvas.height, width: 50, height: 100 + Math.random() * 200, color: `rgb(${Math.floor(50 + Math.random() * 100)}, ${Math.floor(50 + Math.random() * 100)}, ${Math.floor(50 + Math.random() * 100)})` }); } // Controls const keys = { ArrowLeft: false, ArrowRight: false, ArrowUp: false, ArrowDown: false }; window.addEventListener('keydown', (e) => { if (keys.hasOwnProperty(e.key)) { keys[e.key] = true; } if (e.key === 'r' && !gameRunning) { resetGame(); } }); window.addEventListener('keyup', (e) => { if (keys.hasOwnProperty(e.key)) { keys[e.key] = false; } }); function resetGame() { score = 0; gameSpeed = 3; gameRunning = true; cars = []; player.x = canvas.width / 2; gameOverDiv.style.display = 'none'; } function spawnCar() { if (Math.random() < 0.02) { const lane = Math.random() < 0.5 ? roadX + 20 : roadX + roadWidth - 50; cars.push({ x: lane, y: -50, width: 30, height: 50, speed: 2 + Math.random() * gameSpeed, color: carColors[Math.floor(Math.random() * carColors.length)] }); } } function update() { if (!gameRunning) return; // Update player position if (keys.ArrowLeft && player.x > roadX + 10) { player.x -= player.speed; } if (keys.ArrowRight && player.x < roadX + roadWidth - player.width - 10) { player.x += player.speed; } // Update road markers for (let i = 0; i < markers.length; i++) { markers[i] += gameSpeed; if (markers[i] > canvas.height) { markers[i] = -50; } } // Update buildings for (let i = 0; i < buildings.length; i++) { buildings[i].y += gameSpeed / 2; if (buildings[i].y > canvas.height) { buildings[i].y = -buildings[i].height; } } // Update cars for (let i = cars.length - 1; i >= 0; i--) { cars[i].y += cars[i].speed; // Check collision if ( player.x < cars[i].x + cars[i].width && player.x + player.width > cars[i].x && player.y < cars[i].y + cars[i].height && player.y + player.height > cars[i].y ) { gameRunning = false; gameOverDiv.style.display = 'block'; } // Remove cars that are off screen if (cars[i].y > canvas.height) { cars.splice(i, 1); score++; scoreDiv.textContent = `Score: ${score}`; // Increase difficulty if (score % 5 === 0) { gameSpeed += 0.2; } } } spawnCar(); } function draw() { // Clear canvas ctx.fillStyle = '#2c3e50'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Draw buildings ctx.fillStyle = '#34495e'; for (let i = 0; i < buildings.length; i++) { const b = buildings[i]; ctx.fillStyle = b.color; ctx.fillRect(b.x, b.y, b.width, b.height); // Windows ctx.fillStyle = '#ecf0f1'; for (let wy = b.y + 10; wy < b.y + b.height; wy += 20) { for (let wx = b.x + 5; wx < b.x + b.width; wx += 15) { if (Math.random() > 0.3) { ctx.fillRect(wx, wy, 8, 8); } } } } // Draw road ctx.fillStyle = '#7f8c8d'; ctx.fillRect(roadX, 0, roadWidth, canvas.height); // Draw road markers ctx.fillStyle = '#f1c40f'; for (let i = 0; i < markers.length; i++) { ctx.fillRect(canvas.width / 2 - 5, markers[i], 10, 30); } // Draw cars for (let i = 0; i < cars.length; i++) { const car = cars[i]; ctx.fillStyle = car.color; ctx.fillRect(car.x, car.y, car.width, car.height); // Car details ctx.fillStyle = '#000'; ctx.fillRect(car.x + 5, car.y + 10, 20, 10); ctx.fillRect(car.x + 5, car.y + 30, 20, 10); } // Draw player ctx.fillStyle = player.color; ctx.fillRect(player.x, player.y, player.width, player.height); // Player car details ctx.fillStyle = '#000'; ctx.fillRect(player.x + 5, player.y + 10, 20, 10); ctx.fillRect(player.x + 5, player.y + 30, 20, 10); ctx.fillStyle = '#f1c40f'; ctx.fillRect(player.x + 10, player.y + 5, 10, 5); // headlights ctx.fillRect(player.x + 10, player.y + 40, 10, 5); // taillights } function gameLoop() { update(); draw(); requestAnimationFrame(gameLoop); } gameLoop(); </script> </body> </html> ``` This game features: 1. A city backdrop with randomly generated buildings 2. Fast-paced racing where you dodge incoming traffic 3. Increasing difficulty as your score goes up 4. Simple controls (left/right arrows to move) 5. Colorful opponent cars 6. Score tracking 7. Game over screen with restart option (press 'R') The game gets progressively faster as you score points by successfully dodging cars. The buildings scroll by to give a sense of speed, and the road markers help with depth perception. You can copy this entire code into an HTML file and open it in any modern browser to play.
Drag to resize
# Arcade City Racer I'll create a fast-paced arcade-style racing game set in a city environment with colorful graphics, dynamic movement, and increasing difficulty. ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Arcade City Racer</title> <style> body { margin: 0; padding: 0; display: flex; justify-content: center; align-items: center; min-height: 100vh; background: linear-gradient(135deg, #1a2a6c, #b21f1f, #1a2a6c); font-family: 'Arial Rounded MT Bold', 'Arial', sans-serif; overflow: hidden; } .game-container { position: relative; width: 800px; height: 600px; box-shadow: 0 0 30px rgba(0, 0, 0, 0.6); border-radius: 10px; overflow: hidden; } canvas { background: #111; display: block; } .ui-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; } .title { position: absolute; top: 20px; left: 0; width: 100%; text-align: center; font-size: 48px; font-weight: bold; color: #ffcc00; text-shadow: 0 0 10px rgba(255, 204, 0, 0.7), 0 0 20px rgba(255, 204, 0, 0.5), 3px 3px 0 #ff3300; letter-spacing: 2px; transform: perspective(500px) rotateX(20deg); animation: title-pulse 2s infinite alternate; } .score { position: absolute; top: 90px; left: 20px; font-size: 24px; color: #fff; text-shadow: 0 0 5px #00ccff; } .speed { position: absolute; top: 90px; right: 20px; font-size: 24px; color: #fff; text-shadow: 0 0 5px #ff3300; } .message { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 36px; color: #ffcc00; text-shadow: 0 0 10px rgba(255, 204, 0, 0.7); text-align: center; opacity: 0; transition: opacity 0.3s; } .controls { position: absolute; bottom: 20px; left: 0; width: 100%; text-align: center; color: #fff; font-size: 18px; text-shadow: 0 0 5px #00ccff; } .start-button { position: absolute; top: 60%; left: 50%; transform: translate(-50%, -50%); padding: 15px 40px; font-size: 24px; background: linear-gradient(to bottom, #ff3300, #cc0000); color: white; border: none; border-radius: 50px; cursor: pointer; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); pointer-events: auto; transition: all 0.2s; } .start-button:hover { transform: translate(-50%, -50%) scale(1.05); box-shadow: 0 7px 20px rgba(0, 0, 0, 0.6); } .start-button:active { transform: translate(-50%, -50%) scale(0.95); } .city-skyline { position: absolute; bottom: 0; left: 0; width: 100%; height: 150px; background: linear-gradient(to top, #333, #222); z-index: 1; } .building { position: absolute; bottom: 0; background: #222; width: 40px; height: 100px; } .building:before { content: ''; position: absolute; top: -20px; left: 5px; width: 30px; height: 20px; background: #333; clip-path: polygon(50% 0%, 0% 100%, 100% 100%); } @keyframes title-pulse { 0% { text-shadow: 0 0 10px rgba(255, 204, 0, 0.7), 0 0 20px rgba(255, 204, 0, 0.5), 3px 3px 0 #ff3300; } 100% { text-shadow: 0 0 15px rgba(255, 204, 0, 0.9), 0 0 30px rgba(255, 204, 0, 0.7), 5px 5px 0 #ff5500; } } @keyframes road-move { 0% { background-position: 0 0; } 100% { background-position: 0 40px; } } </style> </head> <body> <div class="game-container"> <canvas id="gameCanvas" width="800" height="600"></canvas> <div class="ui-overlay"> <div class="title">ARCADE CITY RACER</div> <div class="score">SCORE: <span id="scoreValue">0</span></div> <div class="speed">SPEED: <span id="speedValue">0</span> MPH</div> <div class="message" id="message">GAME OVER</div> <button class="start-button" id="startButton">START RACE</button> <div class="controls">CONTROLS: ← → ARROWS TO MOVE</div> </div> </div> <script> // Game variables const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const scoreValue = document.getElementById('scoreValue'); const speedValue = document.getElementById('speedValue'); const message = document.getElementById('message'); const startButton = document.getElementById('startButton'); let gameRunning = false; let score = 0; let speed = 0; let maxSpeed = 0; let playerX = canvas.width / 2; let roadOffset = 0; let obstacles = []; let lastObstacleTime = 0; let animationId; let roadLines = []; let particles = []; let gameTime = 0; // Initialize road lines for (let i = 0; i < 20; i++) { roadLines.push({ x: canvas.width / 2 - 5, y: i * 40, width: 10, height: 20 }); } // Player car const playerCar = { x: playerX, y: canvas.height - 100, width: 50, height: 90, color: '#ff3300', draw: function() { // Car body ctx.fillStyle = this.color; ctx.fillRect(this.x - this.width/2, this.y - this.height/2, this.width, this.height); // Car details ctx.fillStyle = '#1a1a1a'; ctx.fillRect(this.x - this.width/2 + 5, this.y - this.height/2 + 5, this.width - 10, 20); ctx.fillRect(this.x - this.width/2 + 5, this.y + this.height/2 - 25, this.width - 10, 20); // Windows ctx.fillStyle = '#aaccff'; ctx.fillRect(this.x - this.width/2 + 10, this.y - this.height/2 + 30, this.width - 20, 30); // Headlights ctx.fillStyle = '#ffff00'; ctx.fillRect(this.x - this.width/2 + 5, this.y + this.height/2 - 10, 8, 5); ctx.fillRect(this.x + this.width/2 - 13, this.y + this.height/2 - 10, 8, 5); // Wheels ctx.fillStyle = '#333'; ctx.fillRect(this.x - this.width/2 - 5, this.y - this.height/2 + 10, 5, 20); ctx.fillRect(this.x + this.width/2, this.y - this.height/2 + 10, 5, 20); ctx.fillRect(this.x - this.width/2 - 5, this.y + this.height/2 - 30, 5, 20); ctx.fillRect(this.x + this.width/2, this.y + this.height/2 - 30, 5, 20); } }; // Obstacle cars function createObstacle() { const lane = Math.floor(Math.random() * 3); // 0 = left, 1 = center, 2 = right let x; if (lane === 0) x = canvas.width / 2 - 100; else if (lane === 1) x = canvas.width / 2; else x = canvas.width / 2 + 100; const colors = ['#00ccff', '#ff00ff', '#00ff99', '#ffcc00']; const color = colors[Math.floor(Math.random() * colors.length)]; obstacles.push({ x: x, y: -100, width: 50, height: 90, color: color, speed: 5 + Math.random() * 3 }); } // Create particle effect function createParticles(x, y, color, count) { for (let i = 0; i < count; i++) { particles.push({ x: x, y: y, size: Math.random() * 8 + 2, speedX: (Math.random() - 0.5) * 10, speedY: (Math.random() - 0.5) * 10, color: color, life: 30 }); } } // Draw road function drawRoad() { // Road ctx.fillStyle = '#444'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Road markings ctx.fillStyle = '#ffff00'; for (let line of roadLines) { ctx.fillRect(line.x - line.width/2, line.y - roadOffset, line.width, line.height); } // Road sides ctx.fillStyle = '#333'; ctx.fillRect(0, 0, 100, canvas.height); ctx.fillRect(canvas.width - 100, 0, 100, canvas.height); // Road side markings ctx.fillStyle = '#ff3300'; ctx.fillRect(95, 0, 5, canvas.height); ctx.fillRect(canvas.width - 100, 0, 5, canvas.height); } // Draw buildings in background function drawBuildings() { ctx.fillStyle = '#1a1a1a'; for (let i = 0; i < 20; i++) { const height = 50 + Math.random() * 150; ctx.fillRect(i * 50, canvas.height - height, 40, height); // Windows ctx.fillStyle = '#333366'; for (let w = 0; w < 4; w++) { for (let h = 0; h < Math.floor(height / 20); h++) { if (Math.random() > 0.3) { ctx.fillRect(i * 50 + 5 + w * 10, canvas.height - height + 10 + h * 20, 8, 15); } } } ctx.fillStyle = '#1a1a1a'; } } // Check collision function checkCollision(rect1, rect2) { return rect1.x < rect2.x + rect2.width && rect1.x + rect1.width > rect2.x && rect1.y < rect2.y + rect2.height && rect1.y + rect1.height > rect2.y; } // Game loop function gameLoop() { if (!gameRunning) return; // Clear canvas ctx.clearRect(0, 0, canvas.width, canvas.height); // Update game time gameTime++; // Update road offset for moving effect roadOffset += speed / 5; if (roadOffset >= 40) roadOffset = 0; // Draw road drawRoad(); // Draw buildings drawBuildings(); // Update and draw obstacles for (let i = obstacles.length - 1; i >= 0; i--) { const obstacle = obstacles[i]; obstacle.y += obstacle.speed + speed / 10; // Draw obstacle car ctx.fillStyle = obstacle.color; ctx.fillRect(obstacle.x - obstacle.width/2, obstacle.y - obstacle.height/2, obstacle.width, obstacle.height); // Car details ctx.fillStyle = '#1a1a1a'; ctx.fillRect(obstacle.x - obstacle.width/2 + 5, obstacle.y - obstacle.height/2 + 5, obstacle.width - 10, 20); ctx.fillRect(obstacle.x - obstacle.width/2 + 5, obstacle.y + obstacle.height/2 - 25, obstacle.width - 10, 20); // Windows ctx.fillStyle = '#aaccff'; ctx.fillRect(obstacle.x - obstacle.width/2 + 10, obstacle.y - obstacle.height/2 + 30, obstacle.width - 20, 30); // Wheels ctx.fillStyle = '#333'; ctx.fillRect(obstacle.x - obstacle.width/2 - 5, obstacle.y - obstacle.height/2 + 10, 5, 20); ctx.fillRect(obstacle.x + obstacle.width/2, obstacle.y - obstacle.height/2 + 10, 5, 20); ctx.fillRect(obstacle.x - obstacle.width/2 - 5, obstacle.y + obstacle.height/2 - 30, 5, 20); ctx.fillRect(obstacle.x + obstacle.width/2, obstacle.y + obstacle.height/2 - 30, 5, 20); // Remove obstacles that are off screen if (obstacle.y > canvas.height + 100) { obstacles.splice(i, 1); score += 10; scoreValue.textContent = score; } // Check collision const playerRect = { x: playerCar.x - playerCar.width/2, y: playerCar.y - playerCar.height/2, width: playerCar.width, height: playerCar.height }; const obstacleRect = { x: obstacle.x - obstacle.width/2, y: obstacle.y - obstacle.height/2, width: obstacle.width, height: obstacle.height }; if (checkCollision(playerRect, obstacleRect)) { createParticles(playerCar.x, playerCar.y, playerCar.color, 30); createParticles(obstacle.x, obstacle.y, obstacle.color, 30); gameOver(); } } // Create new obstacles if (gameTime - lastObstacleTime > 60 - Math.min(speed, 50)) { createObstacle(); lastObstacleTime = gameTime; } // Draw player car playerCar.draw(); // Update and draw particles for (let i = particles.length - 1; i >= 0; i--) { const p = particles[i]; p.x += p.speedX; p.y += p.speedY; p.life--; ctx.fillStyle = p.color; ctx.globalAlpha = p.life / 30; ctx.beginPath(); ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2); ctx.fill(); if (p.life <= 0) { particles.splice(i, 1); } } ctx.globalAlpha = 1; // Increase speed over time if (gameTime % 100 === 0 && speed < 120) { speed += 2; speedValue.textContent = speed; if (speed > maxSpeed) maxSpeed = speed; } // Add score for speed if (gameTime % 10 === 0) { score += Math.floor(speed / 10); scoreValue.textContent = score; } animationId = requestAnimationFrame(gameLoop); } // Game over function function gameOver() { gameRunning = false; cancelAnimationFrame(animationId); message.textContent = `GAME OVER! SCORE: ${score}`; message.style.opacity = '1'; startButton.style.display = 'block'; } // Start game function function startGame() { gameRunning = true; score = 0; speed = 40; maxSpeed = 40; playerX = canvas.width / 2; obstacles = []; particles = []; gameTime = 0; lastObstacleTime = 0; message.style.opacity = '0'; startButton.style.display = 'none'; scoreValue.textContent = '0'; speedValue.textContent = '40'; gameLoop(); } // Event listeners startButton.addEventListener('click', startGame); document.addEventListener('keydown', function(e) { if (!gameRunning) return; if (e.key === 'ArrowLeft' && playerX > canvas.width / 2 - 100) { playerX -= 100; } if (e.key === 'ArrowRight' && playerX < canvas.width / 2 + 100) { playerX += 100; } playerCar.x = playerX; }); // Initialize player position playerCar.x = playerX; </script> </body> </html> ``` ## Game Features 1. **Fast-Paced Racing Action**: The game starts at 40 MPH and gradually increases speed up to 120 MPH. 2. **City Environment**: - Dynamic road with moving markings - Building skyline in the background - Neon-style color scheme 3. **Gameplay**: - Control your car with left/right arrow keys - Avoid colorful obstacle cars - Score increases as you survive longer and go faster - Collisions create particle explosion effects 4. **Visual Elements**: - Animated road for speed effect - Particle explosions on collisions - Detailed car designs - Glowing UI elements 5. **Game States**: - Start screen with "START RACE" button - In-game score and speed display - Game over screen with final score To play, simply open the HTML file in a browser and click "START RACE". Use the left and right arrow keys to dodge the oncoming traffic!
Drag to resize
```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>City Rush - Arcade Racer</title> <style> body { margin: 0; padding: 0; background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%); font-family: 'Arial', sans-serif; overflow: hidden; } #gameContainer { position: relative; width: 100vw; height: 100vh; background: linear-gradient(180deg, #87CEEB 0%, #98FB98 50%, #228B22 100%); } canvas { display: block; background: #333; } #ui { position: absolute; top: 20px; left: 20px; color: white; font-size: 24px; font-weight: bold; text-shadow: 2px 2px 4px rgba(0,0,0,0.8); z-index: 10; } #controls { position: absolute; bottom: 20px; left: 20px; color: white; font-size: 16px; text-shadow: 2px 2px 4px rgba(0,0,0,0.8); z-index: 10; } #gameOver { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(0,0,0,0.9); color: white; padding: 40px; border-radius: 20px; text-align: center; font-size: 24px; display: none; z-index: 20; } button { background: #ff6b6b; color: white; border: none; padding: 15px 30px; font-size: 18px; border-radius: 10px; cursor: pointer; margin-top: 20px; transition: background 0.3s; } button:hover { background: #ff5252; } </style> </head> <body> <div id="gameContainer"> <canvas id="gameCanvas"></canvas> <div id="ui"> <div>Speed: <span id="speed">0</span> mph</div> <div>Score: <span id="score">0</span></div> <div>Distance: <span id="distance">0</span> m</div> </div> <div id="controls"> Use ARROW KEYS or WASD to steer and accelerate/brake </div> <div id="gameOver"> <h2>Game Over!</h2> <div>Final Score: <span id="finalScore">0</span></div> <div>Distance Traveled: <span id="finalDistance">0</span> m</div> <button onclick="restartGame()">Play Again</button> </div> </div> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); // Set canvas size canvas.width = window.innerWidth; canvas.height = window.innerHeight; // Game variables let game = { player: { x: canvas.width / 2, y: canvas.height - 150, width: 30, height: 60, speed: 0, maxSpeed: 15, acceleration: 0.3, friction: 0.95, turnSpeed: 0 }, camera: { x: 0, y: 0 }, cars: [], buildings: [], roadLines: [], particles: [], score: 0, distance: 0, gameRunning: true, keys: {}, roadWidth: 400, laneCount: 4 }; // Input handling document.addEventListener('keydown', (e) => { game.keys[e.key.toLowerCase()] = true; }); document.addEventListener('keyup', (e) => { game.keys[e.key.toLowerCase()] = false; }); // Initialize game objects function initGame() { // Create buildings for (let i = 0; i < 50; i++) { createBuilding(i); } // Create initial traffic for (let i = 0; i < 15; i++) { createCar(); } // Create road lines for (let i = 0; i < 100; i++) { game.roadLines.push({ x: canvas.width / 2 - 20, y: i * 80 - 2000 }); } } function createBuilding(index) { const side = Math.random() > 0.5 ? 'left' : 'right'; const x = side === 'left' ? Math.random() * (canvas.width / 2 - game.roadWidth / 2 - 100) : canvas.width / 2 + game.roadWidth / 2 + Math.random() * (canvas.width / 2 - game.roadWidth / 2 - 100); game.buildings.push({ x: x, y: index * 200 - 1000, width: 80 + Math.random() * 120, height: 100 + Math.random() * 200, color: `hsl(${200 + Math.random() * 60}, 30%, ${30 + Math.random() * 30}%)` }); } function createCar() { const lanes = []; const laneWidth = game.roadWidth / game.laneCount; for (let i = 0; i < game.laneCount; i++) { lanes.push(canvas.width / 2 - game.roadWidth / 2 + laneWidth / 2 + i * laneWidth); } game.cars.push({ x: lanes[Math.floor(Math.random() * lanes.length)], y: -Math.random() * 2000 - 100, width: 25, height: 50, speed: 2 + Math.random() * 4, color: `hsl(${Math.random() * 360}, 70%, 50%)` }); } function createParticle(x, y, color) { for (let i = 0; i < 5; i++) { game.particles.push({ x: x + Math.random() * 20 - 10, y: y + Math.random() * 20 - 10, vx: Math.random() * 6 - 3, vy: Math.random() * 6 - 3, life: 30, color: color }); } } function updatePlayer() { // Handle input if (game.keys['arrowup'] || game.keys['w']) { game.player.speed = Math.min(game.player.speed + game.player.acceleration, game.player.maxSpeed); } if (game.keys['arrowdown'] || game.keys['s']) { game.player.speed = Math.max(game.player.speed - game.player.acceleration * 2, -game.player.maxSpeed / 2); } if (game.keys['arrowleft'] || game.keys['a']) { game.player.turnSpeed = -8; } else if (game.keys['arrowright'] || game.keys['d']) { game.player.turnSpeed = 8; } else { game.player.turnSpeed = 0; } // Apply friction game.player.speed *= game.player.friction; // Move player game.player.x += game.player.turnSpeed; // Keep player on road const roadLeft = canvas.width / 2 - game.roadWidth / 2; const roadRight = canvas.width / 2 + game.roadWidth / 2; game.player.x = Math.max(roadLeft + game.player.width / 2, Math.min(roadRight - game.player.width / 2, game.player.x)); // Update camera and distance if (game.player.speed > 0) { game.camera.y -= game.player.speed; game.distance += game.player.speed * 0.1; game.score += Math.floor(game.player.speed); } // Create speed particles if (game.player.speed > 8) { createParticle(game.player.x, game.player.y + game.player.height, '#ffff00'); } } function updateCars() { game.cars.forEach((car, index) => { car.y += car.speed + game.player.speed; // Remove cars that are off screen if (car.y > canvas.height + 100) { game.cars.splice(index, 1); createCar(); // Add a new car } // Check collision with player if (checkCollision(game.player, car)) { createParticle(car.x, car.y, '#ff0000'); endGame(); } }); } function updateBuildings() { game.buildings.forEach(building => { building.y += game.player.speed; if (building.y > canvas.height + 200) { building.y -= 10000; } }); } function updateRoadLines() { game.roadLines.forEach(line => { line.y += game.player.speed; if (line.y > canvas.height + 50) { line.y -= 8000; } }); } function updateParticles() { game.particles.forEach((particle, index) => { particle.x += particle.vx; particle.y += particle.vy + game.player.speed; particle.life--; if (particle.life <= 0) { game.particles.splice(index, 1); } }); } function checkCollision(rect1, rect2) { return rect1.x < rect2.x + rect2.width && rect1.x + rect1.width > rect2.x && rect1.y < rect2.y + rect2.height && rect1.y + rect1.height > rect2.y; } function draw() { // Clear canvas with sky gradient const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height); gradient.addColorStop(0, '#87CEEB'); gradient.addColorStop(1, '#228B22'); ctx.fillStyle = gradient; ctx.fillRect(0, 0, canvas.width, canvas.height); // Draw buildings game.buildings.forEach(building => { ctx.fillStyle = building.color; ctx.fillRect(building.x, building.y, building.width, building.height); // Add windows ctx.fillStyle = '#ffff99'; for (let i = 0; i < building.width / 15; i++) { for (let j = 0; j < building.height / 20; j++) { if (Math.random() > 0.7) { ctx.fillRect(building.x + i * 15 + 5, building.y + j * 20 + 10, 8, 8); } } } }); // Draw road ctx.fillStyle = '#333'; ctx.fillRect(canvas.width / 2 - game.roadWidth / 2, 0, game.roadWidth, canvas.height); // Draw road lines ctx.fillStyle = '#fff'; game.roadLines.forEach(line => { ctx.fillRect(line.x, line.y, 3, 40); for (let i = 1; i < game.laneCount; i++) { ctx.fillRect(canvas.width / 2 - game.roadWidth / 2 + i * (game.roadWidth / game.laneCount), line.y, 2, 30); } }); // Draw cars game.cars.forEach(car => { ctx.fillStyle = car.color; ctx.fillRect(car.x - car.width / 2, car.y - car.height / 2, car.width, car.height); // Add car details ctx.fillStyle = '#fff'; ctx.fillRect(car.x - car.width / 2 + 2, car.y - car.height / 2 + 2, car.width - 4, 8); ctx.fillStyle = '#ff0000'; ctx.fillRect(car.x - car.width / 2 + 2, car.y + car.height / 2 - 8, car.width - 4, 6); }); // Draw player ctx.fillStyle = '#ff6b6b'; ctx.fillRect(game.player.x - game.player.width / 2, game.player.y - game.player.height / 2, game.player.width, game.player.height); // Add player details ctx.fillStyle = '#fff'; ctx.fillRect(game.player.x - game.player.width / 2 + 2, game.player.y - game.player.height / 2 + 5, game.player.width - 4, 8); ctx.fillStyle = '#ffff00'; ctx.fillRect(game.player.x - game.player.width / 2 + 2, game.player.y + game.player.height / 2 - 8, game.player.width - 4, 6); // Draw particles game.particles.forEach(particle => { ctx.fillStyle = particle.color; ctx.globalAlpha = particle.life / 30; ctx.fillRect(particle.x, particle.y, 3, 3); ctx.globalAlpha = 1; }); } function updateUI() { document.getElementById('speed').textContent = Math.floor(game.player.speed * 10); document.getElementById('score').textContent = Math.floor(game.score); document.getElementById('distance').textContent = Math.floor(game.distance); } function endGame() { game.gameRunning = false; document.getElementById('finalScore').textContent = Math.floor(game.score); document.getElementById('finalDistance').textContent = Math.floor(game.distance); document.getElementById('gameOver').style.display = 'block'; } function restartGame() { // Reset game state game.player.x = canvas.width / 2; game.player.speed = 0; game.cars = []; game.buildings = []; game.roadLines = []; game.particles = []; game.score = 0; game.distance = 0; game.gameRunning = true; game.camera.y = 0; document.getElementById('gameOver').style.display = 'none'; initGame(); } function gameLoop() { if (game.gameRunning) { updatePlayer(); updateCars(); updateBuildings(); updateRoadLines(); updateParticles(); } draw(); updateUI(); requestAnimationFrame(gameLoop); } // Handle window resize window.addEventListener('resize', () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }); // Start the game initGame(); gameLoop(); </script> </body> </html> ``` This is a fast-paced arcade racing game set in a city with the following features: 🏎️ **Gameplay:** - Control your red sports car using arrow keys or WASD - Navigate through traffic while building speed - Avoid collisions with other colored cars - Drive through a procedurally generated city with buildings 🎮 **Features:** - Responsive controls for steering and acceleration/braking - Speed-based particle effects when going fast - Dynamic traffic that moves at different speeds - City skyline with randomly lit windows - Real-time score, speed, and distance tracking - Game over screen with restart functionality 🌃 **Visual Elements:** - Multi-lane highway with proper road markings - Colorful city buildings on both sides - Smooth gradient sky background - Collision effects with explosion particles - Speed indicator and comprehensive UI The game emphasizes fast-paced action while requiring skill to weave through traffic and maintain high speeds for better scores!
Drag to resize
```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>City Rush – Mini Arcade Racer</title> <style> html,body{ margin:0; height:100%; background:#222; overflow:hidden; font-family:Arial,Helvetica,sans-serif; color:#fff; } #ui{ position:fixed; top:10px; left:50%; transform:translateX(-50%); text-align:center; pointer-events:none; font-size:22px; text-shadow:0 0 5px #000; } #ui span{ margin:0 15px; } #msg{ position:fixed; top:50%; left:50%; transform:translate(-50%,-50%); text-align:center; font-size:32px; background:rgba(0,0,0,.7); padding:25px 40px; border-radius:10px; display:none; } #msg button{ margin-top:20px; padding:10px 25px; font-size:20px; cursor:pointer; background:#ff5050; border:none; border-radius:5px; color:#fff; } canvas{ display:block; } </style> </head> <body> <canvas id="gameCanvas"></canvas> <div id="ui"> <span id="scoreLabel">SCORE: 0</span> <span id="speedLabel">SPEED: 0 km/h</span> </div> <div id="msg"> <div id="msgText"></div> <button id="restartBtn">RESTART ( SPACE )</button> </div> <script> (() => { const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const uiScore = document.getElementById('scoreLabel'); const uiSpeed = document.getElementById('speedLabel'); const msgBox = document.getElementById('msg'); const msgText = document.getElementById('msgText'); const restartBtn = document.getElementById('restartBtn'); let W, H; function resize(){ W = canvas.width = window.innerWidth; H = canvas.height = window.innerHeight; } window.addEventListener('resize', resize); resize(); // Game constants const roadWidth = 400; const laneCount = 3; const laneWidth = roadWidth / laneCount; const carWidth = 50; const carHeight = 90; const buildingWidth = 80; const maxSpeed = 12; // Game variables let gameState; // 'running' | 'gameover' let keys = {left:false,right:false}; let obstacles = []; let buildings = []; let stripeOffset=0; let score = 0; let speed = 4; // starts slow, ramps up let timeSinceStart=0; const player = { x: 0, y: 0, lane: 1 }; function startGame(){ obstacles.length = 0; buildings.length = 0; stripeOffset = score = timeSinceStart = 0; speed = 4; player.lane = 1; player.x = W/2 - laneWidth/2 - laneWidth + (laneWidth-player.width)/2; player.y = H - carHeight - 30; gameState = 'running'; msgBox.style.display='none'; requestAnimationFrame(loop); } // Input window.addEventListener('keydown', e=>{ if(e.code==='ArrowLeft' || e.code==='KeyA') keys.left=true; if(e.code==='ArrowRight'|| e.code==='KeyD') keys.right=true; if(gameState==='gameover' && e.code==='Space') startGame(); }); window.addEventListener('keyup', e=>{ if(e.code==='ArrowLeft' || e.code==='KeyA') keys.left=false; if(e.code==='ArrowRight'|| e.code==='KeyD') keys.right=false; }); restartBtn.addEventListener('click',startGame); // Helpers function rand(min,max){return Math.random()*(max-min)+min;} function collides(a,b){ return !(a.x+a.w < b.x || a.x > b.x+b.w || a.y+a.h < b.y || a.y > b.y+b.h); } // Main loop let lastTime=0; function loop(t){ if(gameState!=='running') return; const dt = (t - lastTime)/16.666; // approx frames lastTime = t; update(dt); draw(); requestAnimationFrame(loop); } function update(dt){ // Speed ramp-up speed += 0.005*dt; if(speed > maxSpeed) speed = maxSpeed; stripeOffset += speed*dt*4; if(stripeOffset>40) stripeOffset-=40; // Player lane change if(keys.left && player.lane>0){ player.lane--; keys.left=false; } if(keys.right && player.lane<laneCount-1){ player.lane++; keys.right=false; } player.x = (W/2 - roadWidth/2) + player.lane*laneWidth + (laneWidth-carWidth)/2; // Spawn obstacles if(Math.random() < 0.04*dt){ const lane = Math.floor(Math.random()*laneCount); obstacles.push({ lane, x: (W/2 - roadWidth/2)+lane*laneWidth+(laneWidth-carWidth)/2, y: -carHeight, w: carWidth, h: carHeight, color: 'hsl('+rand(0,360)+',70%,50%)' }); } // Spawn buildings for side-scroll if(Math.random() < 0.1*dt){ const side = Math.random()<0.5 ? 'left' : 'right'; buildings.push({ side, x: side==='left' ? W/2-roadWidth/2-buildingWidth : W/2+roadWidth/2, y: -rand(80,160), w: buildingWidth, h: rand(120,220), color:'#'+Math.floor(rand(0x444444,0xaaaaaa)).toString(16) }); } // Update obstacles for(let i=obstacles.length-1;i>=0;--i){ const o = obstacles[i]; o.y += speed*dt*6; if(o.y>H+100) obstacles.splice(i,1); else if(collides({x:player.x,y:player.y,w:carWidth,h:carHeight},{x:o.x,y:o.y,w:o.w,h:o.h})){ gameOver(); } } // Update buildings for(let i=buildings.length-1;i>=0;--i){ const b = buildings[i]; b.y += speed*dt*4; if(b.y>H+50) buildings.splice(i,1); } // Score timeSinceStart += dt; score += speed*dt*0.5; uiScore.textContent = 'SCORE: '+Math.floor(score); uiSpeed.textContent = 'SPEED: '+Math.floor(speed*30)+' km/h'; } function draw(){ ctx.fillStyle='#111'; ctx.fillRect(0,0,W,H); // road ctx.fillStyle='#444'; ctx.fillRect(W/2-roadWidth/2,0,roadWidth,H); // lane stripes ctx.strokeStyle='#eee'; ctx.lineWidth=4; ctx.setLineDash([20,20]); ctx.lineDashOffset = -stripeOffset; for(let i=1;i<laneCount;i++){ const x = W/2-roadWidth/2 + i*laneWidth; ctx.beginPath(); ctx.moveTo(x,0); ctx.lineTo(x,H); ctx.stroke(); } ctx.setLineDash([]); // buildings buildings.forEach(b=>{ ctx.fillStyle=b.color; ctx.fillRect(b.x,b.y,b.w,b.h); // windows ctx.fillStyle='rgba(255,255,255,.2)'; for(let wy=4;wy<b.h-10;wy+=16){ for(let wx=4;wx<b.w-10;wx+=16){ if(Math.random()<0.5){ ctx.fillRect(b.x+wx,b.y+wy,8,10); } } } }); // player's car ctx.fillStyle='#00b3ff'; ctx.fillRect(player.x,player.y,carWidth,carHeight); ctx.fillStyle='#fff'; ctx.fillRect(player.x+10,player.y+10,carWidth-20,carHeight-60); // windshield ctx.fillStyle='#333'; ctx.fillRect(player.x+8,player.y+carHeight-28,carWidth-16,20); // rear // obstacles obstacles.forEach(o=>{ ctx.fillStyle=o.color; ctx.fillRect(o.x,o.y,o.w,o.h); ctx.fillStyle='#000'; ctx.fillRect(o.x+8,o.y+8,o.w-16,o.h-60); }); } function gameOver(){ gameState='gameover'; msgText.innerHTML = 'CRASH!<br>Final score: '+Math.floor(score); msgBox.style.display='block'; } // initial call startGame(); })(); </script> </body> </html> ```
Drag to resize
Here's a fun, fast-paced arcade racer set in a city environment using JavaScript and HTML5 Canvas. I've included everything in a single HTML block with inline CSS and JavaScript, so it can be rendered directly in a browser. The game features a car dodging obstacles (other vehicles) on a scrolling city road with simple controls (arrow keys for movement). ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>City Arcade Racer</title> <style> body { margin: 0; padding: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #333; font-family: Arial, sans-serif; } canvas { border: 2px solid white; } #gameOver { position: absolute; color: white; font-size: 30px; text-align: center; background: rgba(0, 0, 0, 0.8); padding: 20px; display: none; } #score { position: absolute; top: 10px; left: 10px; color: white; font-size: 20px; background: rgba(0, 0, 0, 0.5); padding: 10px; } </style> </head> <body> <canvas id="gameCanvas" width="400" height="600"></canvas> <div id="gameOver">Game Over!<br>Press R to Restart</div> <div id="score">Score: 0</div> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const gameOverDiv = document.getElementById('gameOver'); const scoreDiv = document.getElementById('score'); // Game settings const carWidth = 50; const carHeight = 80; const roadWidth = canvas.width; const roadHeight = canvas.height; const playerSpeed = 5; const obstacleSpeed = 7; const backgroundSpeed = 5; let score = 0; let gameOver = false; let highScore = localStorage.getItem('highScore') ? parseInt(localStorage.getItem('highScore')) : 0; // Player car const player = { x: roadWidth / 2 - carWidth / 2, y: roadHeight - carHeight - 20, width: carWidth, height: carHeight, speed: playerSpeed, color: 'red' }; // Obstacles (enemy cars) const obstacles = []; const obstacleFrequency = 60; // Frames between spawning new obstacles let frameCount = 0; // Background (city road scrolling effect) let bgY = 0; const bgHeight = roadHeight * 2; // Controls let keys = { left: false, right: false }; document.addEventListener('keydown', (e) => { if (e.key === 'ArrowLeft') keys.left = true; if (e.key === 'ArrowRight') keys.right = true; if (e.key.toLowerCase() === 'r' && gameOver) resetGame(); }); document.addEventListener('keyup', (e) => { if (e.key === 'ArrowLeft') keys.left = false; if (e.key === 'ArrowRight') keys.right = false; }); function resetGame() { player.x = roadWidth / 2 - carWidth / 2; obstacles.length = 0; score = 0; gameOver = false; gameOverDiv.style.display = 'none'; scoreDiv.textContent = `Score: ${score}`; frameCount = 0; } function spawnObstacle() { const obstacle = { x: Math.random() * (roadWidth - carWidth), y: -carHeight, width: carWidth, height: carHeight, color: 'blue', speed: obstacleSpeed + Math.random() * 2 }; obstacles.push(obstacle); } function update() { if (gameOver) return; // Move player if (keys.left && player.x > 0) player.x -= player.speed; if (keys.right && player.x < roadWidth - player.width) player.x += player.speed; // Spawn obstacles frameCount++; if (frameCount >= obstacleFrequency) { spawnObstacle(); frameCount = 0; } // Move obstacles obstacles.forEach(obstacle => { obstacle.y += obstacle.speed; // Collision detection if ( player.x < obstacle.x + obstacle.width && player.x + player.width > obstacle.x && player.y < obstacle.y + obstacle.height && player.y + player.height > obstacle.y ) { gameOver = true; if (score > highScore) { highScore = score; localStorage.setItem('highScore', highScore); } gameOverDiv.innerHTML = `Game Over!<br>Score: ${score}<br>High Score: ${highScore}<br>Press R to Restart`; gameOverDiv.style.left = `${canvas.offsetLeft + roadWidth / 2 - gameOverDiv.offsetWidth / 2}px`; gameOverDiv.style.top = `${canvas.offsetTop + roadHeight / 2 - gameOverDiv.offsetHeight / 2}px`; gameOverDiv.style.display = 'block'; } }); // Remove off-screen obstacles obstacles.filter(obstacle => obstacle.y > roadHeight); // Update background bgY += backgroundSpeed; if (bgY >= roadHeight) bgY = 0; // Increase score score += 1; scoreDiv.textContent = `Score: ${score}`; } function draw() { ctx.clearRect(0, 0, roadWidth, roadHeight); // Draw scrolling city background ctx.fillStyle = 'gray'; ctx.fillRect(0, 0, roadWidth, roadHeight); // Road ctx.fillStyle = 'darkgray'; ctx.fillRect(roadWidth / 4, bgY - roadHeight, roadWidth / 2, roadHeight * 2); // Road lines ctx.fillStyle = 'yellow'; for (let i = 0; i < roadHeight * 2; i += 50) { ctx.fillRect(roadWidth / 2 - 5, (bgY + i) - roadHeight, 10, 30); } // City buildings (simple rectangles on sides) ctx.fillStyle = '#444'; for (let i = 0; i < roadHeight * 2; i += 100) { ctx.fillRect(0, (bgY + i) - roadHeight, roadWidth / 4 - 10, 60); ctx.fillRect(roadWidth - (roadWidth / 4 - 10), (bgY + i) - roadHeight, roadWidth / 4 - 10, 60); } // Draw player car ctx.fillStyle = player.color; ctx.fillRect(player.x, player.y, player.width, player.height); // Car details (headlights) ctx.fillStyle = 'yellow'; ctx.fillRect(player.x + 5, player.y + player.height - 10, 10, 5); ctx.fillRect(player.x + player.width - 15, player.y + player.height - 10, 10, 5); // Draw obstacles (enemy cars) obstacles.forEach(obstacle => { ctx.fillStyle = obstacle.color; ctx.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height); // Car details ctx.fillStyle = 'white'; ctx.fillRect(obstacle.x + 5, obstacle.y + 5, 10, 5); ctx.fillRect(obstacle.x + obstacle.width - 15, obstacle.y + 5, 10, 5); }); } function gameLoop() { update(); draw(); requestAnimationFrame(gameLoop); } // Start the game gameLoop(); </script> </body> </html> ``` This code creates a complete arcade racer game with the following features: - **City Setting**: A scrolling road with simplistic city buildings on the sides, road markings, and a gray urban aesthetic. - **Fast-Paced Gameplay**: The player's car moves quickly with arrow key controls (left and right), while enemy cars spawn at random positions and move down the screen at varying speeds. - **Mechanics**: Avoid crashing into other cars; score increases over time, and the game ends on collision with a restart option (press 'R'). - **Scoring**: Tracks current score and high score (saved in local storage). Simply open this HTML file in a web browser to play. No external libraries are used—everything is built with vanilla JavaScript and Canvas. Enjoy racing through the city streets!
Drag to resize
```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>City Racer Arcade</title> <style> html, body { background: #181c24; margin: 0; overflow: hidden; user-select: none; height: 100%; } canvas { display: block; margin: 0 auto; background: #222941; box-shadow: 0 8px 24px #000c; } #overlay { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0,0,0,0.65); display: flex; align-items: center; justify-content: center; color: #fff; font-family: 'Segoe UI', Arial, sans-serif; font-size: 3vw; letter-spacing: 2px; z-index: 3; flex-direction: column; transition: 0.5s; pointer-events: none; opacity: 0; } #overlay.active { opacity: 1; pointer-events: all; } #overlay button { margin-top: 2vw; background: #ff2954; color: #fff; border: none; font-size: 1.5vw; padding: 1vw 2vw; border-radius: 0.5vw; cursor: pointer; transition: background 0.2s; } #overlay button:hover { background: #ff4480; } </style> </head> <body> <canvas id="game"></canvas> <div id="overlay"> <div id="message"></div> <button id="startBtn">Start</button> </div> <script> const W = 800, H = 600; const ROAD_W = 360; const ROAD_MARK_W = 12; const LANE_COUNT = 3; const BUILDING_W = 80; const BUILDING_DIST = 80; const BUILDING_ROWS = 6; const SPEED_MAX = 14; const SPEED_ACC = 0.16; const SPEED_DEC = 0.12; const TURN_SPEED = 0.23; const CAR_W = 44, CAR_H = 68; const OBSTACLE_W = 44, OBSTACLE_H = 68; const SPAWN_INTERVAL = 880; const CITY_COLORS = [ "#5D6774", "#848CA0", "#B2BAD0", "#57627B", "#444A5C" ]; const canvas = document.getElementById('game'); const ctx = canvas.getContext('2d'); canvas.width = W; canvas.height = H; const overlay = document.getElementById('overlay'); const message = document.getElementById('message'); const startBtn = document.getElementById('startBtn'); // Game state let keys = {}; let car, obstacles, score, speed, gameState, spawnTimer, difficulty, buildings; function resetGame() { car = { x: W/2 - CAR_W/2, y: H-140, lane: 1, vy: 0, crashed: false }; obstacles = []; buildings = []; for (let row=0; row<BUILDING_ROWS; row++) { let y = H - (row+1)*BUILDING_DIST; genBuildingsRow(y, row%2===0 ? 0 : BUILDING_DIST/2); } score = 0; speed = 7; spawnTimer = 0; difficulty = 1; } function genBuildingsRow(y, phase) { // Left side let bx = W/2 - ROAD_W/2 - BUILDING_W; while (bx > 0) { let clr = CITY_COLORS[Math.floor(Math.random()*CITY_COLORS.length)]; let h = 80+Math.random()*120; buildings.push({x: bx, y, w: BUILDING_W-8, h, clr}); bx -= BUILDING_W; } // Right side bx = W/2 + ROAD_W/2 + 8; while (bx < W - BUILDING_W) { let clr = CITY_COLORS[Math.floor(Math.random()*CITY_COLORS.length)]; let h = 80+Math.random()*120; buildings.push({x: bx, y, w: BUILDING_W-8, h, clr}); bx += BUILDING_W; } } function randomLane() { return Math.floor(Math.random()*LANE_COUNT); } function laneX(lane) { return W/2 - ROAD_W/2 + (lane+0.5)*(ROAD_W / LANE_COUNT) - CAR_W/2; } function startGame() { resetGame(); gameState = 'play'; overlay.classList.remove('active'); } function crash() { gameState = 'crashed'; overlay.classList.add('active'); message.innerHTML = `CRASH!<br>SCORE: ${score}`; startBtn.innerText = "Restart"; } function update(dt) { if (gameState !== 'play') return; // Car controls (left/right) if (!car.crashed) { if (keys["ArrowLeft"] || keys["a"]) { if (car.lane > 0) car.lane -= TURN_SPEED*dt/16; if (car.lane < 0) car.lane = 0; } else if (keys["ArrowRight"] || keys["d"]) { if (car.lane < LANE_COUNT-1) car.lane += TURN_SPEED*dt/16; if (car.lane > LANE_COUNT-1) car.lane = LANE_COUNT-1; } car.x += (laneX(Math.round(car.lane)) - car.x) * 0.16; } // Car speed (up/down) if (keys["ArrowUp"] || keys["w"]) { speed += SPEED_ACC*dt/16; } else if (keys["ArrowDown"] || keys["s"]) { speed -= SPEED_DEC*dt/16; } else { speed -= SPEED_DEC*0.32*dt/16; } speed = Math.max(6, Math.min(SPEED_MAX, speed)); score += Math.floor(speed*dt/80); // Difficulty scales difficulty = 1 + Math.floor(score/320); // Obstacles for (let o of obstacles) { o.y += speed*dt/14 * (1.08 + 0.06*difficulty); } // Remove passed obstacles = obstacles.filter(o => o.y < H+OBSTACLE_H); // Spawn spawnTimer -= dt; if (spawnTimer <= 0) { let usedLanes = obstacles.filter(o => o.y < 200).map(o => o.lane); let availLanes = []; for (let l=0; l<LANE_COUNT; l++) if (!usedLanes.includes(l)) availLanes.push(l); if (availLanes.length > 0) { let lane = availLanes[Math.floor(Math.random()*availLanes.length)]; let colors = ["#25c7fc","#fc5a27","#ffdf3b"]; obstacles.push({ x: laneX(lane), y: -OBSTACLE_H, lane, clr: colors[Math.floor(Math.random()*colors.length)] }); } spawnTimer = SPAWN_INTERVAL/(difficulty*1.2 + 0.5 + Math.random()*0.3); } // Collision for (let o of obstacles) { let dx = car.x - o.x; let dy = car.y - o.y; if (Math.abs(dx) < CAR_W-10 && Math.abs(dy) < CAR_H-16) { car.crashed = true; setTimeout(crash, 320); break; } } // Move buildings for (let b of buildings) b.y += speed*dt/20; // remove passed rows, generate new if (buildings[0].y > H) { buildings = buildings.filter(b => b.y <= H); let y = buildings[buildings.length-1].y - BUILDING_DIST; genBuildingsRow(y, Math.random()*BUILDING_DIST); } } function drawRoad() { // Road ctx.save(); ctx.beginPath(); ctx.rect(W/2-ROAD_W/2, 0, ROAD_W, H); ctx.fillStyle = "#232439"; ctx.shadowColor = '#16161d'; ctx.shadowBlur = 48; ctx.fill(); ctx.restore(); // Lanes ctx.strokeStyle = "#eee"; ctx.setLineDash([22, 18]); ctx.lineWidth = ROAD_MARK_W; for (let l=1; l<LANE_COUNT; l++) { let x = W/2-ROAD_W/2 + l*ROAD_W/LANE_COUNT; ctx.beginPath(); ctx.moveTo(x,0); ctx.lineTo(x,H); ctx.stroke(); } ctx.setLineDash([]); } // Simple building top w/ windows function drawBuilding(b) { ctx.save(); ctx.beginPath(); ctx.rect(b.x, b.y-b.h, b.w, b.h); ctx.fillStyle = b.clr; ctx.globalAlpha = 0.92; ctx.fill(); // Windows (randomized) ctx.globalAlpha = 0.65; ctx.fillStyle = Math.random() > 0.5 ? "#ffd" : "#dfe0f7"; for (let wy=0; wy<b.h-12; wy+=16) { for (let wx=4; wx<b.w-8; wx+=16) if (Math.random() > 0.4) ctx.fillRect(b.x+wx, b.y-b.h+wy, 6, 10); } ctx.restore(); } function drawObstacles() { for (let o of obstacles) { // Car shape ctx.save(); ctx.translate(o.x+OBSTACLE_W/2, o.y+OBSTACLE_H/2); ctx.rotate(Math.sin(o.y/100)*0.01); // body ctx.beginPath(); ctx.roundRect(-OBSTACLE_W/2, -OBSTACLE_H/2, OBSTACLE_W, OBSTACLE_H, 11); ctx.fillStyle = o.clr; ctx.shadowColor = "#111"; ctx.shadowBlur = 10; ctx.fill(); // windows ctx.fillStyle = "#aef4fa"; ctx.globalAlpha = 0.6; ctx.fillRect(-14, -OBSTACLE_H/2+13, 28, 20); ctx.globalAlpha = 1; // wheels ctx.fillStyle = "#222"; ctx.fillRect(-OBSTACLE_W/2+5, -OBSTACLE_H/2+8, 8, 12); ctx.fillRect(OBSTACLE_W/2-13, -OBSTACLE_H/2+8, 8, 12); ctx.fillRect(-OBSTACLE_W/2+5, OBSTACLE_H/2-20, 8, 12); ctx.fillRect(OBSTACLE_W/2-13, OBSTACLE_H/2-20, 8, 12); ctx.restore(); } } function drawCar() { ctx.save(); ctx.translate(car.x+CAR_W/2, car.y+CAR_H/2); let tilt = 0; if (car.lane < Math.round(car.lane)-0.05) tilt = -0.13; else if (car.lane > Math.round(car.lane)+0.05) tilt = 0.13; if (car.crashed) tilt = Math.sin(Date.now()/40)*0.38; ctx.rotate(tilt); // shadow ctx.globalAlpha = 0.32; ctx.fillStyle = "#011"; ctx.ellipse(0, 32, 17, 11, 0, 0, 2*Math.PI); ctx.fill(); ctx.globalAlpha = 1; // Main body ctx.beginPath(); ctx.roundRect(-CAR_W/2, -CAR_H/2, CAR_W, CAR_H, 12); ctx.fillStyle = "#ff2954"; ctx.shadowColor = "#3f1637"; ctx.shadowBlur = 14; ctx.fill(); // Windows ctx.beginPath(); ctx.moveTo(-13,-CAR_H/2+13); ctx.lineTo(13,-CAR_H/2+13); ctx.lineTo(16, 7); ctx.lineTo(-16,7); ctx.closePath(); ctx.fillStyle = "#aef4fa"; ctx.globalAlpha = 0.65; ctx.fill(); ctx.globalAlpha = 1; // Wheels ctx.save(); ctx.rotate(0.01*Math.sin(Date.now()/130)); ctx.fillStyle = "#23262f"; // Front wheels ctx.fillRect(-CAR_W/2+6, -CAR_H/2+8, 8, 12); ctx.fillRect(CAR_W/2-14, -CAR_H/2+8, 8, 12); // Rear wheels ctx.fillRect(-CAR_W/2+6, CAR_H/2-20, 8, 12); ctx.fillRect(CAR_W/2-14, CAR_H/2-20, 8, 12); ctx.restore(); // Lights // Headlights ctx.beginPath(); ctx.ellipse(-8,-CAR_H/2+6,3,5,0,0,Math.PI*2); ctx.ellipse(8,-CAR_H/2+6,3,5,0,0,Math.PI*2); ctx.fillStyle = "#fff7c0"; ctx.globalAlpha = 0.62 + 0.22 * Math.sin(Date.now()/80); ctx.fill(); ctx.restore(); } // City background gradient function drawSky() { let grad = ctx.createLinearGradient(0,0,0,H); grad.addColorStop(0, "#3f53a0"); grad.addColorStop(0.33, "#617cc1"); grad.addColorStop(1, "#191d2a"); ctx.fillStyle = grad; ctx.fillRect(0,0,W,H); } // HUD function drawHud() { ctx.save(); ctx.font = "bold 24px Segoe UI, Arial"; ctx.fillStyle = "#fff"; ctx.shadowColor = '#191c28'; ctx.shadowBlur = 8; ctx.fillText("SCORE: "+score, 24, 38); ctx.font = "bold 14px Segoe UI, Arial"; ctx.fillStyle = "#cdf"; ctx.shadowBlur = 4; ctx.fillText("Speed: "+speed.toFixed(1)+" / "+SPEED_MAX, 24, 56); ctx.restore(); // Hints if (score<40) { ctx.save(); ctx.font = "18px Segoe UI"; ctx.fillStyle = "rgba(255,255,255,0.7)"; ctx.fillText("← → or A/D: Move / ↑ or W: Speed up", W/2-138, H-38); ctx.restore(); } } function render() { drawSky(); // Draw buildings for (let b of buildings) drawBuilding(b); drawRoad(); drawObstacles(); drawCar(); drawHud(); } let lastT = performance.now(); function loop(){ let now = performance.now(); let dt = Math.min(38, now-lastT); lastT = now; if (gameState == 'play') update(dt); render(); requestAnimationFrame(loop); } // Input handlers document.addEventListener('keydown', e => { keys[e.key.toLowerCase()] = true; if ((e.key === " " || e.key === "Enter") && overlay.classList.contains('active')) { startBtn.click(); } }); document.addEventListener('keyup', e => { keys[e.key.toLowerCase()] = false; }); startBtn.onclick = () => { startGame(); } function init() { // Initial overlay overlay.classList.add('active'); message.innerHTML = "CITY RACER<br><span style='font-size:1vw;letter-spacing:1px;'>Fast-paced arcade action<br>Dodge cars and reach a high score!</span>"; startBtn.innerText = "Start"; gameState = 'menu'; loop(); } init(); </script> </body> </html> ```
Drag to resize
Below is a simple implementation of a fun, fast-paced arcade racer in JavaScript, HTML, and CSS. The game is set in a cityscape and uses keyboard controls for movement. The car accelerates automatically, and the player must avoid obstacles (represented by red squares). ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>City Racer</title> <style> body { margin: 0; overflow: hidden; background-color: #87CEEB; /* Sky blue background */ } canvas { display: block; } .score { position: absolute; top: 10px; left: 10px; font-size: 24px; font-family: Arial, sans-serif; color: white; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); } </style> </head> <body> <div class="score">Score: <span id="score">0</span></div> <canvas id="gameCanvas"></canvas> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const scoreDisplay = document.getElementById('score'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; const player = { x: canvas.width / 2 - 20, y: canvas.height - 100, width: 40, height: 20, speed: 5, color: '#FF6347' // Tomato color }; let obstacles = []; let score = 0; let gameSpeed = 3; let keys = { ArrowLeft: false, ArrowRight: false }; function createObstacle() { const size = Math.floor(Math.random() * 30) + 20; const gap = Math.floor(Math.random() * 100) + 50; const x = canvas.width; const y = Math.random() * (canvas.height - gap - size); obstacles.push({ x, y, width: size, height: size, passed: false }); } function update() { player.x += (keys.ArrowRight ? player.speed : 0) - (keys.ArrowLeft ? player.speed : 0); if (player.x < 0) player.x = 0; if (player.x + player.width > canvas.width) player.x = canvas.width - player.width; obstacles.forEach(obstacle => { obstacle.x -= gameSpeed; if (!obstacle.passed && obstacle.x + obstacle.width < player.x) { obstacle.passed = true; score++; scoreDisplay.textContent = score; } if (obstacle.x + obstacle.width > player.x && obstacle.x < player.x + player.width && obstacle.y + obstacle.height > player.y && obstacle.y < player.y + player.height) { cancelAnimationFrame(animationFrame); alert('Game Over! Score: ' + score); document.location.reload(); } }); obstacles = obstacles.filter(obstacle => obstacle.x + obstacle.width > 0); if (Math.random() < 0.02) { createObstacle(); } } function draw() { ctx.clearRect(0, 0, canvas.width, canvas.height); // Draw cityscape background ctx.fillStyle = '#CCCCCC'; // Light gray buildings ctx.fillRect(0, canvas.height - 50, canvas.width, 50); // Draw road ctx.fillStyle = '#444444'; // Dark gray road ctx.fillRect(0, canvas.height - 100, canvas.width, 100); // Draw lane lines ctx.strokeStyle = '#FFFFFF'; ctx.lineWidth = 4; ctx.setLineDash([20, 20]); ctx.beginPath(); for (let i = -5; i <= canvas.width; i += 50) { ctx.moveTo(i, canvas.height - 80); ctx.lineTo(i + 20, canvas.height - 80); } ctx.stroke(); ctx.setLineDash([]); // Draw player ctx.fillStyle = player.color; ctx.fillRect(player.x, player.y, player.width, player.height); // Draw obstacles ctx.fillStyle = '#FF0000'; // Red obstacles obstacles.forEach(obstacle => { ctx.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height); }); } function gameLoop() { update(); draw(); const animationFrame = requestAnimationFrame(gameLoop); } document.addEventListener('keydown', e => { if (e.key in keys) { keys[e.key] = true; } }); document.addEventListener('keyup', e => { if (e.key in keys) { keys[e.key] = false; } }); createObstacle(); gameLoop(); </script> </body> </html> ``` **Features of the Game:** 1. **Auto-Acceleration:** The car moves forward automatically, and the player only needs to steer left or right using the arrow keys. 2. **Obstacle Avoidance:** Red squares appear randomly on the road, and the player must avoid them to stay alive. 3. **Scoring System:** The score increases as the player overtakes obstacles. 4. **Game Over:** The game ends if the player collides with an obstacle, displaying the final score. 5. **Responsive Controls:** Smooth left and right movement using the arrow keys. **To run the game:** 1. Copy the code into an HTML file (e.g., `city-racer.html`). 2. Open the file in a web browser. 3. Use the left and right arrow keys to control the car. Enjoy the fast-paced city racing action!
Drag to resize
```html <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> body { margin: 0; overflow: hidden; background: #000; } canvas { display: block; background: #0a0a0a; } </style> </head> <body> <canvas id="gameCanvas"></canvas> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; let keys = { ArrowLeft: false, ArrowRight: false, ArrowUp: false, ArrowDown: false }; let lastTime = 0; let gameSpeed = 4; let spawnTimer = 0; let score = 0; let highScore = 0; let gameOver = false; // Layers const layers = { stars: Array.from({length: 100}, () => ({ x: Math.random()*canvas.width, y: Math.random()*canvas.height, size: Math.random()*1.5, opacity: Math.random() })), buildings: [ { x: 0, y: 40, width: 80, height: 200, speed: 1.2 }, { x: 150, y: 60, width: 50, height: 180, speed: 1.2 }, { x: 300, y: 30, width: 90, height: 220, speed: 1.2 }, // Middle ground { x: 0, y: 300, width: 60, height: 400, speed: 1.5 }, { x: 120, y: 250, width: 70, height: 450, speed: 1.5 }, { x: 250, y: 280, width: 30, height: 420, speed: 1.5 }, // Road reflectors { x: 0, y: canvas.height-20, width: 10, height: 5, speed: 2, color: '#ff0' }, { x: 30, y: canvas.height-20, width: 10, height: 5, speed: 2, color: '#ff0' } ], enemies: Array.from({length: 5}, () => ({ x: canvas.width + Math.random()*200, y: 600 - Math.random()*300, width: 40, height: 80, speed: 2.5 + Math.random() })) }; const player = { x: canvas.width/2 - 20, y: canvas.height - 120, width: 40, height: 80, color: '#ff3333' }; function resetGame() { score = 0; gameOver = false; player.x = canvas.width/2 - 20; layers.enemies.forEach(e => { e.x = canvas.width + Math.random()*200; e.y = 600 - Math.random()*300; }); requestAnimationFrame(gameLoop); } function drawBackground() { // Night sky ctx.fillStyle = '#0a0a0a'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Stars ctx.fillStyle = '#fff'; layers.stars.forEach(star => { ctx.globalAlpha = star.opacity; ctx.fillRect(star.x, star.y, star.size, star.size); }); ctx.globalAlpha = 1; // Buildings layers.buildings.forEach(b => { ctx.fillStyle = b.color || '#222222'; ctx.fillRect(b.x, b.y, b.width, b.height); }); } function drawPlayer() { ctx.fillStyle = player.color; ctx.beginPath(); ctx.roundRect(player.x, player.y, player.width, player.height, 5).fill(); } function updatePlayer() { if(keys.ArrowLeft) player.x -= 6; if(keys.ArrowRight) player.x += 6; // Boundary check player.x = Math.max(0, Math.min(player.x, canvas.width - player.width)); } function drawEnemies() { ctx.fillStyle = '#33ff33'; layers.enemies.forEach(enemy => { ctx.beginPath(); ctx.roundRect(enemy.x, enemy.y, enemy.width, enemy.height, 8).fill(); }); } function updateEnemies() { layers.enemies.forEach(enemy => { enemy.x -= enemy.speed; // Respawn if offscreen if(enemy.x + enemy.width < 0) { enemy.x = canvas.width + Math.random()*200; enemy.y = 600 - Math.random()*300; enemy.speed = 2.5 + Math.random(); score += 1; if(score > highScore) highScore = score; } }); } function drawHUD() { ctx.fillStyle = '#fff'; ctx.font = '20px Arial'; ctx.fillText(`Score: ${score}`, 20, 30); ctx.fillText(`High: ${highScore}`, 20, 50); if(gameOver) { ctx.font = '50px Arial'; ctx.fillStyle = 'rgba(0,0,0,0.7)'; ctx.fillRect(0, canvas.height/2-60, canvas.width, 120); ctx.fillStyle = '#ff0000'; ctx.fillText('GAME OVER', canvas.width/2-100, canvas.height/2-10); ctx.fillStyle = '#fff'; ctx.fillText('Press Space to Restart', canvas.width/2-130, canvas.height/2+30); } } function checkCollisions() { const playerLeft = player.x; const playerRight = player.x + player.width; const playerTop = player.y; const playerBottom = player.y + player.height; layers.enemies.forEach(enemy => { const enemyLeft = enemy.x; const enemyRight = enemy.x + enemy.width; const enemyTop = enemy.y; const enemyBottom = enemy.y + enemy.height; if(playerRight > enemyLeft && playerLeft < enemyRight && playerBottom > enemyTop && playerTop < enemyBottom) { gameOver = true; } }); } function updateBackground() { // Move buildings layers.buildings.forEach(b => { b.x -= b.speed; // Reset position if offscreen if(b.x <= -b.width) { b.x = canvas.width + b.width; b.y = 50 + Math.random()*(canvas.height/2 - 20); b.width = 30 + Math.random()*60; b.height = 50 + Math.random()*300; } }); // Update stars (modulate opacity) layers.stars.forEach(st => { st.opacity = 0.5 + 0.5*Math.sin(Date.now()*0.005 + st.x); }); } function gameLoop(timestamp) { if(gameOver) return; ctx.clearRect(0, 0, canvas.width, canvas.height); updateBackground(); drawBackground(); updatePlayer(); drawPlayer(); updateEnemies(); drawEnemies(); checkCollisions(); drawHUD(); requestAnimationFrame(gameLoop); } // Key controls window.addEventListener('keydown', e => { if(e.code in keys) keys[e.code] = true; if(e.code === 'Space' && gameOver) resetGame(); }); window.addEventListener('keyup', e => { if(e.code in keys) keys[e.code] = false; }); // Path rounding helper - easier for rounded car coords CanvasRenderingContext2D.prototype.roundRect = function (x, y, width, height, radius) { if (typeof radius === 'number') radius = {tl: radius, tr: radius, br: radius, bl: radius}; this.beginPath(); this.moveTo(x + radius.tl, y); this.lineTo(x + width - radius.tr, y); this.quadraticCurveTo(x + width, y, x + width, y + radius.tr); this.lineTo(x + width, y + height - radius.br); this.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height); this.lineTo(x + radius.bl, y + height); this.quadraticCurveTo(x, y + height, x, y + height - radius.bl); this.lineTo(x, y + radius.tl); this.quadraticCurveTo(x, y, x + radius.tl, y); this.closePath(); return this; }; // Start game resetGame(); </script> </body> </html> ```
Drag to resize
```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>City Arcade Racer</title> <style> * { margin:0; padding:0; box-sizing:border-box; } body { background:#333; display:flex; align-items:center; justify-content:center; height:100vh; } canvas { background:#444; display:block; } </style> </head> <body> <canvas id="game"></canvas> <script> const canvas = document.getElementById('game'); const ctx = canvas.getContext('2d'); canvas.width = 400; canvas.height = 600; // Road & lanes const lanes = 3; const roadWidth = 200; const roadX = (canvas.width - roadWidth) / 2; const laneWidth = roadWidth / lanes; // Player car const carW = laneWidth * 0.6; const carH = 80; let laneIndex = 1; // 0,1,2 let carX = roadX + laneIndex * laneWidth + (laneWidth - carW) / 2; const carY = canvas.height - carH - 20; // Controls let leftPressed = false, rightPressed = false, upPressed = false, downPressed = false, spacePressed = false; // Game state let speed = 5; const maxSpeed = 15, minSpeed = 3; let frameCount = 0, spawnInterval = 90; let obstacles = []; let buildings = []; let laneMarkerOffset = 0; let score = 0; let gameOver = false; // Initialize buildings for city sides function initBuildings() { buildings = []; for (let i = 0; i < 15; i++) { ['left','right'].forEach(side => { const bWidth = 50 + Math.random() * 50; const bHeight = 100 + Math.random() * 150; const x = side === 'left' ? roadX - 20 - bWidth : roadX + roadWidth + 20; const y = Math.random() * -canvas.height; buildings.push({ x, y, width: bWidth, height: bHeight, color: '#999' }); }); } } // Spawn an obstacle car in a random lane function spawnObstacle() { const lane = Math.floor(Math.random() * lanes); const x = roadX + lane * laneWidth + (laneWidth - carW) / 2; obstacles.push({ x, y: -carH, width: carW, height: carH, color: '#e33' }); spawnInterval = 60 + Math.random() * 60; } // Reset game function resetGame() { laneIndex = 1; carX = roadX + laneIndex * laneWidth + (laneWidth - carW) / 2; speed = 5; frameCount = 0; score = 0; obstacles = []; laneMarkerOffset = 0; gameOver = false; initBuildings(); requestAnimationFrame(gameLoop); } // Key handlers document.addEventListener('keydown', e => { if (e.key === 'ArrowLeft' || e.key === 'a') leftPressed = true; if (e.key === 'ArrowRight' || e.key === 'd') rightPressed = true; if (e.key === 'ArrowUp' || e.key === 'w') upPressed = true; if (e.key === 'ArrowDown' || e.key === 's') downPressed = true; if (e.key === ' ' || e.key === 'Spacebar') spacePressed = true; }); document.addEventListener('keyup', e => { if (e.key === 'ArrowLeft' || e.key === 'a') leftPressed = false; if (e.key === 'ArrowRight' || e.key === 'd') rightPressed = false; if (e.key === 'ArrowUp' || e.key === 'w') upPressed = false; if (e.key === 'ArrowDown' || e.key === 's') downPressed = false; if (e.key === ' ' || e.key === 'Spacebar') spacePressed = false; }); // Main loop function gameLoop() { update(); draw(); if (!gameOver) requestAnimationFrame(gameLoop); } function update() { frameCount++; // Move car between lanes if (leftPressed && laneIndex > 0) { laneIndex--; leftPressed = false; } if (rightPressed && laneIndex < lanes - 1) { laneIndex++; rightPressed = false; } carX = roadX + laneIndex * laneWidth + (laneWidth - carW) / 2; // Speed control if (upPressed) speed = Math.min(maxSpeed, speed + 0.1); if (downPressed) speed = Math.max(minSpeed, speed - 0.1); // Lane markers offset laneMarkerOffset = (laneMarkerOffset + speed) % 40; // Buildings parallax buildings.forEach(b => { b.y += speed * 0.5; if (b.y > canvas.height) { b.y = -b.height - Math.random() * canvas.height; b.height = 100 + Math.random() * 150; } }); // Obstacles if (frameCount % Math.floor(spawnInterval) === 0) spawnObstacle(); obstacles.forEach(o => o.y += speed); obstacles = obstacles.filter(o => o.y < canvas.height + o.height); // Collision detection obstacles.forEach(o => { if (o.x < carX + carW && o.x + o.width > carX && o.y < carY + carH && o.y + o.height > carY) { gameOver = true; } }); // Score score += speed * 0.1; // Restart if (gameOver && spacePressed) { resetGame(); } } function draw() { // Clear ctx.clearRect(0, 0, canvas.width, canvas.height); // Grass sides ctx.fillStyle = '#072'; ctx.fillRect(0, 0, roadX, canvas.height); ctx.fillRect(roadX + roadWidth, 0, roadX, canvas.height); // Buildings buildings.forEach(b => { ctx.fillStyle = b.color; ctx.fillRect(b.x, b.y, b.width, b.height); }); // Road ctx.fillStyle = '#555'; ctx.fillRect(roadX, 0, roadWidth, canvas.height); // Road edges ctx.strokeStyle = '#fff'; ctx.lineWidth = 4; ctx.beginPath(); ctx.moveTo(roadX, 0); ctx.lineTo(roadX, canvas.height); ctx.moveTo(roadX + roadWidth, 0); ctx.lineTo(roadX + roadWidth, canvas.height); ctx.stroke(); // Lane markers ctx.strokeStyle = '#fff'; ctx.lineWidth = 2; ctx.setLineDash([20, 20]); for (let i = 1; i < lanes; i++) { const x = roadX + i * laneWidth; ctx.beginPath(); ctx.moveTo(x, -laneMarkerOffset); ctx.lineTo(x, canvas.height); ctx.stroke(); } ctx.setLineDash([]); // Obstacles obstacles.forEach(o => { ctx.fillStyle = o.color; ctx.fillRect(o.x, o.y, o.width, o.height); }); // Player car ctx.fillStyle = '#3af'; ctx.fillRect(carX, carY, carW, carH); // Score ctx.fillStyle = '#fff'; ctx.font = '20px sans-serif'; ctx.fillText('Score: ' + Math.floor(score), 10, 30); // Game Over if (gameOver) { ctx.fillStyle = 'rgba(0,0,0,0.7)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = '#f33'; ctx.font = '40px sans-serif'; ctx.textAlign = 'center'; ctx.fillText('GAME OVER', canvas.width/2, canvas.height/2 - 20); ctx.fillStyle = '#fff'; ctx.font = '20px sans-serif'; ctx.fillText('Press SPACE to restart', canvas.width/2, canvas.height/2 + 20); } } // Start initBuildings(); resetGame(); </script> </body> </html> ```
Drag to resize
**City Racer Game** ===================== ### Overview Here is a simple implementation of a fast-paced arcade racer game set in a city using JavaScript and HTML5 Canvas. ### Game Description * The game features a player-controlled car that can be steered left and right using the arrow keys or 'A' and 'D' keys. * The objective is to avoid obstacles (other cars) while navigating through the city streets. * The game gets progressively harder as the player's score increases. ### Code ```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>City Racer</title> <style> /* Add some basic styling to our game */ canvas { border: 1px solid black; } </style> </head> <body> <canvas id="gameCanvas" width="800" height="600"></canvas> <script> // Get the canvas element const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); // Set the canvas dimensions canvas.width = 800; canvas.height = 600; // Define some game constants const ROAD_WIDTH = 400; const CAR_WIDTH = 50; const CAR_HEIGHT = 100; const OBSTACLE_WIDTH = 50; const OBSTACLE_HEIGHT = 100; const OBSTACLE_SPAWN_RATE = 1000; // milliseconds const GAME_SPEED = 5; // pixels per frame // Define some game variables let playerCarX = canvas.width / 2; let playerCarY = canvas.height - CAR_HEIGHT - 20; let obstacles = []; let score = 0; let lastObstacleSpawn = 0; // Main game loop function update() { // Clear the canvas ctx.clearRect(0, 0, canvas.width, canvas.height); // Draw the road ctx.fillStyle = 'gray'; ctx.fillRect((canvas.width - ROAD_WIDTH) / 2, 0, ROAD_WIDTH, canvas.height); // Draw the player's car ctx.fillStyle = 'blue'; ctx.fillRect(playerCarX, playerCarY, CAR_WIDTH, CAR_HEIGHT); // Move and draw obstacles for (let i = 0; i < obstacles.length; i++) { obstacles[i].y += GAME_SPEED; ctx.fillStyle = 'red'; ctx.fillRect(obstacles[i].x, obstacles[i].y, OBSTACLE_WIDTH, OBSTACLE_HEIGHT); // Check for collision with the player's car if (checkCollision(playerCarX, playerCarY, CAR_WIDTH, CAR_HEIGHT, obstacles[i].x, obstacles[i].y, OBSTACLE_WIDTH, OBSTACLE_HEIGHT)) { alert('Game Over! Your score: ' + score); // Reset the game state obstacles = []; score = 0; lastObstacleSpawn = 0; } // Remove obstacles that are off the screen if (obstacles[i].y > canvas.height) { obstacles.splice(i, 1); score++; } } // Spawn new obstacles const now = Date.now(); if (now - lastObstacleSpawn > OBSTACLE_SPAWN_RATE) { lastObstacleSpawn = now; obstacles.push({ x: Math.random() * (canvas.width - OBSTACLE_WIDTH), y: -OBSTACLE_HEIGHT }); } // Update the player's car position based on user input if (isKeyPressed('ArrowLeft') || isKeyPressed('a')) { playerCarX -= 5; } if (isKeyPressed('ArrowRight') || isKeyPressed('d')) { playerCarX += 5; } // Ensure the player's car stays within the road boundaries playerCarX = Math.max((canvas.width - ROAD_WIDTH) / 2, Math.min(playerCarX, (canvas.width + ROAD_WIDTH) / 2 - CAR_WIDTH)); // Display the score ctx.fillStyle = 'black'; ctx.font = '24px Arial'; ctx.textAlign = 'left'; ctx.textBaseline = 'top'; ctx.fillText('Score: ' + score, 10, 10); // Request the next frame requestAnimationFrame(update); } // Helper function to check for collision between two rectangles function checkCollision(x1, y1, w1, h1, x2, y2, w2, h2) { return x1 < x2 + w2 && x1 + w1 > x2 && y1 < y2 + h2 && y1 + h1 > y2; } // Helper function to check if a key is currently pressed const keyState = {}; document.addEventListener('keydown', (e) => { keyState[e.key] = true; }); document.addEventListener('keyup', (e) => { keyState[e.key] = false; }); function isKeyPressed(key) { return keyState[key] === true; } // Start the game update(); </script> </body> </html> ``` ### How to Run 1. Save the above code in an HTML file (e.g., `city_racer.html`). 2. Open the HTML file in a web browser. 3. Use the arrow keys or 'A' and 'D' keys to control the player's car. 4. Avoid obstacles and try to survive for as long as possible. ### Features * Fast-paced gameplay with increasing difficulty * Simple yet intuitive controls * Collision detection with obstacles * Scoring system ### Future Improvements * Add different types of obstacles (e.g., pedestrians, roadblocks) * Introduce power-ups or bonuses (e.g., speed boost, shield) * Implement a high score system * Enhance the game's visuals and audio (e.g., add graphics, sound effects, music)
Drag to resize
```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Arcade City Racer</title> <style> body { margin: 0; overflow: hidden; background-color: #1a1a1a; /* Dark background */ display: flex; justify-content: center; align-items: center; height: 100vh; font-family: sans-serif; } canvas { border: 1px solid #000; background-color: #505050; /* Default road color */ display: block; /* Remove extra space below canvas */ } </style> </head> <body> <canvas id="gameCanvas" width="400" height="600"></canvas> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); // Game State let gameState = 'start'; // 'start', 'playing', 'gameOver' // Game Constants const GAME_WIDTH = canvas.width; const GAME_HEIGHT = canvas.height; const LANE_WIDTH = 80; // Width of one lane const NUM_LANES = 3; // Number of visible driving lanes const ROAD_LINE_WIDTH = 5; const ROAD_LINE_COLOR = '#ffffff'; // White dashed lines const ROAD_COLOR = '#505050'; // Grey road color const SKY_COLOR = '#87CEEB'; // Sky blue const BUILDING_COLOR_1 = '#4d4d4d'; // Dark grey building const BUILDING_COLOR_2 = '#333333'; // Darker grey building // Calculate Road Dimensions const ROAD_WIDTH = NUM_LANES * LANE_WIDTH; const ROAD_X = GAME_WIDTH / 2 - ROAD_WIDTH / 2; // Player Car const CAR_WIDTH = LANE_WIDTH * 0.6; // Make car slightly narrower than lane const CAR_HEIGHT = CAR_WIDTH * 1.75; // Proportionate height let carX = ROAD_X + LANE_WIDTH + (LANE_WIDTH / 2) - (CAR_WIDTH / 2); // Start in the middle lane let carY = GAME_HEIGHT - CAR_HEIGHT - 30; // Position near bottom const CAR_SPEED_X = 7; // How fast car moves left/right // Game Variables let speed = 6; // Initial downward speed of objects let score = 0; let highScore = 0; let frameCount = 0; // Obstacles (Other cars/objects) const OBSTACLE_WIDTH = LANE_WIDTH * 0.6; const OBSTACLE_HEIGHT = OBSTACLE_WIDTH * 1.75; // Same size as player car const OBSTACLE_BASE_SPAWN_RATE = 90; // Frames between spawns at low speed let obstacles = []; const OBSTACLE_COLORS = ['#00ffff', '#ffff00', '#ff00ff', '#00ff00', '#ff8800', '#0000ff']; // Various car colors // City Elements (Buildings/Side Stuff) const BUILDING_MIN_HEIGHT = 150; // Taller buildings const BUILDING_MAX_HEIGHT = 500; const BUILDING_MIN_WIDTH = 60; // Wider buildings const BUILDING_MAX_WIDTH = 120; const BUILDING_SPAWN_RATE = 50; // Frames between building spawns let buildingsLeft = []; let buildingsRight = []; // Input Handling let keys = { ArrowLeft: false, ArrowRight: false, Enter: false }; document.addEventListener('keydown', (e) => { if (keys.hasOwnProperty(e.key)) { keys[e.key] = true; } // Prevent default behavior for arrow keys and space (prevents scrolling) if (['ArrowLeft', 'ArrowRight', ' '].includes(e.key)) { e.preventDefault(); } }); document.addEventListener('keyup', (e) => { if (keys.hasOwnProperty(e.key)) { keys[e.key] = false; } }); // Game Functions function initGame() { // Start car in the middle lane carX = ROAD_X + LANE_WIDTH + (LANE_WIDTH / 2) - (CAR_WIDTH / 2); carY = GAME_HEIGHT - CAR_HEIGHT - 30; // Keep car near bottom speed = 6; // Initial speed score = 0; frameCount = 0; obstacles = []; buildingsLeft = []; buildingsRight = []; // Spawn a few initial buildings off-screen for(let i = 0; i < 7; i++) { // Spawn enough to fill sides initially spawnBuilding('left', -i * (BUILDING_MAX_HEIGHT/4 + Math.random()*50)); spawnBuilding('right', -i * (BUILDING_MAX_HEIGHT/4 + Math.random()*50)); } gameState = 'playing'; } function update() { if (gameState !== 'playing') return; frameCount++; score += Math.floor(speed / 6); // Increase score based on speed // Increase speed gradually if (frameCount % 120 === 0) { // Increase speed every 2 seconds at 60fps speed += 0.3; speed = Math.min(speed, 25); // Cap speed for playability } // Player car movement if (keys.ArrowLeft) { carX -= CAR_SPEED_X; } if (keys.ArrowRight) { carX += CAR_SPEED_X; } // Clamp carX to road boundaries (allows movement within the 3 lanes) const minCarX = ROAD_X; const maxCarX = ROAD_X + ROAD_WIDTH - CAR_WIDTH; carX = Math.max(minCarX, Math.min(maxCarX, carX)); // Update obstacles obstacles.forEach(obstacle => { obstacle.y += speed * 0.9; // Obstacles move slightly slower than road speed }); // Remove obstacles that are off-screen (top or bottom - shouldn't go top with current speed) obstacles = obstacles.filter(obstacle => obstacle.y < GAME_HEIGHT); // Spawn new obstacles const currentObstacleSpawnRate = Math.max(30, OBSTACLE_BASE_SPAWN_RATE - Math.floor(speed * 1.5)); // Spawn rate increases with speed, clamped at minimum 30 frames if (frameCount % currentObstacleSpawnRate === 0) { spawnObstacle(); } // Update buildings [...buildingsLeft, ...buildingsRight].forEach(building => { building.y += speed * 0.3; // Buildings move significantly slower than road/obstacles for parallax effect }); buildingsLeft = buildingsLeft.filter(building => building.y - building.height < GAME_HEIGHT); // Keep if any part is on screen buildingsRight = buildingsRight.filter(building => building.y - building.height < GAME_HEIGHT); // Spawn new buildings // Spawn based on frame count AND ensure there's space for a new building off-screen const lastLeft = buildingsLeft.length > 0 ? buildingsLeft[buildingsLeft.length - 1] : null; const lastRight = buildingsRight.length > 0 ? buildingsRight[buildingsRight.length - 1] : null; if (frameCount % BUILDING_SPAWN_RATE === 0) { if (!lastLeft || lastLeft.y + lastLeft.height + speed * 0.3 > -BUILDING_MIN_HEIGHT/2) { // Check if last building is close to screen top spawnBuilding('left'); } if (!lastRight || lastRight.y + lastRight.height + speed * 0.3 > -BUILDING_MIN_HEIGHT/2) { spawnBuilding('right'); } } // Collision detection checkCollisions(); } function draw() { // Background City Sky ctx.fillStyle = SKY_COLOR; ctx.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT); // Draw Buildings (simplified non-perspective rectangles) drawBuildings(); // Draw Road ctx.fillStyle = ROAD_COLOR; ctx.fillRect(ROAD_X, 0, ROAD_WIDTH, GAME_HEIGHT); // Draw Lane Lines (dashed) ctx.fillStyle = ROAD_LINE_COLOR; const numLines = NUM_LANES - 1; const lineLength = 30; const lineGap = 30; // Adjust gap from 20 to 30 const totalLineSegment = lineLength + lineGap; // Y offset for animation - faster animation with speed const lineOffsetY = (frameCount * speed * 0.2) % totalLineSegment; for (let i = 0; i < numLines; i++) { const lineX = ROAD_X + LANE_WIDTH * (i + 1) - ROAD_LINE_WIDTH / 2; // Draw dashed line segments for (let j = lineOffsetY - totalLineSegment; j < GAME_HEIGHT; j += totalLineSegment) { ctx.fillRect(lineX, j, ROAD_LINE_WIDTH, lineLength); } } // Draw Player Car ctx.fillStyle = '#ff0000'; // Red car ctx.fillRect(carX, carY, CAR_WIDTH, CAR_HEIGHT); // Draw Obstacles (Other Cars) obstacles.forEach(obstacle => { ctx.fillStyle = obstacle.color; // Obstacle color ctx.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height); }); // Draw UI (Score, Speed) ctx.fillStyle = '#ffffff'; ctx.font = '20px Arial'; ctx.fillText(`Score: ${score}`, 10, 30); ctx.fillText(`Speed: ${speed.toFixed(1)}`, 10, 60); // Fictional speed unit // Draw Start/Game Over Screen if (gameState === 'start') { drawStartScreen(); } else if (gameState === 'gameOver') { drawGameOverScreen(); } } function spawnObstacle() { // Choose a random lane to spawn in const lane = Math.floor(Math.random() * NUM_LANES); const obstacleX = ROAD_X + lane * LANE_WIDTH + (LANE_WIDTH / 2) - (OBSTACLE_WIDTH / 2); // Start off-screen at the top, position relative to the very top const obstacleY = -OBSTACLE_HEIGHT - Math.random() * GAME_HEIGHT/4; // Random variance before appearing const color = OBSTACLE_COLORS[Math.floor(Math.random() * OBSTACLE_COLORS.length)]; // Add to obstacles array obstacles.push({ x: obstacleX, y: obstacleY, color: color, width: OBSTACLE_WIDTH, height: OBSTACLE_HEIGHT }); } // Spawn building at a specific Y coordinate (or random if null) function spawnBuilding(side, startY = null) { const width = BUILDING_MIN_WIDTH + Math.random() * (BUILDING_MAX_WIDTH - BUILDING_MIN_WIDTH); const height = BUILDING_MIN_HEIGHT + Math.random() * (BUILDING_MAX_HEIGHT - BUILDING_MIN_HEIGHT); // Start off-screen at the top, positioned just above the top edge or further up const y = startY !== null ? startY : -height - Math.random() * GAME_HEIGHT/4; // Random spacing between buildings let x; if (side === 'left') { x = ROAD_X - width; // Place buildings to the immediate left of the road buildingsLeft.push({ x: x, y: y, width: width, height: height, color: color }); } else { // side === 'right' x = ROAD_X + ROAD_WIDTH; // Place buildings to the immediate right of the road buildingsRight.push({ x: x, y: y, width: width, height: height, color: color }); } } function drawBuildings() { // Draw buildings slightly behind the road perspective-wise [...buildingsLeft, ...buildingsRight].forEach(building => { ctx.fillStyle = building.color; ctx.fillRect(building.x, building.y, building.width, building.height); }); } function checkCollisions() { const carHitBox = { // Simple AABB x: carX, y: carY, width: CAR_WIDTH, height: CAR_HEIGHT }; for (let i = 0; i < obstacles.length; i++) { const obstacle = obstacles[i]; // Simple AABB collision detection if (carHitBox.x < obstacle.x + obstacle.width && carHitBox.x + carHitBox.width > obstacle.x && carHitBox.y < obstacle.y + obstacle.height && carHitBox.y + carHitBox.height > obstacle.y) { // Collision detected gameOver(); return; // Exit function after game over } } } function gameOver() { if (score > highScore) { highScore = score; } gameState = 'gameOver'; } function drawStartScreen() { ctx.fillStyle = 'rgba(0, 0, 0, 0.8)'; // Semi-transparent black overlay ctx.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT); ctx.fillStyle = '#ffffff'; ctx.font = '40px Arial'; ctx.textAlign = 'center'; ctx.fillText('Arcade City Racer', GAME_WIDTH / 2, GAME_HEIGHT / 2 - 50); ctx.font = '25px Arial'; ctx.fillText('Press ENTER to Start', GAME_WIDTH / 2, GAME_HEIGHT / 2 + 20); ctx.font = '20px Arial'; ctx.fillText('Use LEFT/RIGHT Arrows to Steer', GAME_WIDTH / 2, GAME_HEIGHT / 2 + 70); ctx.textAlign = 'left'; // Reset alignment } function drawGameOverScreen() { ctx.fillStyle = 'rgba(0, 0, 0, 0.8)'; // Semi-transparent black overlay ctx.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT); ctx.fillStyle = '#ffffff'; ctx.font = '40px Arial'; ctx.textAlign = 'center'; ctx.fillText('Game Over!', GAME_WIDTH / 2, GAME_HEIGHT / 2 - 60); ctx.font = '30px Arial'; ctx.fillText(`Final Score: ${score}`, GAME_WIDTH / 2, GAME_HEIGHT / 2 + 0); ctx.fillText(`High Score: ${highScore}`, GAME_WIDTH / 2, GAME_HEIGHT / 2 + 40); ctx.font = '25px Arial'; ctx.fillText('Press ENTER to Restart', GAME_WIDTH / 2, GAME_HEIGHT / 2 + 100); ctx.textAlign = 'left'; // Reset alignment } // Game Loop function gameLoop() { // Handle input for state transitions only once per frame if ((gameState === 'start' || gameState === 'gameOver') && keys.Enter) { initGame(); // Start or restart the game keys.Enter = false; // Consume the key press immediately } update(); draw(); requestAnimationFrame(gameLoop); } // Start the game loop when window loads window.onload = function() { gameLoop(); }; </script> </body> </html> ```
Drag to resize
```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>City Arcade Racer</title> <style> body { margin: 0; background: #000; display: flex; justify-content: center; align-items: center; height: 100vh; } canvas { background: #333; } </style> </head> <body> <canvas id="gameCanvas"></canvas> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); canvas.width = 400; canvas.height = 600; let playerLane = 1; // 0 left, 1 middle, 2 right const lanes = 3; const laneWidth = canvas.width / lanes; const laneCenters = [laneWidth / 2, laneWidth * 1.5, laneWidth * 2.5]; const playerY = canvas.height - 60; let speed = 4; let obstacles = []; let buildings = []; let roadLines = []; let score = 0; let gameOver = false; let lastSpawn = 0; let speedIncrease = 0; // Generate initial buildings for (let i = 0; i < 10; i++) { buildings.push({ x: Math.random() < 0.5 ? -Math.random() * 50 - 10 : canvas.width + Math.random() * 50 + 10, y: i * 100 - 1000, width: 40 + Math.random() * 40, height: 100 + Math.random() * 200, color: `rgb(${100 + Math.random()*100}, ${100 + Math.random()*100}, ${100 + Math.random()*100})` }); } // Generate initial road lines for (let i = 0; i < 20; i++) { roadLines.push({ y: i * 40 - 800 }); } // Input handling document.addEventListener('keydown', (e) => { if (gameOver) { if (e.key === 'Enter') { resetGame(); } return; } if (e.key === 'ArrowLeft' && playerLane > 0) playerLane--; if (e.key === 'ArrowRight' && playerLane < 2) playerLane++; }); function resetGame() { playerLane = 1; speed = 4; obstacles = []; score = 0; gameOver = false; speedIncrease = 0; lastSpawn = 0; update(); } function update() { if (gameOver) return; speed = 4 + speedIncrease * 0.1; speedIncrease += 0.01; // Gradually increase speed // Update player position const playerX = laneCenters[playerLane]; // Spawn obstacles if (Math.random() < 0.02 + speedIncrease * 0.001 && Date.now() - lastSpawn > 300) { const obsLane = Math.floor(Math.random() * lanes); obstacles.push({ lane: obsLane, y: canvas.height + 50 }); lastSpawn = Date.now(); } // Move obstacles obstacles.forEach((obs, index) => { obs.y -= speed; if (obs.y < -50) { obstacles.splice(index, 1); } }); // Move buildings buildings.forEach((bldg) => { bldg.y += speed; if (bldg.y > canvas.height) { bldg.y = -bldg.height - Math.random() * 200; bldg.x = Math.random() < 0.5 ? -Math.random() * 50 - 10 : canvas.width + Math.random() * 50 + 10; bldg.width = 40 + Math.random() * 40; bldg.height = 100 + Math.random() * 200; bldg.color = `rgb(${100 + Math.random()*100}, ${100 + Math.random()*100}, ${100 + Math.random()*100})`; } }); // Move road lines roadLines.forEach((line) => { line.y += speed; if (line.y > canvas.height) { line.y = -40; } }); // Check collisions obstacles.forEach((obs) => { if (Math.abs(obs.y - playerY) < 40 && obs.lane === playerLane) { gameOver = true; } }); // Increase score score += Math.floor(speed / 10); // Draw everything ctx.clearRect(0, 0, canvas.width, canvas.height); // Draw road ctx.fillStyle = '#555'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Draw road lines ctx.fillStyle = '#fff'; roadLines.forEach((line) => { ctx.fillRect(laneWidth - 5, line.y, 10, 20); ctx.fillRect(laneWidth * 2 - 5, line.y, 10, 20); }); // Draw buildings buildings.forEach((bldg) => { ctx.fillStyle = bldg.color; ctx.fillRect(bldg.x, bldg.y, bldg.width, bldg.height); // Draw windows ctx.fillStyle = '#ff0'; for (let wy = 10; wy < bldg.height - 10; wy += 20) { for (let wx = 5; wx < bldg.width - 5; wx += 15) { if (Math.random() < 0.7) { ctx.fillRect(bldg.x + wx, bldg.y + wy, 5, 5); } } } }); // Draw obstacles (enemy cars) obstacles.forEach((obs) => { const obsX = laneCenters[obs.lane]; ctx.fillStyle = '#f00'; ctx.fillRect(obsX - 20, obs.y - 40, 40, 50); ctx.fillStyle = '#fff'; ctx.fillRect(obsX - 15, obs.y - 35, 30, 10); ctx.fillRect(obsX - 15, obs.y - 10, 30, 10); }); // Draw player car ctx.fillStyle = '#0f0'; ctx.fillRect(playerX - 20, playerY - 40, 40, 50); ctx.fillStyle = '#fff'; ctx.fillRect(playerX - 15, playerY - 35, 30, 10); ctx.fillRect(playerX - 15, playerY - 10, 30, 10); // Draw score ctx.fillStyle = '#fff'; ctx.font = '20px Arial'; ctx.fillText(`Score: ${score}`, 10, 30); if (gameOver) { ctx.fillStyle = 'rgba(0,0,0,0.7)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = '#fff'; ctx.font = '40px Arial'; ctx.fillText('Game Over!', 50, canvas.height / 2 - 20); ctx.font = '20px Arial'; ctx.fillText(`Score: ${score}`, 140, canvas.height / 2 + 20); ctx.fillText('Press Enter to Restart', 60, canvas.height / 2 + 50); } else { requestAnimationFrame(update); } } update(); </script> </body> </html> ```
Drag to resize
Below is a complete HTML file that implements a simple fun arcade racer game in JavaScript. The game is set in a stylized city environment with scrolling buildings and roads, and it's designed to be fast-paced. You control a car using the arrow keys: left and right to steer, and up to accelerate. Avoid obstacles to survive as long as possible! ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>City Arcade Racer</title> <style> body { margin: 0; overflow: hidden; background-color: #000; display: flex; justify-content: center; align-items: center; height: 100vh; } canvas { border: 1px solid #fff; background-color: #222; } </style> </head> <body> <canvas id="gameCanvas" width="800" height="600"></canvas> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); // Game variables const car = { x: canvas.width / 2, y: canvas.height - 100, width: 50, height: 30, speed: 5, velocity: 0, // For acceleration angle: 0 // For steering }; const obstacles = []; // Array to hold obstacles let score = 0; const obstacleFrequency = 100; // Frames between obstacles let frameCount = 0; // Background elements (city buildings and road) const buildings = [ { x: 0, width: 100, height: 200, color: '#444' }, { x: 150, width: 80, height: 150, color: '#555' }, { x: 300, width: 120, height: 250, color: '#666' }, { x: 450, width: 90, height: 180, color: '#777' }, { x: 600, width: 110, height: 220, color: '#888' }, { x: 750, width: 100, height: 190, color: '#999' } ]; let roadLines = []; // For scrolling road lines // Initialize road lines for (let i = 0; i < 20; i++) { roadLines.push({ x: i * 100, y: canvas.height }); } // Keyboard controls const keys = { ArrowLeft: false, ArrowRight: false, ArrowUp: false }; window.addEventListener('keydown', (e) => { if (keys.hasOwnProperty(e.code)) keys[e.code] = true; }); window.addEventListener('keyup', (e) => { if (keys.hasOwnProperty(e.code)) keys[e.code] = false; }); // Game loop function gameLoop() { ctx.clearRect(0, 0, canvas.width, canvas.height); // Update score score++; frameCount++; // Generate obstacles periodically if (frameCount % obstacleFrequency === 0) { obstacles.push({ x: Math.random() * (canvas.width - 50), y: -50, width: 50, height: 50, speed: 5 + score / 1000 // Increase speed over time }); } // Update car if (keys.ArrowUp) car.velocity += 0.1; // Accelerate if (keys.ArrowLeft) car.angle -= 0.05; // Turn left if (keys.ArrowRight) car.angle += 0.05; // Turn right car.velocity *= 0.98; // Natural deceleration car.x += (car.speed + car.velocity) * Math.sin(car.angle); // Forward movement with angle car.y -= car.speed + car.velocity; // Move forward // Boundary checks if (car.x < 0) car.x = 0; if (car.x + car.width > canvas.width) car.x = canvas.width - car.width; if (car.y < 0) car.y = canvas.height - car.height; // Wrap around vertically for fun // Update obstacles obstacles.forEach((obs, index) => { obs.y += obs.speed; if (obs.y > canvas.height) obstacles.splice(index, 1); // Remove off-screen obstacles // Collision detection if ( car.x < obs.x + obs.width && car.x + car.width > obs.x && car.y < obs.y + obs.height && car.y + car.height > obs.y ) { alert('Game Over! Score: ' + score); document.location.reload(); // Restart game } }); // Update and draw background (scrolling buildings and road) buildings.forEach(building => { ctx.fillStyle = building.color; ctx.fillRect(building.x, building.y || canvas.height - building.height, building.width, building.height); building.x -= 2; // Scroll buildings if (building.x + building.width < 0) building.x = canvas.width; // Loop }); roadLines.forEach(line => { ctx.strokeStyle = '#fff'; ctx.beginPath(); ctx.moveTo(line.x, line.y); ctx.lineTo(line.x + 50, line.y); ctx.stroke(); line.y -= (car.speed + car.velocity); // Scroll with speed if (line.y < 0) line.y = canvas.height; // Loop }); // Draw car ctx.fillStyle = '#f00'; // Red car ctx.save(); ctx.translate(car.x + car.width / 2, car.y + car.height / 2); ctx.rotate(car.angle); ctx.fillRect(-car.width / 2, -car.height / 2, car.width, car.height); ctx.restore(); // Draw obstacles obstacles.forEach(obs => { ctx.fillStyle = '#0f0'; // Green obstacles ctx.fillRect(obs.x, obs.y, obs.width, obs.height); }); // Draw score ctx.fillStyle = '#fff'; ctx.font = '20px Arial'; ctx.fillText('Score: ' + score, 10, 30); requestAnimationFrame(gameLoop); } gameLoop(); // Start the game </script> </body> </html> ```
Drag to resize