/
sergorel
/
Croach
Обзор
Документация
Войти
/
sergorel
/
Croach
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
index.html
653 строки
21 KB
sergorel
Create: new_file, index.html
10 июл 2026, 15:28
Верифицирован
10 июл 2026, 15:28
2345e44
Код
Авторство
О чём код?
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>🏎️ Гонка машинок</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background: linear-gradient(135deg, #0f0c29, #302b63, #24243e); font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; overflow: hidden; } .game-container { background: #1a1a2e; border-radius: 20px; padding: 20px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.7); border: 2px solid #e94560; } canvas { display: block; margin: 0 auto; border-radius: 12px; background: #16213e; cursor: none; } .hud { display: flex; justify-content: space-between; align-items: center; padding: 12px 20px; background: #0f3460; border-radius: 12px; margin-top: 15px; color: white; font-weight: bold; font-size: 18px; } .hud div { display: flex; align-items: center; gap: 8px; } .score { color: #ffd700; } .speed { color: #00f5ff; } .hint { color: #aaa; font-size: 14px; font-weight: normal; } .game-over { display: none; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.8); justify-content: center; align-items: center; flex-direction: column; border-radius: 20px; z-index: 10; } .game-over.show { display: flex; } .game-over h1 { color: #e94560; font-size: 48px; margin-bottom: 10px; text-shadow: 0 0 30px rgba(233, 69, 96, 0.5); } .game-over p { color: white; font-size: 24px; margin-bottom: 20px; } .game-over .final-score { color: #ffd700; font-size: 36px; } .restart-btn { padding: 14px 40px; font-size: 20px; font-weight: bold; color: white; background: linear-gradient(135deg, #e94560, #c23152); border: none; border-radius: 50px; cursor: pointer; transition: transform 0.2s, box-shadow 0.2s; margin-top: 10px; } .restart-btn:hover { transform: scale(1.05); box-shadow: 0 5px 25px rgba(233, 69, 96, 0.5); } .controls-info { display: flex; gap: 40px; color: #aaa; font-size: 14px; margin-top: 5px; padding: 5px 20px; } .controls-info span { display: flex; align-items: center; gap: 5px; } .key { background: #333; padding: 2px 10px; border-radius: 5px; color: white; font-weight: bold; font-size: 13px; } </style> </head> <body> <div class="game-container" style="position: relative;"> <canvas id="gameCanvas" width="800" height="600"></canvas> <div class="hud"> <div> <span>🏆</span> <span class="score" id="scoreDisplay">0</span> </div> <div> <span>📊</span> <span class="speed" id="speedDisplay">0</span> <span class="hint">км/ч</span> </div> <div> <span>🛣️</span> <span id="distanceDisplay" style="color: #7fff7f;">0</span> <span class="hint">м</span> </div> </div> <div class="controls-info"> <span><span class="key">←</span><span class="key">→</span> — управление</span> <span><span class="key">↑</span> — газ</span> <span><span class="key">↓</span> — тормоз</span> <span><span class="key">R</span> — рестарт</span> </div> <div class="game-over" id="gameOverScreen"> <h1>💥 КРАХ!</h1> <p>Ты разбился</p> <p class="final-score">Счёт: <span id="finalScore">0</span></p> <p style="color: #7fff7f; font-size: 18px;">Дистанция: <span id="finalDistance">0</span> м</p> <button class="restart-btn" id="restartBtn">🔄 Ещё заезд!</button> </div> </div> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const W = canvas.width; const H = canvas.height; // DOM элементы const scoreDisplay = document.getElementById('scoreDisplay'); const speedDisplay = document.getElementById('speedDisplay'); const distanceDisplay = document.getElementById('distanceDisplay'); const gameOverScreen = document.getElementById('gameOverScreen'); const finalScore = document.getElementById('finalScore'); const finalDistance = document.getElementById('finalDistance'); const restartBtn = document.getElementById('restartBtn'); // ============ ИГРОВЫЕ ПАРАМЕТРЫ ============ const PLAYER_WIDTH = 40; const PLAYER_HEIGHT = 70; const LANE_COUNT = 4; const LANE_WIDTH = 150; const ROAD_OFFSET = (W - LANE_COUNT * LANE_WIDTH) / 2; // Машинка игрока const player = { x: W / 2 - PLAYER_WIDTH / 2, y: H - 120, width: PLAYER_WIDTH, height: PLAYER_HEIGHT, speed: 0, maxSpeed: 12, acceleration: 0.3, braking: 0.5, friction: 0.05, angle: 0, // для наклона при повороте }; let score = 0; let distance = 0; let gameRunning = true; let keys = {}; let enemies = []; let coins = []; let roadLines = []; let frameCount = 0; // Полосы движения const lanes = []; for (let i = 0; i < LANE_COUNT; i++) { lanes.push(ROAD_OFFSET + i * LANE_WIDTH + LANE_WIDTH / 2); } // ============ ОТРИСОВКА ДОРОГИ ============ function drawRoad() { // Асфальт ctx.fillStyle = '#2d2d2d'; ctx.fillRect(ROAD_OFFSET - 10, 0, LANE_COUNT * LANE_WIDTH + 20, H); // Боковые линии (белые) ctx.strokeStyle = 'white'; ctx.lineWidth = 4; ctx.setLineDash([]); ctx.strokeRect(ROAD_OFFSET - 5, 0, LANE_COUNT * LANE_WIDTH + 10, H); // Разметка полос ctx.strokeStyle = '#fff'; ctx.lineWidth = 3; ctx.setLineDash([20, 30]); for (let i = 1; i < LANE_COUNT; i++) { const x = ROAD_OFFSET + i * LANE_WIDTH; ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, H); ctx.stroke(); } ctx.setLineDash([]); // Обочины ctx.fillStyle = '#1a1a1a'; ctx.fillRect(0, 0, ROAD_OFFSET - 10, H); ctx.fillRect(W - ROAD_OFFSET + 10, 0, ROAD_OFFSET - 10, H); // Зелёные обочины (трава) const grassGrad = ctx.createLinearGradient(0, 0, ROAD_OFFSET - 10, 0); grassGrad.addColorStop(0, '#1a5c1a'); grassGrad.addColorStop(1, '#2d8a2d'); ctx.fillStyle = grassGrad; ctx.fillRect(0, 0, ROAD_OFFSET - 10, H); const grassGrad2 = ctx.createLinearGradient(W, 0, W - ROAD_OFFSET + 10, 0); grassGrad2.addColorStop(0, '#1a5c1a'); grassGrad2.addColorStop(1, '#2d8a2d'); ctx.fillStyle = grassGrad2; ctx.fillRect(W - ROAD_OFFSET + 10, 0, ROAD_OFFSET - 10, H); } // ============ ОТРИСОВКА МАШИНКИ ============ function drawCar(x, y, w, h, color, isPlayer = false, angle = 0) { ctx.save(); ctx.translate(x + w / 2, y + h / 2); ctx.rotate(angle); // Кузов const grad = ctx.createLinearGradient(-w / 2, -h / 2, w / 2, h / 2); if (isPlayer) { grad.addColorStop(0, '#ff4757'); grad.addColorStop(0.5, '#ff6b81'); grad.addColorStop(1, '#c0392b'); } else { grad.addColorStop(0, color); grad.addColorStop(0.5, lightenColor(color, 30)); grad.addColorStop(1, darkenColor(color, 30)); } ctx.fillStyle = grad; ctx.shadowColor = isPlayer ? '#ff4757' : 'transparent'; ctx.shadowBlur = isPlayer ? 20 : 0; // Основной корпус (закруглённый) const r = 8; ctx.beginPath(); ctx.moveTo(-w / 2 + r, -h / 2); ctx.lineTo(w / 2 - r, -h / 2); ctx.quadraticCurveTo(w / 2, -h / 2, w / 2, -h / 2 + r); ctx.lineTo(w / 2, h / 2 - r); ctx.quadraticCurveTo(w / 2, h / 2, w / 2 - r, h / 2); ctx.lineTo(-w / 2 + r, h / 2); ctx.quadraticCurveTo(-w / 2, h / 2, -w / 2, h / 2 - r); ctx.lineTo(-w / 2, -h / 2 + r); ctx.quadraticCurveTo(-w / 2, -h / 2, -w / 2 + r, -h / 2); ctx.closePath(); ctx.fill(); ctx.shadowBlur = 0; // Кабина (лобовое стекло) ctx.fillStyle = isPlayer ? '#1e90ff' : '#87ceeb'; const cabW = w * 0.6; const cabH = h * 0.25; ctx.beginPath(); ctx.roundRect(-cabW / 2, -h / 2 + 5, cabW, cabH, 3); ctx.fill(); // Заднее стекло ctx.fillStyle = isPlayer ? '#1e90ff' : '#87ceeb'; ctx.beginPath(); ctx.roundRect(-cabW / 2, h / 2 - cabH - 5, cabW, cabH, 3); ctx.fill(); // Колёса ctx.fillStyle = '#1a1a1a'; const wheelW = 8; const wheelH = 18; // Передние колёса ctx.fillRect(-w / 2 - wheelW / 2 + 2, -h / 2 + 10, wheelW, wheelH); ctx.fillRect(w / 2 - wheelW / 2 - 2, -h / 2 + 10, wheelW, wheelH); // Задние колёса ctx.fillRect(-w / 2 - wheelW / 2 + 2, h / 2 - 10 - wheelH, wheelW, wheelH); ctx.fillRect(w / 2 - wheelW / 2 - 2, h / 2 - 10 - wheelH, wheelW, wheelH); // Диски ctx.fillStyle = '#666'; const discSize = 4; const discs = [ [-w / 2 + 2, -h / 2 + 19], [w / 2 - 2, -h / 2 + 19], [-w / 2 + 2, h / 2 - 19], [w / 2 - 2, h / 2 - 19] ]; discs.forEach(([dx, dy]) => { ctx.beginPath(); ctx.arc(dx, dy, discSize, 0, Math.PI * 2); ctx.fill(); }); // Фары (для игрока) if (isPlayer) { ctx.fillStyle = '#ffff00'; ctx.shadowColor = '#ffff00'; ctx.shadowBlur = 15; ctx.beginPath(); ctx.arc(-w / 2 + 8, -h / 2 + 5, 4, 0, Math.PI * 2); ctx.fill(); ctx.beginPath(); ctx.arc(w / 2 - 8, -h / 2 + 5, 4, 0, Math.PI * 2); ctx.fill(); ctx.shadowBlur = 0; } ctx.restore(); } // ============ ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ============ function lightenColor(color, percent) { // Упрощённая версия return color; } function darkenColor(color, percent) { // Упрощённая версия return color; } // roundRect polyfill для canvas if (!CanvasRenderingContext2D.prototype.roundRect) { CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) { if (r > w / 2) r = w / 2; if (r > h / 2) r = h / 2; this.moveTo(x + r, y); this.lineTo(x + w - r, y); this.quadraticCurveTo(x + w, y, x + w, y + r); this.lineTo(x + w, y + h - r); this.quadraticCurveTo(x + w, y + h, x + w - r, y + h); this.lineTo(x + r, y + h); this.quadraticCurveTo(x, y + h, x, y + h - r); this.lineTo(x, y + r); this.quadraticCurveTo(x, y, x + r, y); }; } // ============ СОЗДАНИЕ ВРАГОВ ============ const enemyColors = ['#e74c3c', '#3498db', '#2ecc71', '#f39c12', '#9b59b6', '#1abc9c']; function spawnEnemy() { if (!gameRunning) return; // Случайная полоса const laneIndex = Math.floor(Math.random() * LANE_COUNT); const x = lanes[laneIndex] - PLAYER_WIDTH / 2; // Проверка, не занята ли полоса слишком близко for (let e of enemies) { if (Math.abs(e.x - x) < PLAYER_WIDTH && e.y < 100) { return; // Не спавним, если слишком близко } } const speed = 2 + Math.random() * 4; const color = enemyColors[Math.floor(Math.random() * enemyColors.length)]; enemies.push({ x: x, y: -PLAYER_HEIGHT - Math.random() * 100, width: PLAYER_WIDTH, height: PLAYER_HEIGHT, speed: speed, color: color, passed: false, }); } // ============ СОЗДАНИЕ МОНЕТОК ============ function spawnCoin() { if (!gameRunning) return; if (Math.random() > 0.3) return; // 30% шанс const laneIndex = Math.floor(Math.random() * LANE_COUNT); const x = lanes[laneIndex] - 10; coins.push({ x: x, y: -20, size: 15, collected: false, }); } // ============ ОБНОВЛЕНИЕ ИГРЫ ============ function update() { if (!gameRunning) return; // Управление if (keys['ArrowLeft'] || keys['KeyA']) { player.x -= 5 + player.speed * 0.3; player.angle = -0.15; } else if (keys['ArrowRight'] || keys['KeyD']) { player.x += 5 + player.speed * 0.3; player.angle = 0.15; } else { player.angle *= 0.8; // Плавное возвращение } // Ускорение if (keys['ArrowUp'] || keys['KeyW']) { player.speed = Math.min(player.speed + player.acceleration, player.maxSpeed); } else if (keys['ArrowDown'] || keys['KeyS']) { player.speed = Math.max(player.speed - player.braking, 0); } else { player.speed = Math.max(player.speed - player.friction, 0); } // Границы дороги const minX = ROAD_OFFSET + 5; const maxX = ROAD_OFFSET + LANE_COUNT * LANE_WIDTH - PLAYER_WIDTH - 5; player.x = Math.max(minX, Math.min(maxX, player.x)); // Обновление счёта (дистанция) distance += player.speed * 0.1; score = Math.floor(distance / 10); // Спавн врагов if (frameCount % 60 === 0) { spawnEnemy(); } // Спавн монеток if (frameCount % 30 === 0) { spawnCoin(); } // Движение врагов вниз for (let i = enemies.length - 1; i >= 0; i--) { const e = enemies[i]; e.y += e.speed + player.speed * 0.3; // Проверка на столкновение с игроком if (checkCollision(player, e)) { gameOver(); return; } // Если враг ушёл за экран — удаляем if (e.y > H + 50) { enemies.splice(i, 1); } } // Движение монеток for (let i = coins.length - 1; i >= 0; i--) { const c = coins[i]; c.y += 3 + player.speed * 0.3; // Сбор монетки if (!c.collected && checkCoinCollision(player, c)) { c.collected = true; score += 10; coins.splice(i, 1); continue; } if (c.y > H + 20) { coins.splice(i, 1); } } // Обновление UI scoreDisplay.textContent = score; speedDisplay.textContent = Math.floor(player.speed * 10); distanceDisplay.textContent = Math.floor(distance); frameCount++; } // ============ ПРОВЕРКА СТОЛКНОВЕНИЙ ============ function checkCollision(a, b) { return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y; } function checkCoinCollision(player, coin) { const cx = coin.x + coin.size / 2; const cy = coin.y + coin.size / 2; const px = player.x + player.width / 2; const py = player.y + player.height / 2; const dist = Math.sqrt((cx - px) ** 2 + (cy - py) ** 2); return dist < player.width / 2 + coin.size / 2; } // ============ GAME OVER ============ function gameOver() { gameRunning = false; finalScore.textContent = score; finalDistance.textContent = Math.floor(distance); gameOverScreen.classList.add('show'); } // ============ ОТРИСОВКА ============ function draw() { ctx.clearRect(0, 0, W, H); // Дорога drawRoad(); // Монетки for (let c of coins) { ctx.save(); ctx.shadowColor = '#ffd700'; ctx.shadowBlur = 15; // Монетка const gradient = ctx.createRadialGradient( c.x + c.size / 2, c.y + c.size / 2, 2, c.x + c.size / 2, c.y + c.size / 2, c.size / 2 ); gradient.addColorStop(0, '#ffd700'); gradient.addColorStop(0.7, '#ffaa00'); gradient.addColorStop(1, '#cc8800'); ctx.beginPath(); ctx.arc(c.x + c.size / 2, c.y + c.size / 2, c.size / 2, 0, Math.PI * 2); ctx.fillStyle = gradient; ctx.fill(); // Символ $ ctx.fillStyle = '#8B6914'; ctx.font = 'bold 14px Arial'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.shadowBlur = 0; ctx.fillText('$', c.x + c.size / 2, c.y + c.size / 2 + 1); ctx.restore(); } // Враги for (let e of enemies) { drawCar(e.x, e.y, e.width, e.height, e.color, false, 0); } // Игрок drawCar(player.x, player.y, player.width, player.height, '#ff4757', true, player.angle); // Счёт на экране (крупно) if (gameRunning) { ctx.fillStyle = 'rgba(255,255,255,0.1)'; ctx.font = 'bold 100px Arial'; ctx.textAlign = 'center'; ctx.fillText(score, W / 2, 120); } } // ============ ИГРОВОЙ ЦИКЛ ============ function gameLoop() { update(); draw(); requestAnimationFrame(gameLoop); } // ============ УПРАВЛЕНИЕ ============ document.addEventListener('keydown', (e) => { keys[e.code] = true; if (e.code === 'KeyR' && !gameRunning) { restartGame(); } // Предотвращаем скролл страницы if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Space'].includes(e.code)) { e.preventDefault(); } }); document.addEventListener('keyup', (e) => { keys[e.code] = false; }); // ============ РЕСТАРТ ============ function restartGame() { player.x = W / 2 - PLAYER_WIDTH / 2; player.y = H - 120; player.speed = 0; player.angle = 0; score = 0; distance = 0; enemies = []; coins = []; frameCount = 0; gameRunning = true; gameOverScreen.classList.remove('show'); scoreDisplay.textContent = '0'; speedDisplay.textContent = '0'; distanceDisplay.textContent = '0'; } restartBtn.addEventListener('click', restartGame); // ============ ЗАПУСК ============ gameLoop(); console.log('🏎️ Гонка машинок запущена!'); console.log('Управление: ← → - движение, ↑ - газ, ↓ - тормоз'); </script> </body> </html>