🎮ArcadeLab

🌸 Гран-При 18 лет 🌸

by SolarBear25
641 lines25.8 KB
▶ Play
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>🌸 Гран-При 18 лет 🌸</title>
    <style>
        /* ГЛОБАЛЬНЫЙ РОЗОВЫЙ СТИЛЬ */
        * {
            box-sizing: border-box;
            user-select: none;
        }
        body {
            margin: 0;
            min-height: 100vh;
            background: linear-gradient(145deg, #1a0b1a 0%, #2d142c 40%, #4a1e3f 100%);
            display: flex;
            justify-content: center;
            align-items: center;
            font-family: 'Segoe UI', 'Arial', sans-serif;
            touch-action: manipulation;
        }
        .game-wrapper {
            background: rgba(255, 220, 240, 0.1);
            backdrop-filter: blur(4px);
            padding: 20px;
            border-radius: 60px 60px 30px 30px;
            box-shadow: 0 0 60px rgba(255, 20, 147, 0.5), inset 0 0 30px rgba(255, 105, 180, 0.3);
            border: 2px solid #ff69b4;
        }
        .container {
            background: #fce4ec;
            background-image: radial-gradient(circle at 10% 20%, rgba(255, 182, 193, 0.4) 0%, transparent 50%);
            border-radius: 40px;
            padding: 20px;
            max-width: 420px;
            margin: 0 auto;
            box-shadow: inset 0 0 30px #ffb6c1;
            border: 1px solid #ff85a2;
        }

        /* ШАПКА ИГРЫ */
        .header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 0 5px 15px 5px;
            color: #8b1a4a;
            font-weight: 900;
            text-shadow: 0 2px 0 #ffb6c1;
        }
        .score-box {
            background: #4a1a2e;
            padding: 8px 20px;
            border-radius: 50px;
            color: #ffb0d0;
            font-size: 1.4rem;
            letter-spacing: 1px;
            box-shadow: 0 0 15px #ff1493;
            border: 1px solid #ff69b4;
        }
        .lives {
            font-size: 2rem;
            line-height: 1;
        }

        /* Холст (Трасса) */
        canvas {
            display: block;
            width: 100%;
            height: auto;
            aspect-ratio: 360 / 600;
            background: #2b1a22;
            border-radius: 30px;
            box-shadow: 0 0 0 3px #ff69b4, 0 0 0 6px #9b4d6b;
            cursor: pointer;
            touch-action: none;
            margin-bottom: 10px;
        }

        /* Кнопки управления (для мобильных) */
        .controls {
            display: flex;
            justify-content: space-between;
            gap: 10px;
            padding-top: 10px;
        }
        .ctrl-btn {
            background: #7a2b4f;
            border: 2px solid #ff85a2;
            color: #ffe0ec;
            font-size: 2.2rem;
            padding: 12px 0;
            border-radius: 60px;
            flex: 1;
            text-align: center;
            font-weight: bold;
            box-shadow: 0 5px 0 #3f172b;
            transition: all 0.08s ease;
            touch-action: manipulation;
            cursor: pointer;
            letter-spacing: 2px;
        }
        .ctrl-btn:active {
            transform: translateY(5px);
            box-shadow: 0 1px 0 #3f172b;
        }

        /* ЭКРАН ФИНАЛА (ПИСЬМО + ХЛОПУШКИ) */
        .final-screen {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(20, 5, 18, 0.9);
            backdrop-filter: blur(12px);
            z-index: 999;
            justify-content: center;
            align-items: center;
            flex-direction: column;
            padding: 20px;
            animation: fadeInPop 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275);
        }
        .final-screen.show {
            display: flex;
        }
        .letter {
            max-width: 500px;
            width: 100%;
            background: linear-gradient(135deg, #fff5f9, #ffe4ec);
            padding: 40px 30px;
            border-radius: 80px 20px 80px 20px;
            box-shadow: 0 0 80px #ff1493, 0 20px 40px rgba(0,0,0,0.8);
            border: 3px solid #ff69b4;
            text-align: center;
            color: #3b1c2b;
            position: relative;
            transform: scale(1);
            transition: 0.3s;
            font-size: 1rem;
        }
        .letter h1 {
            font-size: 2.8rem;
            margin: 0 0 5px 0;
            background: linear-gradient(45deg, #d61a6b, #ff1493, #ff69b4);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            text-shadow: none;
            font-weight: 900;
        }
        .letter .sub {
            font-size: 1.2rem;
            background: #8b1a4a;
            color: #ffc0d0;
            padding: 5px 20px;
            border-radius: 50px;
            display: inline-block;
            margin-bottom: 15px;
            -webkit-text-fill-color: #ffd1dc;
        }
        .letter p {
            font-size: 1.2rem;
            line-height: 1.6;
            font-weight: 500;
        }
        .letter .emoji-big {
            font-size: 4rem;
            display: block;
            margin: 10px 0;
        }
        .btn-restart {
            background: #d61a6b;
            border: none;
            padding: 15px 40px;
            border-radius: 50px;
            font-size: 1.4rem;
            font-weight: bold;
            color: white;
            margin-top: 20px;
            box-shadow: 0 0 30px #ff1493;
            cursor: pointer;
            transition: 0.2s;
            border: 2px solid #ff85a2;
        }
        .btn-restart:active {
            transform: scale(0.9);
        }

        /* АНИМАЦИЯ КОНФЕТТИ И ХЛОПУШЕК */
        .confetti-container {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            z-index: 1000;
            overflow: hidden;
        }
        .confetti {
            position: absolute;
            width: 14px;
            height: 14px;
            opacity: 0.9;
            animation: confettiFall linear forwards;
        }
        @keyframes confettiFall {
            0% { transform: translateY(-10vh) rotate(0deg) scale(1); opacity: 1; }
            100% { transform: translateY(110vh) rotate(720deg) scale(0.3); opacity: 0; }
        }
        @keyframes fadeInPop {
            0% { opacity: 0; transform: scale(0.5); }
            100% { opacity: 1; transform: scale(1); }
        }

        /* Адаптив */
        @media (max-width: 480px) {
            .letter h1 { font-size: 2.2rem; }
            .letter p { font-size: 1rem; }
            .game-wrapper { padding: 10px; }
            .container { padding: 12px; }
        }
    </style>
</head>
<body>

    <!-- ИГРОВОЙ БЛОК -->
    <div class="game-wrapper">
        <div class="container">
            <div class="header">
                <span class="score-box">💖 <span id="scoreDisplay">0</span>/18</span>
                <span class="lives" id="livesDisplay">❤️❤️❤️</span>
            </div>

            <canvas id="gameCanvas" width="360" height="600"></canvas>

            <div class="controls">
                <div class="ctrl-btn" id="btnLeft">◀ ЛЕВО</div>
                <div class="ctrl-btn" id="btnRight">ПРАВО ▶</div>
            </div>
            <p style="text-align:center; color:#8b1a4a; font-weight:bold; margin:8px 0 0 0; font-size:0.9rem;">
                🏁 Собери 18 💖, объезжай 🚗! 🏁
            </p>
        </div>
    </div>

    <!-- ЭКРАН С ПИСЬМОМ (ФИНАЛ) -->
    <div class="final-screen" id="finalScreen">
        <div class="letter">
            <div class="emoji-big">🏎️💨</div>
            <h1>С 18-ЛЕТИЕМ!</h1>
            <span class="sub">🌸 Гран-При Твоей Жизни 🌸</span>
            <p>
                <strong>Наша Розовая Гонщица!</strong><br><br>
                Сегодня ты пересекаешь финишную черту детства<br>
                и входишь на трассу взрослой жизни на полном газу! 🏁<br><br>
                Пусть твой путь будет быстрым, как формула-1,<br>
                но таким же красивым и стильным, как этот розовый болид.<br>
                <span style="font-size:1.8rem;">💖🔥</span><br><br>
                Желаю тебе миллион побед, верных механиков (друзей),<br>
                бесконечного топлива счастья и только ярких эмоций!<br>
                Ты — наша чемпионка! 🥂✨
            </p>
            <p style="font-style:italic; color:#a1416b;">С любовью, твоя команда поддержки ❤️</p>
            <button class="btn-restart" id="restartBtn">🔁 ПРОКРУТИТЬ ЗАНОВО</button>
        </div>
    </div>

    <!-- КОНТЕЙНЕР ДЛЯ КОНФЕТТИ -->
    <div class="confetti-container" id="confettiContainer"></div>

    <script>
        (function() {
            // === НАСТРОЙКИ ===
            const canvas = document.getElementById('gameCanvas');
            const ctx = canvas.getContext('2d');
            const scoreSpan = document.getElementById('scoreDisplay');
            const livesSpan = document.getElementById('livesDisplay');
            const finalScreen = document.getElementById('finalScreen');
            const confettiContainer = document.getElementById('confettiContainer');

            const W = 360, H = 600;
            canvas.width = W; canvas.height = H;

            // Игрок с параметрами плавности
            const player = {
                x: 180,
                y: 480,
                radius: 20,
                vx: 0,
                acceleration: 0.7,
                friction: 0.92,
                maxSpeed: 10
            };

            // Состояние игры
            let score = 0;
            let lives = 3;
            let gameOver = false;
            let winFlag = false;

            // Массивы
            let hearts = [];
            let obstacles = [];
            let frame = 0;

            // Управление
            let leftPressed = false;
            let rightPressed = false;

            // === ФУНКЦИЯ СОЗДАНИЯ ОБЪЕКТОВ ===
            function spawnHeart() {
                const x = 30 + Math.random() * (W - 60);
                hearts.push({
                    x: x,
                    y: -20,
                    radius: 14,
                    speed: 1.5 + Math.random() * 1.5
                });
            }

            function spawnObstacle() {
                const x = 30 + Math.random() * (W - 60);
                const carEmojis = ['🚗', '🚕', '🚙', '🚌', '🚓'];
                const emoji = carEmojis[Math.floor(Math.random() * carEmojis.length)];
                obstacles.push({
                    x: x,
                    y: -20,
                    radius: 20,
                    speed: 1.2 + Math.random() * 1.8,
                    emoji: emoji
                });
            }

            // === СБРОС ИГРЫ ===
            function resetGame() {
                score = 0;
                lives = 3;
                gameOver = false;
                winFlag = false;
                hearts = [];
                obstacles = [];
                player.x = 180;
                player.vx = 0;
                leftPressed = false;
                rightPressed = false;
                finalScreen.classList.remove('show');
                confettiContainer.innerHTML = '';
                updateUI();
                // Восстанавливаем текст письма на оригинальный
                document.querySelector('.letter h1').textContent = 'С 18-ЛЕТИЕМ!';
                document.querySelector('.letter .sub').textContent = '🌸 Гран-При Твоей Жизни 🌸';
                document.querySelector('.letter p').innerHTML = `
                    <strong>Наша Розовая Гонщица!</strong><br><br>
                    Сегодня ты пересекаешь финишную черту детства<br>
                    и входишь на трассу взрослой жизни на полном газу! 🏁<br><br>
                    Пусть твой путь будет быстрым, как формула-1,<br>
                    но таким же красивым и стильным, как этот розовый болид.<br>
                    <span style="font-size:1.8rem;">💖🔥</span><br><br>
                    Желаю тебе миллион побед, верных механиков (друзей),<br>
                    бесконечного топлива счастья и только ярких эмоций!<br>
                    Ты — наша чемпионка! 🥂✨
                `;
            }

            // === ОБНОВЛЕНИЕ UI ===
            function updateUI() {
                scoreSpan.textContent = Math.min(score, 18);
                let heartsStr = '';
                for (let i = 0; i < lives; i++) heartsStr += '❤️';
                if (lives === 0) heartsStr = '💔💔💔';
                livesSpan.textContent = heartsStr || '💀';
            }

            // === СТОЛКНОВЕНИЯ ===
            function distance(x1, y1, x2, y2) {
                return Math.hypot(x1 - x2, y1 - y2);
            }

            // === ЗАПУСК КОНФЕТТИ ===
            function launchConfetti() {
                confettiContainer.innerHTML = '';
                const colors = ['#ff1493', '#ff69b4', '#ffb6c1', '#ff85a2', '#d61a6b', '#ffc0cb', '#ffffff', '#ffd700'];
                const shapes = ['●', '■', '▲', '★', '♦', '♥'];
                for (let i = 0; i < 150; i++) {
                    const el = document.createElement('div');
                    el.className = 'confetti';
                    el.textContent = shapes[Math.floor(Math.random() * shapes.length)];
                    el.style.left = Math.random() * 100 + '%';
                    el.style.color = colors[Math.floor(Math.random() * colors.length)];
                    el.style.fontSize = (10 + Math.random() * 24) + 'px';
                    el.style.animationDuration = (2 + Math.random() * 3) + 's';
                    el.style.animationDelay = (Math.random() * 2) + 's';
                    el.style.transform = `rotate(${Math.random()*360}deg)`;
                    confettiContainer.appendChild(el);
                }
                for (let i = 0; i < 30; i++) {
                    setTimeout(() => {
                        const pop = document.createElement('div');
                        pop.className = 'confetti';
                        pop.textContent = '✨';
                        pop.style.left = Math.random() * 100 + '%';
                        pop.style.color = '#fff9c4';
                        pop.style.fontSize = (30 + Math.random() * 40) + 'px';
                        pop.style.animationDuration = (1 + Math.random()) + 's';
                        pop.style.animationDelay = '0s';
                        pop.style.opacity = '1';
                        confettiContainer.appendChild(pop);
                        setTimeout(() => pop.remove(), 1200);
                    }, i * 80);
                }
            }

            // === ПОБЕДА (18 сердец) ===
            function winGame() {
                if (winFlag) return;
                winFlag = true;
                gameOver = true;
                launchConfetti();
                setTimeout(() => {
                    finalScreen.classList.add('show');
                }, 400);
            }

            // === ПОТЕРЯ ЖИЗНИ ===
            function loseLife() {
                if (gameOver) return;
                lives--;
                updateUI();
                if (lives <= 0) {
                    gameOver = true;
                    setTimeout(() => {
                        launchConfetti();
                        finalScreen.classList.add('show');
                        document.querySelector('.letter h1').textContent = '💪 НЕ СДАВАЙСЯ!';
                        document.querySelector('.letter .sub').textContent = '🌸 Ты всё равно чемпионка! 🌸';
                        document.querySelector('.letter p').innerHTML = `
                            <strong>Даже если машинки мешали,</strong><br>
                            ты уже победила своим характером! 🏎️<br><br>
                            В 18 лет все дороги открыты,<br>
                            а мы всегда рядом, чтобы подтолкнуть вперёд!<br>
                            <span style="font-size:2rem;">💖🚀</span><br><br>
                            С днём рождения! Ты — лучшая!
                        `;
                    }, 300);
                }
            }

            // === ОБНОВЛЕНИЕ ИГРЫ ===
            function update() {
                if (gameOver) return;

                // Плавное движение
                let accel = 0;
                if (leftPressed) accel = -player.acceleration;
                if (rightPressed) accel = player.acceleration;

                player.vx += accel;
                player.vx *= player.friction;
                if (Math.abs(player.vx) < 0.05) player.vx = 0;
                if (Math.abs(player.vx) > player.maxSpeed) {
                    player.vx = Math.sign(player.vx) * player.maxSpeed;
                }
                player.x += player.vx;

                if (player.x - player.radius < 5) {
                    player.x = 5 + player.radius;
                    player.vx = 0;
                }
                if (player.x + player.radius > W - 5) {
                    player.x = W - 5 - player.radius;
                    player.vx = 0;
                }

                // Спавн
                frame++;
                if (frame % 35 === 0 && hearts.length < 12) spawnHeart();
                if (frame % 45 === 0 && obstacles.length < 7) spawnObstacle();

                // Сердечки
                for (let i = hearts.length - 1; i >= 0; i--) {
                    const h = hearts[i];
                    h.y += h.speed;
                    if (distance(player.x, player.y, h.x, h.y) < player.radius + h.radius) {
                        hearts.splice(i, 1);
                        score++;
                        updateUI();
                        if (score >= 18) {   // ← ИЗМЕНЕНО НА 18
                            winGame();
                        }
                        continue;
                    }
                    if (h.y > H + 30) {
                        hearts.splice(i, 1);
                    }
                }

                // Машинки-препятствия
                for (let i = obstacles.length - 1; i >= 0; i--) {
                    const o = obstacles[i];
                    o.y += o.speed;
                    if (distance(player.x, player.y, o.x, o.y) < player.radius + o.radius) {
                        obstacles.splice(i, 1);
                        loseLife();
                        continue;
                    }
                    if (o.y > H + 30) {
                        obstacles.splice(i, 1);
                    }
                }
            }

            // === РИСОВАНИЕ ===
            function draw() {
                ctx.clearRect(0, 0, W, H);

                // Трасса
                ctx.fillStyle = '#2b1a22';
                ctx.fillRect(0, 0, W, H);
                for (let y = 0; y < H; y += 40) {
                    for (let x = 0; x < W; x += 40) {
                        if ((Math.floor(x/40) + Math.floor(y/40)) % 2 === 0) {
                            ctx.fillStyle = 'rgba(255, 105, 180, 0.15)';
                            ctx.fillRect(x, y, 40, 40);
                        }
                    }
                }
                ctx.strokeStyle = '#ff69b4';
                ctx.lineWidth = 6;
                ctx.setLineDash([15, 20]);
                ctx.beginPath();
                ctx.moveTo(10, 0);
                ctx.lineTo(10, H);
                ctx.moveTo(W-10, 0);
                ctx.lineTo(W-10, H);
                ctx.stroke();
                ctx.setLineDash([]);

                // Сердечки
                for (let h of hearts) {
                    ctx.shadowColor = '#ff1493';
                    ctx.shadowBlur = 25;
                    ctx.font = '28px "Segoe UI", Arial';
                    ctx.textAlign = 'center';
                    ctx.textBaseline = 'middle';
                    ctx.fillStyle = '#ff1493';
                    ctx.fillText('💖', h.x, h.y);
                    ctx.shadowBlur = 0;
                }

                // Машинки
                for (let o of obstacles) {
                    ctx.shadowColor = '#ff4500';
                    ctx.shadowBlur = 20;
                    ctx.font = '32px "Segoe UI", Arial';
                    ctx.textAlign = 'center';
                    ctx.textBaseline = 'middle';
                    ctx.fillStyle = '#ff6347';
                    ctx.fillText(o.emoji, o.x, o.y);
                    ctx.shadowBlur = 0;
                }

                // Игрок
                ctx.shadowColor = '#ff1493';
                ctx.shadowBlur = 40;
                ctx.font = '44px "Segoe UI", Arial';
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                ctx.fillStyle = '#ff1493';
                ctx.fillText('🏎️', player.x, player.y);
                ctx.shadowBlur = 0;

                // Тень
                ctx.beginPath();
                ctx.arc(player.x, player.y+25, 15, 0, Math.PI*2);
                ctx.fillStyle = 'rgba(255,20,147,0.2)';
                ctx.filter = 'blur(8px)';
                ctx.fill();
                ctx.filter = 'none';

                // Финишная черта с 18
                ctx.fillStyle = '#ff69b4';
                ctx.font = 'bold 16px Arial';
                ctx.fillText('🏁 ФИНИШ (18💖) 🏁', W/2, 25);
            }

            // === ИГРОВОЙ ЦИКЛ ===
            function gameLoop() {
                update();
                draw();
                requestAnimationFrame(gameLoop);
            }

            // === УПРАВЛЕНИЕ ===
            function handleKeyDown(e) {
                const key = e.key;
                if (key === 'ArrowLeft' || key === 'Left' || key === 'a' || key === 'A') {
                    leftPressed = true;
                    e.preventDefault();
                } else if (key === 'ArrowRight' || key === 'Right' || key === 'd' || key === 'D') {
                    rightPressed = true;
                    e.preventDefault();
                }
            }
            function handleKeyUp(e) {
                const key = e.key;
                if (key === 'ArrowLeft' || key === 'Left' || key === 'a' || key === 'A') {
                    leftPressed = false;
                    e.preventDefault();
                } else if (key === 'ArrowRight' || key === 'Right' || key === 'd' || key === 'D') {
                    rightPressed = false;
                    e.preventDefault();
                }
            }

            // Мобильные кнопки
            document.getElementById('btnLeft').addEventListener('touchstart', (e) => { e.preventDefault(); leftPressed = true; });
            document.getElementById('btnLeft').addEventListener('touchend', (e) => { e.preventDefault(); leftPressed = false; });
            document.getElementById('btnLeft').addEventListener('mousedown', () => { leftPressed = true; });
            document.getElementById('btnLeft').addEventListener('mouseup', () => { leftPressed = false; });
            document.getElementById('btnLeft').addEventListener('mouseleave', () => { leftPressed = false; });

            document.getElementById('btnRight').addEventListener('touchstart', (e) => { e.preventDefault(); rightPressed = true; });
            document.getElementById('btnRight').addEventListener('touchend', (e) => { e.preventDefault(); rightPressed = false; });
            document.getElementById('btnRight').addEventListener('mousedown', () => { rightPressed = true; });
            document.getElementById('btnRight').addEventListener('mouseup', () => { rightPressed = false; });
            document.getElementById('btnRight').addEventListener('mouseleave', () => { rightPressed = false; });

            document.getElementById('restartBtn').addEventListener('click', resetGame);

            window.addEventListener('keydown', handleKeyDown);
            window.addEventListener('keyup', handleKeyUp);

            resetGame();
            gameLoop();
        })();
    </script>
</body>
</html>

Game Source: 🌸 Гран-При 18 лет 🌸

Creator: SolarBear25

Libraries: none

Complexity: complex (641 lines, 25.8 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: 18-solarbear25" to link back to the original. Then publish at arcadelab.ai/publish.