Ни для кого уже не секрет, что ​нейросети сегодня используются при разработке игр: создание концептов, арта, написание историй. А что насчет кодинга? Могут ли нейросети кодить вместо разработчиков и создавать полноценные игры? За ответом на этот вопрос я обратился к одной из лучших по мнению многих обзорщиков нейросетей для разработки – Qwen. Кстати, эта нейросеть бесплатна и без проблем работает в РФ.

Давайте начнем с простого. База для любого разработчика игр – аналог Pong! Но с небольшим усложнением. Мне захотелось, чтобы вместо шарика в игре летала снежинка. Я вбил самый простой промпт:

Напиши игру типа Pong! Вместо шарика сделай снежинку

В результате в течение 1 минуты нейросеть написала 475 строк кода и выдала мне саммари:

Это полноценная HTML-игра в стиле Pong с снежинкой! Основные особенности:

  • Вместо шарика используется анимированная снежинка с вращением

  • Стильный темный интерфейс с градиентами и свечением

  • Анимированный снег в фоне

  • Реалистичная физика отскоков

  • Подсчет очков до 5

  • Эффекты при отскоке (вращение снежинки)

  • Адаптивный дизайн

⌨️ Управление:

  • Игрок 1: W и S

  • Игрок 2: Стрелки вверх и вниз

? Особенности дизайна:

  • Градиентный фон с зимней тематикой

  • Анимированные снежинки в фоне

  • Свечение элементов

  • Плавные переходы и анимации

  • Экран окончания игры с кнопкой перезапуска

Игра полностью автономна и работает в любом современном браузере!

Так выглядела самая первая версия игры
Так выглядела самая первая версия игры

То есть, Qwen в действительности сделала даже больше, чем я просил. Нейронка добавила в игру фон со стильными снежинками и добавила в игру полноценный PVP режим. Хотя, режима PVE в игре не было. Справедливости ради, в этом моя вина – я подразумевал его наличие у себя в голове, но не написал об этом в промпте. Что ж, давайте исправим:

Я: Можешь добавить в игру PVE режим?

Qwen: Конечно! Вот обновлённая версия игры Snow Pong с режимом PVE (игрок против компьютера). Я добавил:

  • Кнопку выбора режима: PVP или PVE

  • В режиме PVE правая ракетка управляется ИИ

  • ИИ отслеживает положение снежинки с небольшой задержкой для реалистичности

  • Сохраняется вся графика и анимации

Далее ещё минута, ещё 544 строчки кода и перевод мной новая версия игры: теперь я могу выбрать режим игры: PVP или PVE. Выбираем игру против компьютера и… понимаем, что это слишком легко. Qwen пожалел нас и сделал ракетку ИИ-противника очень медленной. С такой скоростью он отражал только один удар из пяти. Хорошо, что вместе с этим он предложил:

Qwen: Хочешь добавить уровни сложности (лёгкий/средний/сложный ИИ)?

Я: Да, давай добавим уровни сложности

Новое минутное ожидание и еще 536 строчек кода и передо мной новая игра с уровнями сложности. И вместе с этим, новое предложение от ИИ:

Qwen: Хочешь добавить звуки или счётчик очков за сессию? ?
Я: Да, давай добавим звуки и счетчик очков за сессию, а так же переведем управление игрока в PVE режиме на стрелочки

Управление на W/S не всегда было удобно, так как эти символы не работали в верхнем регистре или в русской раскладке. Нейросеть в переписке со мной предлагала исправить эти проблемы, но я решил не зацикливаться на этом и просто перевести управление на стрелочки.

Итак, еще пару минут (по мере усложнения кода увеличивается и время ожидания) и 614 строчек кода спустя нас ждет новая версия игры. Новая версия оказалась проблемной – игра крашилась сразу же после запуска. После пары сообщений Qwen понял в чем была причина краша и исправил его. Но появилась новая проблема – теперь в PVE режиме ракетка игрока (на стрелочках) не двигалась. После недолгой переписки с ИИ мы решили проблему, на это ушло около пяти минут. Очень понравилась его решительность:


