не видно персонажей 
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>2D Файтинг Игра</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            background-color: #333;
            color: #fff;
            font-family: Arial, sans-serif;
            text-align: center;
            overflow: hidden;
        }
        h1 {
            margin-top: 20px;
            font-size: 36px;
        }
        #gameContainer {
            position: relative;
            width: 800px;
            height: 600px;
            margin: 20px auto;
            background-color: #000;
            border: 2px solid #fff;
            overflow: hidden;
        }
        #characterSelect {
            position: absolute;
            top: 0;
            left: 0;
            width: 800px;
            height: 600px;
            background-color: rgba(0, 0, 0, 0.9);
            display: flex;
            justify-content: center;
            align-items: center;
            flex-direction: column;
            z-index: 2;
        }
        #characters {
            display: flex;
            justify-content: center;
            margin-top: 20px;
        }
        .character {
            width: 100px; /* Ширина спрайта выбора */
            height: 200px; /* Высота спрайта выбора */
            margin: 0 20px;
            cursor: pointer;
            border: 2px solid #fff;
            background-size: cover;
            background-position: center;
            background-repeat: no-repeat;
            transition: transform 0.2s;
        }
        .character:hover {
            transform: scale(1.1);
        }
        #gameCanvas {
            width: 800px;
            height: 600px;
            background-image: url('https://via.placeholder.com/800x600/555555/000000?text=Фон+Боя');
            background-size: cover;
            display: none;
        }
        /* Полосы здоровья */
        .health-bar-container {
            position: absolute;
            top: 10px;
            width: 200px;
            height: 20px;
            border: 2px solid #fff;
            background-color: #555;
        }
        #playerHealthContainer {
            left: 50px;
        }
        #botHealthContainer {
            right: 50px;
        }
        .health-bar {
            height: 100%;
            background-color: red;
            width: 100%;
            transition: width 0.3s;
        }
        /* Счетчики очков */
        .score-container {
            position: absolute;
            top: 40px;
            width: 200px;
            font-size: 20px;
        }
        #playerScoreContainer {
            left: 50px;
        }
        #botScoreContainer {
            right: 50px;
        }
        /* Таймер раунда */
        #timer {
            position: absolute;
            top: 10px;
            left: 50%;
            transform: translateX(-50%);
            font-size: 24px;
            background-color: rgba(0,0,0,0.5);
            padding: 5px 10px;
            border-radius: 5px;
        }
        /* Загрузка спрайтов */
        #loadingScreen {
            position: absolute;
            top: 0;
            left: 0;
            width: 800px;
            height: 600px;
            background-color: rgba(0, 0, 0, 0.95);
            display: flex;
            justify-content: center;
            align-items: center;
            flex-direction: column;
            z-index: 3;
        }
        #loadingProgress {
            margin-top: 10px;
            font-size: 18px;
        }
        /* Обратная связь */
        #statusDisplay {
            position: absolute;
            bottom: 10px;
            left: 50%;
            transform: translateX(-50%);
            font-size: 14px;
            background-color: rgba(0,0,0,0.5);
            padding: 5px 10px;
            border-radius: 5px;
        }
    </style>
