Avtor2/Space_battle
1
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>