Я: Слушай, стрелочки все еще не работают Qwen: Спасибо, что держишь меня в курсе! Давай раз и навсегда решим проблему с управлением стрелочками

Раз и навсегда решить проблему со стрелочками не удалось, поэтому я предложил альтернативу – управление второго игрока на клавишах O и L. Таким образом в PVP режиме игрок 1 управлял на WS, а игрок 2 на OL, а в PVE режиме игрок управлял на WS.

До идеальной игры осталась последняя деталь: боты в PVE режиме были слишком слабы – даже сильный бот не создавал никаких проблем. Я попросил его повысить уровень сложности и увеличить скорость передвижения ракетки у ботов – и все сработало. Теперь чтобы победить сложного бота надо постараться. Игра полностью готова и любой желающий может в неё поиграть:

https://chat.qwen.ai/s/deploy/386f16fb-096d-4fe2-b706-a8c72374825c

Не знаю, как долго она будет храниться на серверах, поэтому не могу ручаться за работоспособность ссылки для тех, кто увидит статью сильно позже её выхода.

Я добавил меню игры
Я добавил меню игры
И окно победы/поражения
И окно победы/поражения
А так стал выглядеть сам геймплей
А так стал выглядеть сам геймплей

Что я получил в итоге?

Полноценный симулятор Pong! со снежинкой вместо мячика. На фоне падал снег, добавляя игре атмосферы. В игре присутствовал счетчик очков. Удары ракетки по мячику и победа озвучивались. В игре было два режима: PVP и PVE и три уровня сложности для PVE режима. Режим и сложность выбирались в главном меню игры. Нейросеть отлично запоминает что мы с ней делали и по моей просьбе легко достает нужную мне версию игры. Итоговый код игры составил 701 строчку. Его я приложу ниже. Отмечу также, что мне не пришлось применить никаких знаний программирования для создания этой игры. Все что я делал – это ставил задачи нейросети.

Что я потратил?

Примерно полтора часа времени на диалог с ИИ с учетом времени ожидания ответа. Нейросеть бесплатна и ничего от меня не потребовала.