</head>
<body>
    <h1>2D Файтинг Игра</h1>
    <div id="gameContainer">
        <!-- Полосы здоровья -->
        <div id="playerHealthContainer" class="health-bar-container">
            <div id="playerHealth" class="health-bar"></div>
        </div>
        <div id="botHealthContainer" class="health-bar-container">
            <div id="botHealth" class="health-bar"></div>
        </div>

        <!-- Счетчики очков -->
        <div id="playerScoreContainer" class="score-container">
            Игрок: <span id="playerScore">0</span>
        </div>
        <div id="botScoreContainer" class="score-container">
            Бот: <span id="botScore">0</span>
        </div>

        <!-- Таймер раунда -->
        <div id="timer">Раунд 1: 60 секунд</div>

        <!-- Экран выбора персонажа -->
        <div id="characterSelect">
            <h2>Выберите персонажа</h2>
            <div id="characters">
                <div class="character" data-character="red" style="background-image: url('https://via.placeholder.com/100x200/FF0000/FFFFFF?text=Red');"></div>
                <div class="character" data-character="green" style="background-image: url('https://via.placeholder.com/100x200/00FF00/FFFFFF?text=Green');"></div>
                <div class="character" data-character="blue" style="background-image: url('https://via.placeholder.com/100x200/0000FF/FFFFFF?text=Blue');"></div>
            </div>
        </div>

        <!-- Экран загрузки -->
        <div id="loadingScreen">
            <h2>Загрузка...</h2>
            <div id="loadingProgress">0%</div>
        </div>

        <!-- Canvas для игры -->
        <canvas id="gameCanvas" width="800" height="600"></canvas>

        <!-- Обратная связь -->
        <div id="statusDisplay">Состояние: Идл</div>

        <!-- Аудио элементы -->
        <audio id="attackSound" src="https://www.soundjay.com/buttons/sounds/button-16.mp3"></audio>
        <audio id="hitSound" src="https://www.soundjay.com/buttons/sounds/button-10.mp3"></audio>
        <audio id="victorySound" src="https://www.soundjay.com/misc/sounds/bell-ringing-05.mp3"></audio>
        <audio id="defeatSound" src="https://www.soundjay.com/misc/sounds/failure-buzzer-01.mp3"></audio>
        <audio id="backgroundMusic" src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3" loop></audio>
    </div>

    <script>
        // Обёртка для обеспечения выполнения после загрузки DOM
        window.addEventListener('DOMContentLoaded', () => {
            // Получение элементов
            const canvas = document.getElementById('gameCanvas');
            const ctx = canvas.getContext('2d');
            const characterSelect = document.getElementById('characterSelect');
            const characters = document.querySelectorAll('.character');
            const playerHealthBar = document.getElementById('playerHealth');
            const botHealthBar = document.getElementById('botHealth');
            const playerScoreElem = document.getElementById('playerScore');
            const botScoreElem = document.getElementById('botScore');
            const timerElem = document.getElementById('timer');
            const statusDisplay = document.getElementById('statusDisplay');
            const loadingScreen = document.getElementById('loadingScreen');
            const loadingProgress = document.getElementById('loadingProgress');

            // Аудио элементы
            const attackSound = document.getElementById('attackSound');
            const hitSound = document.getElementById('hitSound');
            const victorySound = document.getElementById('victorySound');
            const defeatSound = document.getElementById('defeatSound');
            const backgroundMusic = document.getElementById('backgroundMusic');

            const GAME_WIDTH = 800;
            const GAME_HEIGHT = 600;

            // Загрузка изображений персонажей
            const spriteImages = {
                redIdle: [],
                redWalk: [],
                greenIdle: [],
                greenWalk: [],
                blueIdle: [],
                blueWalk: []
            };

            const framesPerAnimation = 4; // Количество кадров для каждой анимации

            // Предположим, что у нас по 4 кадра для каждого состояния и персонажа
            for (let i = 1; i <= framesPerAnimation; i++) {
                // Idle спрайты
                const redIdleImg = new Image();
                redIdleImg.src = `https://via.placeholder.com/100x200/FF0000/FFFFFF?text=Red+Idle+${i}`;
                spriteImages.redIdle.push(redIdleImg);

                const greenIdleImg = new Image();
                greenIdleImg.src = `https://via.placeholder.com/100x200/00FF00/FFFFFF?text=Green+Idle+${i}`;
                spriteImages.greenIdle.push(greenIdleImg);

                const blueIdleImg = new Image();
                blueIdleImg.src = `https://via.placeholder.com/100x200/0000FF/FFFFFF?text=Blue+Idle+${i}`;
                spriteImages.blueIdle.push(blueIdleImg);

                // Walk спрайты
                const redWalkImg = new Image();
                redWalkImg.src = `https://via.placeholder.com/100x200/FFAAAA/FFFFFF?text=Red+Walk+${i}`;
                spriteImages.redWalk.push(redWalkImg);

                const greenWalkImg = new Image();
                greenWalkImg.src = `https://via.placeholder.com/100x200/AAFFAA/FFFFFF?text=Green+Walk+${i}`;
                spriteImages.greenWalk.push(greenWalkImg);

                const blueWalkImg = new Image();
                blueWalkImg.src = `https://via.placeholder.com/100x200/AAAAFF/FFFFFF?text=Blue+Walk+${i}`;
                spriteImages.blueWalk.push(blueWalkImg);
            }

            // Проверка загрузки всех изображений
            let imagesLoaded = 0;
            const totalImages = Object.keys(spriteImages).reduce((acc, key) => acc + spriteImages[key].length, 0);

            for (let key in spriteImages) {
                spriteImages[key].forEach(img => {
                    img.onload = () => {
                        imagesLoaded++;
                        const progress = Math.floor((imagesLoaded / totalImages) * 100);
                        loadingProgress.innerText = `${progress}%`;
                        if (imagesLoaded === totalImages) {
                            // Все изображения загружены
                            loadingScreen.style.display = 'none';
                            characterSelect.style.display = 'flex';
                            backgroundMusic.volume = 0.3;
                            backgroundMusic.play();
                        }
                    };
                    img.onerror = () => {
                        console.error(`Не удалось загрузить изображение: ${img.src}`);
                        imagesLoaded++;
                        const progress = Math.floor((imagesLoaded / totalImages) * 100);
                        loadingProgress.innerText = `${progress}%`;
                        if (imagesLoaded === totalImages) {
                            // Все изображения загружены
                            loadingScreen.style.display = 'none';
                            characterSelect.style.display = 'flex';
                            backgroundMusic.volume = 0.3;
                            backgroundMusic.play();
                        }
                    };
                });
            }

            // Класс для персонажей
            class Character {
                constructor({ x, y, width, height, speed, sprites, isBot = false }) {
                    this.x = x;
                    this.y = y;
                    this.width = width;
                    this.height = height;
                    this.speed = speed;
                    this.dx = 0;
                    this.isAttacking = false;
                    this.attackCooldown = false;
                    this.sprites = sprites; // Объект со спрайтами для разных состояний
                    this.currentSpriteState = 'idle'; // Текущее состояние (idle, walk, attack)
                    this.health = 100;
                    this.score = 0;
                    this.currentFrame = 0;
                    this.animationFrame = 0;
                    this.animationSpeed = 10; // Количество игровых циклов на кадр
                    this.isBot = isBot;
                    this.facingRight = true; // Направление персонажа
                }

                setState(state) {
                    if (this.currentSpriteState !== state && this.sprites[state]) {
                        this.currentSpriteState = state;
                        this.currentFrame = 0;
                        this.animationFrame = 0;
                        statusDisplay.innerText = `Состояние: ${this.currentSpriteState.toUpperCase()}`;
                    }
                }

                updatePosition() {
                    this.x += this.dx;

                    // Ограничение движения по границам экрана
                    if (this.x < 0) this.x = 0;
                    if (this.x + this.width > GAME_WIDTH) this.x = GAME_WIDTH - this.width;

                    // Определение направления
                    if (this.dx > 0) {
                        this.facingRight = true;
                    } else if (this.dx < 0) {
                        this.facingRight = false;
                    }

                    // Изменение состояния на 'walk' или 'idle'
                    if (this.dx !== 0) {
                        if (this.currentSpriteState !== 'walk' && !this.isAttacking) {
                            this.setState('walk');
                        }
                    } else {
                        if (this.currentSpriteState !== 'idle' && !this.isAttacking) {
                            this.setState('idle');
                        }
                    }
                }

                updateAnimation() {
                    this.animationFrame++;
                    if (this.animationFrame >= this.animationSpeed) {
                        this.currentFrame = (this.currentFrame + 1) % this.sprites[this.currentSpriteState].length;
                        this.animationFrame = 0;
                    }
                }

                draw() {
                    // Обновление анимации
                    this.updateAnimation();

                    // Выбор текущего спрайта
                    const sprite = this.sprites[this.currentSpriteState][this.currentFrame];

                    // Отрисовка текущего кадра из спрайт-листа
                    if (this.facingRight) {
                        ctx.drawImage(
                            sprite,
                            this.x,
                            this.y,
                            this.width,
                            this.height
                        );
                    } else {
                        // Отражение изображения по горизонтали
                        ctx.save();
                        ctx.scale(-1, 1);
                        ctx.drawImage(
                            sprite,
                            -this.x - this.width,
                            this.y,
                            this.width,
                            this.height
                        );
                        ctx.restore();
                    }

                    // Отображение атаки (зона атаки)
                    if (this.isAttacking) {
                        ctx.fillStyle = 'yellow';
                        if (this.facingRight) {
                            ctx.fillRect(this.x + this.width, this.y + 50, 30, this.height - 100);
                        } else {
                            ctx.fillRect(this.x - 30, this.y + 50, 30, this.height - 100);
                        }
                    }
                }

                attack() {
                    if (!this.attackCooldown) {
                        this.isAttacking = true;
                        this.attackCooldown = true;
                        this.setState('attack');
                        attackSound.currentTime = 0;
                        attackSound.play();
                        setTimeout(() => {
                            this.isAttacking = false;
                            this.setState(this.dx !== 0 ? 'walk' : 'idle');
                        }, 500); // Время выполнения атаки
                        setTimeout(() => {
                            this.attackCooldown = false;
                        }, 800); // Время восстановления атаки
                    }
                }

                getHitbox() {
                    return {
                        x: this.x,
                        y: this.y,
                        width: this.width,
                        height: this.height
                    };
                }

                getAttackHitbox() {
                    if (this.isAttacking) {
                        if (this.facingRight) {
                            return {
                                x: this.x + this.width,
                                y: this.y + 50,
                                width: 30,
                                height: this.height - 100
                            };
                        } else {
                            return {
                                x: this.x - 30,
                                y: this.y + 50,
                                width: 30,
                                height: this.height - 100
                            };
                        }
                    }
                    return null;
                }
            }

            let player;
            let bot;

            // Обработчики выбора персонажа
            characters.forEach(char => {
                char.addEventListener('click', () => {
                    const selectedColor = char.getAttribute('data-character');
                    const sprites = {
                        idle: spriteImages[`${selectedColor}Idle`],
                        walk: spriteImages[`${selectedColor}Walk`],
                        attack: spriteImages[`${selectedColor}Idle`] // В реальной игре использовать отдельные спрайты для атаки
                    };
                    player = new Character({
                        x: 100,
                        y: GAME_HEIGHT - 200,
                        width: 100,
                        height: 200,
                        speed: 5,
                        sprites: sprites,
                        isBot: false
                    });
                    // Инициализация бота с конкретными спрайтами
                    bot = new Character({
                        x: GAME_WIDTH - 200,
                        y: GAME_HEIGHT - 200,
                        width: 100,
                        height: 200,
                        speed: 3,
                        sprites: {
                            idle: spriteImages['blueIdle'],
                            walk: spriteImages['blueWalk'],
                            attack: spriteImages['blueIdle'] // В реальной игре использовать отдельные спрайты для атаки
                        },
                        isBot: true
                    });
                    characterSelect.style.display = 'none';
                    canvas.style.display = 'block';
                    updateHealthBars();
                    updateScores();
                    updateTimer();
                    requestAnimationFrame(gameLoop);
                });
            });

            // Клавиши
            const keys = {
                right: false,
                left: false,
                space: false
            };

            // Обработчики нажатия клавиш
            document.addEventListener('keydown', (e) => {
                switch(e.code) {
                    case 'ArrowRight':
                        keys.right = true;
                        break;
                    case 'ArrowLeft':
                        keys.left = true;
                        break;
                    case 'Space':
                        if (!player.attackCooldown) {
                            player.attack();
                            checkCollision();
                        }
                        break;
                }
            });

            document.addEventListener('keyup', (e) => {
                switch(e.code) {
                    case 'ArrowRight':
                        keys.right = false;
                        break;
                    case 'ArrowLeft':
                        keys.left = false;
                        break;
                }
            });

            // Функция обновления позиции игрока
            function updatePlayer() {
                if (keys.right) {
                    player.dx = player.speed;
                } else if (keys.left) {
                    player.dx = -player.speed;
                } else {
                    player.dx = 0;
                }

                player.updatePosition();
            }

            // Простая логика бота
            function updateBot() {
                // Если бот далеко от игрока, двигаться к игроку
                if (bot.x > player.x + player.width + 50) {
                    bot.dx = -bot.speed;
                    bot.setState('walk');
                } else if (bot.x + bot.width < player.x - 50) {
                    bot.dx = bot.speed;
                    bot.setState('walk');
                } else {
                    bot.dx = 0;
                    bot.setState('idle');
                }

                bot.updatePosition();

                // Атака бота
                if (!bot.attackCooldown && Math.abs(bot.x - player.x) < 150) {
                    bot.attack();
                    checkCollision();
                }
            }

            // Функция проверки столкновений атак
            function checkCollision() {
                // Проверка атаки игрока
                const playerAttack = player.getAttackHitbox();
                if (playerAttack) {
                    const botHitbox = bot.getHitbox();
                    if (isCollision(playerAttack, botHitbox)) {
                        bot.health -= 10;
                        player.score += 10;
                        hitSound.currentTime = 0;
                        hitSound.play();
                        updateHealthBars();
                        updateScores();
                        player.isAttacking = false;
                        if (bot.health <= 0) {
                            victorySound.play();
                            setTimeout(() => {
                                alert('Вы победили!');
                                resetGame();
                            }, 100);
                        }
                    }
                }

                // Проверка атаки бота
                const botAttack = bot.getAttackHitbox();
                if (botAttack) {
                    const playerHitbox = player.getHitbox();
                    if (isCollision(botAttack, playerHitbox)) {
                        player.health -= 10;
                        bot.score += 10;
                        hitSound.currentTime = 0;
                        hitSound.play();
                        updateHealthBars();
                        updateScores();
                        bot.isAttacking = false;
                        if (player.health <= 0) {
                            defeatSound.play();
                            setTimeout(() => {
                                alert('Вы проиграли!');
                                resetGame();
                            }, 100);
                        }
                    }
                }
            }

            // Функция проверки пересечения двух прямоугольников
            function isCollision(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 updateHealthBars() {
                playerHealthBar.style.width = player.health * 2 + 'px'; // 200px максимальная ширина
                botHealthBar.style.width = bot.health * 2 + 'px';
            }

            // Обновление счетчиков очков
            function updateScores() {
                playerScoreElem.innerText = player.score;
                botScoreElem.innerText = bot.score;
            }

            // Таймер раунда
            let roundTime = 60; // Время раунда в секундах
            let timerInterval = null;

            function updateTimer() {
                timerElem.innerText = `Раунд 1: ${roundTime} секунд`;
                timerInterval = setInterval(() => {
                    roundTime--;
                    timerElem.innerText = `Раунд 1: ${roundTime} секунд`;
                    if (roundTime <= 0) {
                        clearInterval(timerInterval);
                        determineRoundWinner();
                    }
                }, 1000);
            }

            // Определение победителя раунда
            function determineRoundWinner() {
                if (player.health > bot.health) {
                    victorySound.play();
                    alert('Вы победили раунд!');
                    resetRound();
                } else if (bot.health > player.health) {
                    defeatSound.play();
                    alert('Вы проиграли раунд!');
                    resetGame();
                } else {
                    alert('Ничья! Начинаем заново!');
                    resetRound();
                }
            }

            // Функция сброса раунда
            function resetRound() {
                player.x = 100;
                player.y = GAME_HEIGHT - 200;
                bot.x = GAME_WIDTH - 200;
                bot.y = GAME_HEIGHT - 200;
                player.health = 100;
                bot.health = 100;
                updateHealthBars();
                player.isAttacking = false;
                bot.isAttacking = false;
                updateScores();
                roundTime = 60;
                updateTimer();
            }

            // Функция сброса игры
            function resetGame() {
                player.x = 100;
                player.y = GAME_HEIGHT - 200;
                bot.x = GAME_WIDTH - 200;
                bot.y = GAME_HEIGHT - 200;
                player.health = 100;
                bot.health = 100;
                player.score = 0;
                bot.score = 0;
                updateHealthBars();
                updateScores();
                player.isAttacking = false;
                bot.isAttacking = false;
                characterSelect.style.display = 'flex';
                canvas.style.display = 'none';
                clearInterval(timerInterval);
                roundTime = 60;
                timerElem.innerText = `Раунд 1: ${roundTime} секунд`;
            }

            // Основной цикл игры
            function gameLoop() {
                // Очистка экрана
                ctx.clearRect(0, 0, GAME_WIDTH, GAME_HEIGHT);

                // Обновление позиций
                updatePlayer();
                updateBot();

                // Проверка столкновений
                checkCollision();

                // Отрисовка персонажей
                player.draw();
                bot.draw();

                // Обновление обратной связи
                statusDisplay.innerText = `Состояние: ${player.currentSpriteState.toUpperCase()}`;

                // Повторный вызов цикла
                requestAnimationFrame(gameLoop);
            }
        });
    </script>
</body>
</html>