CoolFace
Apppublic

Avtor2/Space_battle

sourceHugging Faceupdated 2y agoView on Hugging Face
1likes
o7eXxtYfDIn1H1qIT.html796 linesDownload Raw Back to root
1<html><head><base href="https://cosmic-rhythm-battle.com/"><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Космическая Ритмичная Битва</title><style>2    body, html {3        margin: 0;4        padding: 0;5        overflow: hidden;6        background: #000;7        font-family: 'Orbitron', sans-serif;8        color: #fff;9        cursor: crosshair; /* Custom cursor */10    }11    #gameCanvas {12        position: absolute;13        top: 0;14        left: 0;15    }16    #ui {17        position: absolute;18        top: 10px;19        left: 10px;20        z-index: 10;21    }22    #modeSelection {23        position: absolute;24        top: 50%;25        left: 50%;26        transform: translate(-50%, -50%);27        text-align: center;28        background: rgba(0, 0, 0, 0.7);29        padding: 20px;30        border-radius: 10px;31        display: none;32    }33    #modeSelection h2 {34        margin-bottom: 20px;35    }36    #modeSelection button {37        padding: 10px 20px;38        font-size: 18px;39        margin: 0 10px;40        background: #4CAF50;41        color: white;42        border: none;43        cursor: pointer;44        border-radius: 5px;45        text-transform: uppercase;46        letter-spacing: 2px;47        transition: all 0.3s ease;48    }49    #modeSelection button:hover {50        background: #45a049;51        box-shadow: 0 0 10px #4CAF50;52    }53    #languageSelection {54        position: absolute;55        top: 50%;56        left: 50%;57        transform: translate(-50%, -50%);58        text-align: center;59        background: rgba(0, 0, 0, 0.7);60        padding: 20px;61        border-radius: 10px;62        display: none;63    }64    #languageSelection h2 {65        margin-bottom: 20px;66    }67    #languageSelection button {68        padding: 10px 20px;69        font-size: 18px;70        margin: 0 10px;71        background: #4CAF50;72        color: white;73        border: none;74        cursor: pointer;75        border-radius: 5px;76        text-transform: uppercase;77        letter-spacing: 2px;78        transition: all 0.3s ease;79    }80    #languageSelection button:hover {81        background: #45a049;82        box-shadow: 0 0 10px #4CAF50;83    }84    #startButton {85        padding: 10px 20px;86        font-size: 18px;87        background: #4CAF50;88        color: white;89        border: none;90        cursor: pointer;91        display: none;92        border-radius: 5px;93        text-transform: uppercase;94        letter-spacing: 2px;95        transition: all 0.3s ease;96    }97    #startButton:hover {98        background: #45a049;99        box-shadow: 0 0 10px #4CAF50;100    }101    #scoreDisplay {102        font-size: 24px;103        margin-top: 10px;104        text-shadow: 0 0 5px #00ffff;105    }106    #audioInput {107        margin-bottom: 10px;108    }109    #healthBar {110        width: 200px;111        height: 20px;112        background: #333;113        border: 2px solid #fff;114        margin-top: 10px;115    }116    #healthFill {117        width: 100%;118        height: 100%;119        background: #00ff00;120        transition: width 0.3s ease;121    }122</style>123<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap" rel="stylesheet">124</head>125<body>126<div id="ui">127    <div id="languageSelection" style="display: none;">128        <h2>Select Language / Выберите язык</h2>129        <button id="englishBtn">English</button>130        <button id="russianBtn">Русский</button>131    </div>132    <div id="modeSelection">133        <h2>Выберите режим игры</h2>134        <button id="classicMode">Классика</button>135        <button id="bossMode">С боссом</button>136        <button id="insanityMode">Безумие</button>137    </div>138    <input type="file" id="audioInput" accept="audio/*">139    <button id="startButton">Запустить корабль</button>140    <div id="scoreDisplay">Очки: 0</div>141    <div id="healthBar">142        <div id="healthFill"></div>143    </div>144</div>145<canvas id="gameCanvas"></canvas>146 147<script>148const canvas = document.getElementById('gameCanvas');149const ctx = canvas.getContext('2d');150const audioInput = document.getElementById('audioInput');151const startButton = document.getElementById('startButton');152const scoreDisplay = document.getElementById('scoreDisplay');153 154let audioContext, audioBuffer, analyser, dataArray;155let player, enemies = [], bullets = [], stars = [], planets = [];156let isGameRunning = false;157let score = 0;158let difficulty = 1;159let gameMode = '';160let currentLanguage = 'en';161let isPaused = false;162let audioSource;163let pausedAt = 0;164let startTime = 0;165 166const translations = {167    en: {168        selectMode: "Select game mode",169        classic: "Classic",170        boss: "Boss",171        insanity: "Insanity",172        start: "Launch ship",173        score: "Score",174        gameOver: "GAME OVER",175        finalScore: "Final score",176        playAgain: "Play again",177        paused: "PAUSED"178    },179    ru: {180        selectMode: "Выберите режим игры",181        classic: "Классика",182        boss: "С боссом",183        insanity: "Безумие",184        start: "Запустить корабль",185        score: "Очки",186        gameOver: "ИГРА ОКОНЧЕНА",187        finalScore: "Финальный счет",188        playAgain: "Играть снова",189        paused: "ПАУЗА"190    }191};192 193canvas.width = window.innerWidth;194canvas.height = window.innerHeight;195 196class GameObject {197    constructor(x, y, radius, color) {198        this.x = x;199        this.y = y;200        this.radius = radius;201        this.color = color;202    }203 204    draw() {205        ctx.beginPath();206        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);207        ctx.fillStyle = this.color;208        ctx.fill();209        ctx.closePath();210    }211}212 213class Player extends GameObject {214    constructor(weakArmor = false) {215        super(canvas.width / 2, canvas.height / 2, 20, '#00ffff');216        this.speed = 5;217        this.health = weakArmor ? 50 : 100;218        this.weakArmor = weakArmor;219        this.invincible = false;220    }221 222    draw() {223        ctx.save();224        ctx.translate(this.x, this.y);225        ctx.rotate(Math.atan2(mouseY - this.y, mouseX - this.x));226        227        ctx.beginPath();228        ctx.moveTo(20, 0);229        ctx.lineTo(-10, -10);230        ctx.lineTo(-5, 0);231        ctx.lineTo(-10, 10);232        ctx.closePath();233        ctx.fillStyle = this.color;234        ctx.fill();235 236        ctx.shadowColor = '#00ffff';237        ctx.shadowBlur = 10;238        ctx.strokeStyle = '#ffffff';239        ctx.lineWidth = 2;240        ctx.stroke();241 242        ctx.restore();243    }244 245    move(keys) {246        // WASD, ЦФЫВ (Russian layout), Arrow keys247        if ((keys.w || keys.ц || keys.ArrowUp) && this.y > this.radius) this.y -= this.speed;248        if ((keys.s || keys.ы || keys.ArrowDown) && this.y < canvas.height - this.radius) this.y += this.speed;249        if ((keys.a || keys.ф || keys.ArrowLeft) && this.x > this.radius) this.x -= this.speed;250        if ((keys.d || keys.в || keys.ArrowRight) && this.x < canvas.width - this.radius) this.x += this.speed;251    }252}253 254class Enemy extends GameObject {255    constructor() {256        const side = Math.floor(Math.random() * 4);257        let x, y;258        switch(side) {259            case 0: x = Math.random() * canvas.width; y = 0; break;260            case 1: x = canvas.width; y = Math.random() * canvas.height; break;261            case 2: x = Math.random() * canvas.width; y = canvas.height; break;262            case 3: x = 0; y = Math.random() * canvas.height; break;263        }264        super(x, y, 10, '#ff0000'); 265        this.speed = 2 * difficulty;266    }267 268    draw() {269        ctx.save();270        ctx.translate(this.x, this.y);271        ctx.beginPath();272        for (let i = 0; i < 5; i++) {273            ctx.rotate(Math.PI * 2 / 5);274            ctx.lineTo(0, -this.radius);275            ctx.lineTo(0, -this.radius * 0.5);276        }277        ctx.fillStyle = this.color;278        ctx.fill();279        ctx.closePath();280        ctx.restore();281    }282 283    move(playerX, playerY) {284        const angle = Math.atan2(playerY - this.y, playerX - this.x);285        this.x += Math.cos(angle) * this.speed;286        this.y += Math.sin(angle) * this.speed;287    }288}289 290class Boss extends Enemy {291    constructor() {292        super();293        this.radius = 50; 294        this.color = '#ff00ff';295        this.health = 1000; 296        this.speed = 0.8 * difficulty; 297        this.shootInterval = 1500; 298        this.lastShot = 0;299    }300 301    draw() {302        ctx.save();303        ctx.translate(this.x, this.y);304        ctx.beginPath();305        for (let i = 0; i < 8; i++) {306            ctx.rotate(Math.PI * 2 / 8);307            ctx.lineTo(0, -this.radius);308            ctx.lineTo(0, -this.radius * 0.7);309        }310        ctx.fillStyle = this.color;311        ctx.fill();312        ctx.closePath();313        ctx.restore();314 315        ctx.fillStyle = 'red';316        ctx.fillRect(this.x - 20, this.y - this.radius - 10, 40, 5);317        ctx.fillStyle = 'green';318        ctx.fillRect(this.x - 20, this.y - this.radius - 10, 40 * (this.health / 1000), 5);319    }320 321    shoot(playerX, playerY) {322        const now = Date.now();323        if (now - this.lastShot > this.shootInterval) {324            const angle = Math.atan2(playerY - this.y, playerX - this.x);325            bullets.push(new Bullet(this.x, this.y, this.x + Math.cos(angle) * 1000, this.y + Math.sin(angle) * 1000, true));326            this.lastShot = now;327        }328    }329}330 331class Bullet extends GameObject {332    constructor(x, y, targetX, targetY, isBossBullet = false) {333        super(x, y, 5, isBossBullet ? '#ff00ff' : '#ffff00');334        const angle = Math.atan2(targetY - y, targetX - x);335        this.speed = 10;336        this.dx = Math.cos(angle) * this.speed;337        this.dy = Math.sin(angle) * this.speed;338        this.isBossBullet = isBossBullet;339    }340 341    move() {342        this.x += this.dx;343        this.y += this.dy;344    }345 346    draw() {347        ctx.beginPath();348        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);349        ctx.fillStyle = this.color;350        ctx.fill();351        ctx.closePath();352 353        ctx.shadowColor = '#ffff00';354        ctx.shadowBlur = 10;355        ctx.beginPath();356        ctx.arc(this.x, this.y, this.radius + 2, 0, Math.PI * 2);357        ctx.strokeStyle = '#ffffff';358        ctx.lineWidth = 2;359        ctx.stroke();360    }361}362 363class Star {364    constructor() {365        this.x = Math.random() * canvas.width;366        this.y = Math.random() * canvas.height;367        this.size = Math.random() * 2;368        this.speed = Math.random() * 0.5;369    }370 371    draw() {372        ctx.fillStyle = '#ffffff';373        ctx.fillRect(this.x, this.y, this.size, this.size);374    }375 376    move() {377        this.y += this.speed;378        if (this.y > canvas.height) {379            this.y = 0;380            this.x = Math.random() * canvas.width;381        }382    }383}384 385class Planet {386    constructor() {387        this.x = Math.random() * canvas.width;388        this.y = Math.random() * canvas.height;389        this.radius = Math.random() * 30 + 10;390        this.color = `hsl(${Math.random() * 360}, 50%, 50%)`;391    }392 393    draw() {394        ctx.beginPath();395        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);396        ctx.fillStyle = this.color;397        ctx.fill();398        ctx.closePath();399 400        for (let i = 0; i < 5; i++) {401            const craterRadius = Math.random() * (this.radius / 4);402            const craterX = this.x + (Math.random() - 0.5) * this.radius;403            const craterY = this.y + (Math.random() - 0.5) * this.radius;404            ctx.beginPath();405            ctx.arc(craterX, craterY, craterRadius, 0, Math.PI * 2);406            ctx.fillStyle = `rgba(0, 0, 0, 0.3)`;407            ctx.fill();408            ctx.closePath();409        }410    }411}412 413function applyScreenShake(intensity) {414    const shakeAmount = intensity * 10; 415    ctx.save();416    ctx.translate(417        (Math.random() - 0.5) * shakeAmount,418        (Math.random() - 0.5) * shakeAmount419    );420}421 422function showLanguageSelection() {423    document.getElementById('languageSelection').style.display = 'block';424}425 426function hideLanguageSelection() {427    document.getElementById('languageSelection').style.display = 'none';428}429 430function selectLanguage(lang) {431    currentLanguage = lang;432    hideLanguageSelection();433    updateUILanguage();434    showModeSelection();435}436 437function updateUILanguage() {438    document.getElementById('modeSelection').querySelector('h2').textContent = translations[currentLanguage].selectMode;439    document.getElementById('classicMode').textContent = translations[currentLanguage].classic;440    document.getElementById('bossMode').textContent = translations[currentLanguage].boss;441    document.getElementById('insanityMode').textContent = translations[currentLanguage].insanity;442    startButton.textContent = translations[currentLanguage].start;443}444 445function showModeSelection() {446    document.getElementById('modeSelection').style.display = 'block';447}448 449function hideModeSelection() {450    document.getElementById('modeSelection').style.display = 'none';451}452 453function selectMode(mode) {454    gameMode = mode;455    hideModeSelection();456    startButton.style.display = 'block';457    if (mode === 'insanity') {458        player = new Player(true);459    }460}461 462function resetGame() {463    player = new Player(gameMode === 'insanity');464    enemies = [];465    bullets = [];466    stars = Array(200).fill().map(() => new Star());467    planets = Array(5).fill().map(() => new Planet());468    score = 0;469    difficulty = 1;470    471    if (gameMode === 'insanity') {472        enemies.push(new Boss(), new Boss());473    }474}475 476function initAudio(file) {477    const reader = new FileReader();478    reader.onload = function(e) {479        audioContext.decodeAudioData(e.target.result, function(buffer) {480            audioBuffer = buffer;481            analyser = audioContext.createAnalyser();482            dataArray = new Uint8Array(analyser.frequencyBinCount);483            showLanguageSelection();484        });485    };486    reader.readAsArrayBuffer(file);487}488 489function startGame() {490    if (isGameRunning) return;491    492    isGameRunning = true;493    isPaused = false;494    resetGame();495    496    if (!audioContext || audioContext.state === 'closed') {497        audioContext = new (window.AudioContext || window.webkitAudioContext)();498        analyser = audioContext.createAnalyser();499        dataArray = new Uint8Array(analyser.frequencyBinCount);500    }501    502    audioSource = audioContext.createBufferSource();503    audioSource.buffer = audioBuffer;504    audioSource.connect(analyser);505    analyser.connect(audioContext.destination);506    audioSource.start(0);507    startTime = audioContext.currentTime;508    audioSource.onended = () => {509        isGameRunning = false;510        showGameOver();511    };512    513    animate();514}515 516function showPauseScreen() {517    ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';518    ctx.fillRect(0, 0, canvas.width, canvas.height);519    ctx.fillStyle = '#ffffff';520    ctx.font = '48px Orbitron';521    ctx.textAlign = 'center';522    ctx.fillText(translations[currentLanguage].paused, canvas.width / 2, canvas.height / 2);523}524 525function hidePauseScreen() {526}527 528function togglePause() {529    isPaused = !isPaused;530    if (isPaused) {531        audioSource.stop();532        pausedAt = audioContext.currentTime - startTime;533        showPauseScreen();534    } else {535        startTime = audioContext.currentTime - pausedAt;536        audioSource = audioContext.createBufferSource();537        audioSource.buffer = audioBuffer;538        audioSource.connect(analyser);539        audioSource.start(0, pausedAt);540        hidePauseScreen();541        requestAnimationFrame(animate);542    }543}544 545function animate() {546    if (!isGameRunning || isPaused) return;547 548    analyser.getByteFrequencyData(dataArray);549    let sum = dataArray.reduce((a, b) => a + b, 0);550    let average = sum / dataArray.length;551 552    difficulty = 1 + (average / 128) * 0.5; 553 554    ctx.clearRect(0, 0, canvas.width, canvas.height);555    556    applyScreenShake(average / 255); 557 558    spawnEnemy();559    updateGameObjects();560    drawGameObjects();561 562    ctx.fillStyle = `rgba(255, 255, 255, ${average / 512})`;563    ctx.fillRect(0, 0, canvas.width, canvas.height);564 565    ctx.restore(); 566 567    scoreDisplay.textContent = `${translations[currentLanguage].score}: ${score}`;568 569    requestAnimationFrame(animate);570}571 572const keys = {};573window.addEventListener('keydown', e => {574    keys[e.key.toLowerCase()] = true;575    if (e.code === 'Space' && isGameRunning) {576        e.preventDefault();577        togglePause();578    }579});580window.addEventListener('keyup', e => keys[e.key.toLowerCase()] = false);581 582canvas.addEventListener('mousemove', e => {583    mouseX = e.clientX;584    mouseY = e.clientY;585});586 587canvas.addEventListener('click', e => {588    if (isGameRunning && !isPaused) {589        bullets.push(new Bullet(player.x, player.y, e.clientX, e.clientY));590    }591});592 593document.getElementById('englishBtn').addEventListener('click', () => selectLanguage('en'));594document.getElementById('russianBtn').addEventListener('click', () => selectLanguage('ru'));595 596document.getElementById('classicMode').addEventListener('click', () => selectMode('classic'));597document.getElementById('bossMode').addEventListener('click', () => selectMode('boss'));598document.getElementById('insanityMode').addEventListener('click', () => selectMode('insanity'));599 600audioInput.addEventListener('change', e => {601    const file = e.target.files[0];602    if (file) {603        audioContext = new (window.AudioContext || window.webkitAudioContext)();604        initAudio(file);605    }606});607 608startButton.addEventListener('click', startGame);609 610window.addEventListener('resize', () => {611    canvas.width = window.innerWidth;612    canvas.height = window.innerHeight;613});614 615function spawnEnemy() {616    const spawnRate = gameMode === 'insanity' ? 0.04 : 0.02;617    if (Math.random() < spawnRate * difficulty) {618        enemies.push(new Enemy());619    }620    if (gameMode === 'boss' && enemies.every(e => !(e instanceof Boss))) {621        enemies.push(new Boss());622    }623    if (gameMode === 'insanity' && enemies.filter(e => e instanceof Boss).length < 2) {624        enemies.push(new Boss());625    }626}627 628function updateGameObjects() {629    player.move(keys);630    631    enemies.forEach((enemy, index) => {632        enemy.move(player.x, player.y);633        if (enemy instanceof Boss) {634            enemy.shoot(player.x, player.y);635        }636        if (Math.hypot(enemy.x - player.x, enemy.y - player.y) < player.radius + enemy.radius) {637            if (!player.invincible) {638                player.health -= enemy instanceof Boss ? 20 : 10; 639            }640            if (enemy instanceof Boss) {641                enemy.health -= 5; 642                if (enemy.health <= 0) {643                    createBossExplosion(enemy.x, enemy.y);644                    enemies.splice(index, 1);645                    score += 2000; 646                }647            } else {648                enemies.splice(index, 1);649            }650            if (player.health <= 0) {651                isGameRunning = false;652                showGameOver();653            }654        }655    });656 657    const healthFill = document.getElementById('healthFill');658    healthFill.style.width = `${player.health}%`;659 660    bullets = bullets.filter(bullet => {661        bullet.move();662        if (bullet.isBossBullet) {663            if (Math.hypot(bullet.x - player.x, bullet.y - player.y) < bullet.radius + player.radius) {664                if (!player.invincible) {665                    player.health -= 5;666                }667                return false;668            }669        } else {670            let hitEnemy = false;671            enemies = enemies.filter(enemy => {672                if (Math.hypot(bullet.x - enemy.x, bullet.y - enemy.y) < bullet.radius + enemy.radius) {673                    hitEnemy = true;674                    if (enemy instanceof Boss) {675                        enemy.health -= 2; 676                        if (enemy.health <= 0) {677                            score += 2000;678                            return false;679                        }680                        return true;681                    } else {682                        score += 10;683                        return false;684                    }685                }686                return true;687            });688            if (hitEnemy) return false;689        }690        return bullet.x > 0 && bullet.x < canvas.width && bullet.y > 0 && bullet.y < canvas.height;691    });692 693    stars.forEach(star => star.move());694}695 696function drawBackground() {697    ctx.fillStyle = '#000033';698    ctx.fillRect(0, 0, canvas.width, canvas.height);699    stars.forEach(star => star.draw());700    planets.forEach(planet => planet.draw());701}702 703function drawGameObjects() {704    drawBackground();705    player.draw();706    enemies.forEach(enemy => enemy.draw());707    bullets.forEach(bullet => bullet.draw());708}709 710function showGameOver() {711    if (audioContext && audioContext.state === 'running') {712        audioContext.close();713    }714    ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';715    ctx.fillRect(0, 0, canvas.width, canvas.height);716    717    ctx.fillStyle = '#ffffff';718    ctx.font = '48px Orbitron';719    ctx.textAlign = 'center';720    ctx.fillText(translations[currentLanguage].gameOver, canvas.width / 2, canvas.height / 2 - 50);721    722    ctx.font = '24px Orbitron';723    ctx.fillText(`${translations[currentLanguage].finalScore}: ${score}`, canvas.width / 2, canvas.height / 2 + 50);724    725    const restartButton = document.createElement('button');726    restartButton.textContent = translations[currentLanguage].playAgain;727    restartButton.style.position = 'absolute';728    restartButton.style.left = '50%';729    restartButton.style.top = '60%';730    restartButton.style.transform = 'translate(-50%, -50%)';731    restartButton.style.padding = '10px 20px';732    restartButton.style.fontSize = '18px';733    restartButton.style.backgroundColor = '#4CAF50';734    restartButton.style.color = 'white';735    restartButton.style.border = 'none';736    restartButton.style.borderRadius = '5px';737    restartButton.style.cursor = 'pointer';738    739    restartButton.addEventListener('click', () => {740        document.body.removeChild(restartButton);741        restartGame();742    });743    744    document.body.appendChild(restartButton);745}746 747function restartGame() {748    resetGame();749    startGame();750}751 752function createBossExplosion(x, y) {753    const explosionParticles = [];754    for (let i = 0; i < 100; i++) {755        explosionParticles.push({756            x: x,757            y: y,758            radius: Math.random() * 3 + 1,759            color: `hsl(${Math.random() * 60 + 300}, 100%, 50%)`,760            velocity: {761                x: (Math.random() - 0.5) * 8,762                y: (Math.random() - 0.5) * 8763            },764            alpha: 1765        });766    }767    768    function animateExplosion() {769        ctx.save();770        ctx.globalAlpha = 0.7;771        explosionParticles.forEach((particle, index) => {772            particle.x += particle.velocity.x;773            particle.y += particle.velocity.y;774            particle.alpha -= 0.01;775            776            if (particle.alpha <= 0) {777                explosionParticles.splice(index, 1);778            } else {779                ctx.beginPath();780                ctx.arc(particle.x, particle.y, particle.radius, 0, Math.PI * 2);781                ctx.fillStyle = particle.color;782                ctx.globalAlpha = particle.alpha;783                ctx.fill();784            }785        });786        ctx.restore();787        788        if (explosionParticles.length > 0) {789            requestAnimationFrame(animateExplosion);790        }791    }792    793    animateExplosion();794}795</script>796</body></html>