Получается, что нейросети уже сейчас могут успешно генерировать простые игры типа Pong!, даже с небольшими усложнениями. Но, что будет, если попросить их создать что-то более сложное? В следующий раз мы с Qwen попробуем создать что-то посложнее понга. Например, платформер. И я обязательно напишу об этом.

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Snow Pong</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Arial', sans-serif;
        }
        
        body {
            background: linear-gradient(135deg, #1e3c72, #2a5298);
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            overflow: hidden;
        }
        
        .game-container {
            position: relative;
            width: 800px;
            height: 600px;
            background: rgba(10, 20, 40, 0.8);
            border-radius: 20px;
            box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
            overflow: hidden;
            border: 2px solid rgba(255, 255, 255, 0.2);
        }
        
        .game-title {
            text-align: center;
            color: white;
            padding: 20px;
            font-size: 28px;
            font-weight: bold;
            text-shadow: 0 0 10px rgba(135, 206, 250, 0.8);
        }
        
        .score-board {
            display: flex;
            justify-content: space-around;
            background: rgba(0, 0, 0, 0.3);
            padding: 15px;
            color: white;
            font-size: 24px;
            font-weight: bold;
        }
        
        .score {
            text-shadow: 0 0 5px rgba(135, 206, 250, 0.8);
        }
        
        .session-score {
            font-size: 16px;
            color: rgba(255, 255, 255, 0.7);
            margin-top: 5px;
            text-align: center;
        }
        
        .paddle {
            position: absolute;
            width: 15px;
            height: 100px;
            background: linear-gradient(to right, #4facfe, #00f2fe);
            border-radius: 10px;
            box-shadow: 0 0 15px rgba(79, 172, 254, 0.6);
        }
        
        .left-paddle {
            left: 30px;
        }
        
        .right-paddle {
            right: 30px;
        }
        
        /* --- ДВОЙНОЙ КРЕСТ — СНЕЖИНКА (настоящая!) --- */
        .snowflake {
            position: absolute;
            width: 6px;
            height: 6px;
            background: white;
            border-radius: 50%;
            transform: translate(-50%, -50%);
            box-shadow: 
                /* Горизонтальные лучи (← и →) */
                -15px 0 0 rgba(255, 255, 255, 0.9),
                15px 0 0 rgba(255, 255, 255, 0.9),
                
                /* Вертикальные лучи (↑ и ↓) */
                0 -15px 0 rgba(255, 255, 255, 0.9),
                0 15px 0 rgba(255, 255, 255, 0.9),
                
                /* Диагональ ↖ и ↘ */
                -11px -11px 0 rgba(255, 255, 255, 0.8),
                11px 11px 0 rgba(255, 255, 255, 0.8),
                
                /* Диагональ ↗ и ↙ */
                11px -11px 0 rgba(255, 255, 255, 0.8),
                -11px 11px 0 rgba(255, 255, 255, 0.8);
            animation: rotate 8s linear infinite;
            filter: drop-shadow(0 0 2px rgba(255, 255, 255, 0.8));
        }

        @keyframes rotate {
            0% { transform: translate(-50%, -50%) rotate(0deg); }
            100% { transform: translate(-50%, -50%) rotate(360deg); }
        }
        
        .center-line {
            position: absolute;
            left: 50%;
            top: 0;
            bottom: 0;
            width: 2px;
            background: rgba(255, 255, 255, 0.2);
            transform: translateX(-50%);
        }
        
        .center-line::before {
            content: '';
            position: absolute;
            top: 50%;
            left: 50%;
            width: 10px;
            height: 10px;
            background: rgba(255, 255, 255, 0.2);
            border-radius: 50%;
            transform: translate(-50%, -50%);
        }
        
        .controls {
            text-align: center;
            color: rgba(255, 255, 255, 0.7);
            margin-top: 10px;
            font-size: 14px;
        }
        
        .game-over {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.8);
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            z-index: 10;
            opacity: 0;
            pointer-events: none;
            transition: opacity 0.5s;
        }
        
        .game-over.active {
            opacity: 1;
            pointer-events: all;
        }
        
        .game-over h2 {
            color: white;
            font-size: 48px;
            margin-bottom: 20px;
            text-shadow: 0 0 20px rgba(135, 206, 250, 0.8);
        }
        
        .game-over p {
            color: #4facfe;
            font-size: 24px;
            margin-bottom: 30px;
        }
        
        .restart-btn {
            background: linear-gradient(45deg, #4facfe, #00f2fe);
            color: white;
            border: none;
            padding: 15px 30px;
            font-size: 18px;
            border-radius: 25px;
            cursor: pointer;
            box-shadow: 0 5px 15px rgba(79, 172, 254, 0.4);
            transition: all 0.3s;
        }
        
        .restart-btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 8px 20px rgba(79, 172, 254, 0.6);
        }
        
        .sound-toggle {
            position: absolute;
            top: 10px;
            right: 10px;
            background: transparent;
            border: none;
            color: rgba(255, 255, 255, 0.7);
            font-size: 20px;
            cursor: pointer;
            z-index: 5;
        }
        
        .snow-effect {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            z-index: 1;
        }
        
        .snow {
            position: absolute;
            background: white;
            border-radius: 50%;
            opacity: 0.8;
            pointer-events: none;
        }

        .start-screen {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.9);
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            z-index: 20;
            color: white;
            text-align: center;
            padding: 20px;
        }

        .start-screen h2 {
            font-size: 36px;
            margin-bottom: 20px;
            text-shadow: 0 0 10px rgba(135, 206, 250, 0.8);
        }

        .start-option {
            margin: 15px 0;
            font-size: 18px;
            color: rgba(255, 255, 255, 0.9);
        }

        .mode-btn, .difficulty-btn {
            display: inline-block;
            padding: 8px 16px;
            margin: 0 10px;
            border: 2px solid rgba(255, 255, 255, 0.3);
            background: transparent;
            color: white;
            border-radius: 20px;
            cursor: pointer;
            font-size: 14px;
            transition: all 0.3s;
        }
        
        .mode-btn.active, .difficulty-btn.active {
            background: rgba(79, 172, 254, 0.4);
            border-color: #4facfe;
            box-shadow: 0 0 10px rgba(79, 172, 254, 0.5);
        }
        
        .mode-btn:hover, .difficulty-btn:hover {
            background: rgba(255, 255, 255, 0.1);
        }

        .start-btn {
            margin-top: 30px;
            padding: 15px 40px;
            background: linear-gradient(45deg, #4facfe, #00f2fe);
            color: white;
            border: none;
            border-radius: 30px;
            font-size: 18px;
            cursor: pointer;
            box-shadow: 0 5px 15px rgba(79, 172, 254, 0.4);
            transition: all 0.3s;
        }

        .start-btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 8px 20px rgba(79, 172, 254, 0.6);
        }

        .focus-hint {
            margin-top: 20px;
            padding: 10px 20px;
            background: rgba(255, 255, 255, 0.1);
            border-radius: 10px;
            color: #4facfe;
            font-size: 16px;
            cursor: pointer;
            border: 1px solid rgba(255, 255, 255, 0.3);
        }

        .debug-info {
            position: absolute;
            top: 10px;
            left: 10px;
            color: #00ff00;
            font-size: 12px;
            z-index: 10;
            background: rgba(0, 0, 0, 0.7);
            padding: 5px;
            border-radius: 5px;
        }
    </style>
</head>
<body>
    <div class="game-container">
        <div class="game-title">❄️ Snow Pong ❄️</div>
        
        <button class="sound-toggle" id="sound-btn">?</button>
        
        <div class="score-board">
            <div class="score" id="left-score">0</div>
            <div class="score" id="right-score">0</div>
        </div>
        
        <div class="session-score">
            Всего голов за сессию: <span id="total-goals">0</span>
        </div>
        
        <div class="center-line"></div>
        <div class="paddle left-paddle" id="left-paddle"></div>
        <div class="paddle right-paddle" id="right-paddle"></div>
        <div class="snowflake" id="snowflake"></div>
        <div class="snow-effect" id="snow-effect"></div>
        
        <div class="game-over" id="game-over">
            <h2>Игра окончена!</h2>
            <p id="winner-text">Победитель: Игрок 1</p>
            <button class="restart-btn" id="restart-btn">Новая игра</button>
        </div>
        
        <div class="controls">
            <div id="control-hint">Управление: W/S</div>
        </div>

        <div class="start-screen" id="start-screen">
            <h2>Добро пожаловать в Snow Pong! ❄️</h2>
            
            <div class="start-option">
                <strong>Режим игры:</strong><br>
                <button class="mode-btn active" data-mode="pvp">PVP</button>
                <button class="mode-btn" data-mode="pve">PVE</button>
            </div>
            
            <div class="start-option" id="difficulty-section">
                <strong>Сложность (для PVE):</strong><br>
                <button class="difficulty-btn active" data-level="easy">Лёгкий</button>
                <button class="difficulty-btn" data-level="medium">Средний</button>
                <button class="difficulty-btn" data-level="hard">Сложный</button>
            </div>
            
            <button class="start-btn" id="start-game-btn">Начать игру</button>
            
            <div class="focus-hint" id="focus-btn">? Кликните сюда для фокуса</div>
        </div>

        <div class="debug-info" id="debug">Последняя клавиша: —</div>
    </div>

    <script>
        // Элементы
        const gameContainer = document.querySelector('.game-container');
        const leftPaddle = document.getElementById('left-paddle');
        const rightPaddle = document.getElementById('right-paddle');
        const snowflake = document.getElementById('snowflake');
        const leftScoreElement = document.getElementById('left-score');
        const rightScoreElement = document.getElementById('right-score');
        const totalGoalsElement = document.getElementById('total-goals');
        const gameOverScreen = document.getElementById('game-over');
        const winnerText = document.getElementById('winner-text');
        const restartBtn = document.getElementById('restart-btn');
        const snowEffect = document.getElementById('snow-effect');
        const soundBtn = document.getElementById('sound-btn');
        const controlHint = document.getElementById('control-hint');
        const startScreen = document.getElementById('start-screen');
        const debug = document.getElementById('debug');

        // Настройки
        let gameMode = 'pvp';
        let difficulty = 'medium';
        let soundEnabled = true;
        let audioContext = null;

        // Параметры
        const gameWidth = 800;
        const gameHeight = 600;
        const paddleHeight = 100;
        const paddleWidth = 15;
        const snowflakeSize = 30;
        const paddleSpeed = 8;
        const maxScore = 5;
        
        // Игровые переменные
        let leftPaddleY = gameHeight / 2 - paddleHeight / 2;
        let rightPaddleY = gameHeight / 2 - paddleHeight / 2;
        let snowflakeX = gameWidth / 2;
        let snowflakeY = gameHeight / 2;
        let snowflakeVelX = 5;
        let snowflakeVelY = 3;
        let leftScore = 0;
        let rightScore = 0;
        let totalGoals = 0;
        let gameActive = false;

        // Управление
        const keys = { w: false, s: false, o: false, l: false };

        // --- НАСТРОЙКИ СЛОЖНОСТИ ---
        const difficultySettings = {
            easy: { speed: 0.1, error: 30, multiplier: 1 },
            medium: { speed: 0.15, error: 10, multiplier: 2 },
            hard: { speed: 0.2, error: 2, multiplier: 3 }
        };

        // --- УПРОЩЁННЫЙ ИИ (без застревания) ---
        function moveAiPaddle() {
            if (gameMode !== 'pve') return;

            const settings = difficultySettings[difficulty];
            const rightPaddleCenter = rightPaddleY + paddleHeight / 2;
            let targetY = snowflakeY;
            const error = difficulty === 'hard' ? 0 : (Math.random() * settings.error - settings.error / 2);
            const finalTarget = targetY + error;
            const diff = finalTarget - rightPaddleCenter;
            const threshold = difficulty === 'hard' ? 2 : 5;

            if (Math.abs(diff) > threshold) {
                const moveSpeed = paddleSpeed * settings.speed * settings.multiplier;
                if (diff > 0) {
                    rightPaddleY += moveSpeed;
                } else {
                    rightPaddleY -= moveSpeed;
                }
            }

            if (rightPaddleY < 0) rightPaddleY = 0;
            if (rightPaddleY > gameHeight - paddleHeight) rightPaddleY = gameHeight - paddleHeight;
        }

        // --- АУДИО ---
        function initAudio() {
            if (audioContext) return;
            try {
                audioContext = new (window.AudioContext || window.webkitAudioContext)();
            } catch (e) {
                console.warn('Audio not available');
            }
        }

        function playSound(freq, dur = 0.1) {
            if (!soundEnabled || !audioContext) return;
            const osc = audioContext.createOscillator();
            const gain = audioContext.createGain();
            osc.connect(gain);
            gain.connect(audioContext.destination);
            osc.frequency.value = freq;
            osc.type = 'square';
            gain.gain.setValueAtTime(0.1, audioContext.currentTime);
            gain.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + dur);
            osc.start();
            osc.stop(audioContext.currentTime + dur);
        }

        function playBounce() { playSound(300); }
        function playScore() { playSound(150, 0.2); }
        function playWin() { playSound(800, 0.3); }

        soundBtn.addEventListener('click', () => {
            soundEnabled = !soundEnabled;
            soundBtn.textContent = soundEnabled ? '?' : '?';
        });

        // --- СНЕГ ---
        function createSnowflakes() {
            for (let i = 0; i < 20; i++) {
                const snow = document.createElement('div');
                snow.classList.add('snow');
                const size = Math.random() * 6 + 2;
                snow.style.width = `${size}px`;
                snow.style.height = `${size}px`;
                snow.style.left = `${Math.random() * 100}%`;
                snow.style.top = `${Math.random() * 100}%`;
                snow.style.opacity = Math.random() * 0.7 + 0.3;
                snow.dataset.speed = Math.random() * 2 + 1;
                snowEffect.appendChild(snow);
            }
        }
        
        function animateSnowflakes() {
            document.querySelectorAll('.snow').forEach(snow => {
                let top = parseFloat(snow.style.top) + parseFloat(snow.dataset.speed);
                if (top > 100) top = -5;
                snow.style.top = `${top}%`;
            });
        }
        
        // --- ВЫБОР НА СТАРТЕ ---
        const modeButtons = document.querySelectorAll('.mode-btn');
        const difficultyButtons = document.querySelectorAll('.difficulty-btn');
        const difficultySection = document.getElementById('difficulty-section');
        const startGameBtn = document.getElementById('start-game-btn');
        const focusBtn = document.getElementById('focus-btn');

        modeButtons.forEach(btn => {
            btn.addEventListener('click', () => {
                modeButtons.forEach(b => b.classList.remove('active'));
                btn.classList.add('active');
                gameMode = btn.dataset.mode;
                difficultySection.style.display = gameMode === 'pve' ? 'block' : 'none';
                updateControlHint();
            });
        });

        difficultyButtons.forEach(btn => {
            btn.addEventListener('click', () => {
                difficultyButtons.forEach(b => b.classList.remove('active'));
                btn.classList.add('active');
                difficulty = btn.dataset.level;
            });
        });

        // --- ФОКУС ---
        function setFocus() {
            document.body.focus();
            debug.textContent = 'Фокус установлен';
            setTimeout(() => debug.textContent = 'Последняя клавиша: —', 1000);
        }

        focusBtn.addEventListener('click', setFocus);
        startGameBtn.addEventListener('click', setFocus);

        // --- УПРАВЛЕНИЕ ---
        document.addEventListener('keydown', (e) => {
            const key = e.key.toLowerCase();
            debug.textContent = `Key down: ${e.key}`;
            if (keys.hasOwnProperty(key)) {
                keys[key] = true;
                e.preventDefault();
            }
        });
        
        document.addEventListener('keyup', (e) => {
            const key = e.key.toLowerCase();
            if (keys.hasOwnProperty(key)) {
                keys[key] = false;
            }
        });

        // --- ИГРОВАЯ ЛОГИКА ---
        function updateControlHint() {
            controlHint.textContent = gameMode === 'pvp'
                ? 'Игрок 1: W/S | Игрок 2: O/L'
                : 'Вы играете за левую ракетку. Управление: W/S';
        }

        function checkCollision(el1, el2) {
            const r1 = el1.getBoundingClientRect();
            const r2 = el2.getBoundingClientRect();
            return !(r1.right < r2.left || r1.left > r2.right || r1.bottom < r2.top || r1.top > r2.bottom);
        }

        function resetSnowflake() {
            snowflakeX = gameWidth / 2;
            snowflakeY = gameHeight / 2;
            snowflakeVelX = 5 * (Math.random() > 0.5 ? 1 : -1);
            snowflakeVelY = 3 * (Math.random() > 0.5 ? 1 : -1);
            updateSnowflakePosition();
        }

        function updateSnowflakePosition() {
            snowflake.style.left = `${snowflakeX}px`;
            snowflake.style.top = `${snowflakeY}px`;
        }

        function updatePaddlePositions() {
            leftPaddle.style.top = `${leftPaddleY}px`;
            rightPaddle.style.top = `${rightPaddleY}px`;
        }

        function resetGame() {
            leftScore = 0;
            rightScore = 0;
            leftScoreElement.textContent = '0';
            rightScoreElement.textContent = '0';
            leftPaddleY = gameHeight / 2 - paddleHeight / 2;
            rightPaddleY = gameHeight / 2 - paddleHeight / 2;
            resetSnowflake();
            updatePaddlePositions();
        }

        // --- ИГРОВОЙ ЦИКЛ ---
        function gameLoop() {
            if (gameActive) {
                // Управление
                if (gameMode === 'pvp') {
                    if (keys.w) leftPaddleY = Math.max(0, leftPaddleY - paddleSpeed);
                    if (keys.s) leftPaddleY = Math.min(gameHeight - paddleHeight, leftPaddleY + paddleSpeed);
                    if (keys.o) rightPaddleY = Math.max(0, rightPaddleY - paddleSpeed);
                    if (keys.l) rightPaddleY = Math.min(gameHeight - paddleHeight, rightPaddleY + paddleSpeed);
                } else if (gameMode === 'pve') {
                    if (keys.w) leftPaddleY = Math.max(0, leftPaddleY - paddleSpeed);
                    if (keys.s) leftPaddleY = Math.min(gameHeight - paddleHeight, leftPaddleY + paddleSpeed);
                    moveAiPaddle();
                }

                // Движение снежинки
                snowflakeX += snowflakeVelX;
                snowflakeY += snowflakeVelY;
                updateSnowflakePosition();

                // Отскок от стен
                if (snowflakeY <= 0 || snowflakeY >= gameHeight - 6) {
                    snowflakeVelY = -snowflakeVelY;
                    playBounce();
                }

                // Столкновение
                if (checkCollision(snowflake, leftPaddle) || checkCollision(snowflake, rightPaddle)) {
                    snowflakeVelX = -snowflakeVelX * 1.05;
                    if (checkCollision(snowflake, rightPaddle)) {
                        snowflakeVelX *= 1.03;
                    }
                    playBounce();
                }

                // Гол
                if (snowflakeX < 0) {
                    rightScore++;
                    totalGoals++;
                    playScore();
                    resetSnowflake();
                } else if (snowflakeX > gameWidth) {
                    leftScore++;
                    totalGoals++;
                    playScore();
                    resetSnowflake();
                }

                // Победа
                if (leftScore >= maxScore || rightScore >= maxScore) {
                    gameActive = false;
                    playWin();
                    gameOverScreen.classList.add('active');
                    winnerText.textContent = leftScore >= maxScore 
                        ? (gameMode === 'pve' ? '? Вы победили!' : 'Победитель: Игрок 1!')
                        : (gameMode === 'pve' ? '? Компьютер победил!' : 'Победитель: Игрок 2!');
                }

                // Обновление
                leftScoreElement.textContent = leftScore;
                rightScoreElement.textContent = rightScore;
                totalGoalsElement.textContent = totalGoals;
                updatePaddlePositions();
                animateSnowflakes();
            }
            requestAnimationFrame(gameLoop);
        }

        // --- ЗАПУСК ИГРЫ ---
        startGameBtn.addEventListener('click', () => {
            startScreen.style.display = 'none';
            initAudio();
            setFocus();
            gameActive = true;
            updateControlHint();
            requestAnimationFrame(gameLoop);
        });

        restartBtn.addEventListener('click', () => {
            resetGame();
            gameOverScreen.classList.remove('active');
            gameActive = true;
            setFocus();
        });

        // --- ИНИЦИАЛИЗАЦИЯ ---
        window.onload = () => {
            createSnowflakes();
            difficultySection.style.display = 'none';
            updateControlHint();
            document.body.tabIndex = 0;
            document.body.focus();
        };
    </script>
</body>
</html>

Комментарии (7)


  1. monowar
    04.08.2025 14:17

    Знатная простыня!


  1. Mr_Zavod
    04.08.2025 14:17

    Хотите сказать, что в будущем люди будут играть только в понг?

    Ужасное будущее