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');153let audioContext, audioBuffer, analyser, dataArray;154let player, enemies = [], bullets = [], stars = [], planets = [];155let isGameRunning = false;156let score = 0;157let difficulty = 1;158let gameMode = '';159let currentLanguage = 'en';160let isPaused = false;161let audioSource;162let pausedAt = 0;163let startTime = 0;164const translations = {165 en: {166 selectMode: "Select game mode",167 classic: "Classic",168 boss: "Boss",169 insanity: "Insanity",170 start: "Launch ship",171 score: "Score",172 gameOver: "GAME OVER",173 finalScore: "Final score",174 playAgain: "Play again",175 paused: "PAUSED"176 },177 ru: {178 selectMode: "Выберите режим игры",179 classic: "Классика",180 boss: "С боссом",181 insanity: "Безумие",182 start: "Запустить корабль",183 score: "Очки",184 gameOver: "ИГРА ОКОНЧЕНА",185 finalScore: "Финальный счет",186 playAgain: "Играть снова",187 paused: "ПАУЗА"188 }189};190canvas.width = window.innerWidth;191canvas.height = window.innerHeight;192class GameObject {193 constructor(x, y, radius, color) {194 this.x = x;195 this.y = y;196 this.radius = radius;197 this.color = color;198 }199 draw() {200 ctx.beginPath();201 ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);202 ctx.fillStyle = this.color;203 ctx.fill();204 ctx.closePath();205 }206}207class Player extends GameObject {208 constructor(weakArmor = false) {209 super(canvas.width / 2, canvas.height / 2, 20, '#00ffff');210 this.speed = 5;211 this.health = weakArmor ? 50 : 100;212 this.weakArmor = weakArmor;213 this.invincible = false;214 }215 draw() {216 ctx.save();217 ctx.translate(this.x, this.y);218 ctx.rotate(Math.atan2(mouseY - this.y, mouseX - this.x));219 220 ctx.beginPath();221 ctx.moveTo(20, 0);222 ctx.lineTo(-10, -10);223 ctx.lineTo(-5, 0);224 ctx.lineTo(-10, 10);225 ctx.closePath();226 ctx.fillStyle = this.color;227 ctx.fill();228 ctx.shadowColor = '#00ffff';229 ctx.shadowBlur = 10;230 ctx.strokeStyle = '#ffffff';231 ctx.lineWidth = 2;232 ctx.stroke();233 ctx.restore();234 }235 move(keys) {236 // WASD, ЦФЫВ (Russian layout), Arrow keys237 if ((keys.w || keys.ц || keys.ArrowUp) && this.y > this.radius) this.y -= this.speed;238 if ((keys.s || keys.ы || keys.ArrowDown) && this.y < canvas.height - this.radius) this.y += this.speed;239 if ((keys.a || keys.ф || keys.ArrowLeft) && this.x > this.radius) this.x -= this.speed;240 if ((keys.d || keys.в || keys.ArrowRight) && this.x < canvas.width - this.radius) this.x += this.speed;241 }242}243class Enemy extends GameObject {244 constructor() {245 const side = Math.floor(Math.random() * 4);246 let x, y;247 switch(side) {248 case 0: x = Math.random() * canvas.width; y = 0; break;249 case 1: x = canvas.width; y = Math.random() * canvas.height; break;250 case 2: x = Math.random() * canvas.width; y = canvas.height; break;251 case 3: x = 0; y = Math.random() * canvas.height; break;252 }253 super(x, y, 10, '#ff0000'); 254 this.speed = 2 * difficulty;255 }256 draw() {257 ctx.save();258 ctx.translate(this.x, this.y);259 ctx.beginPath();260 for (let i = 0; i < 5; i++) {261 ctx.rotate(Math.PI * 2 / 5);262 ctx.lineTo(0, -this.radius);263 ctx.lineTo(0, -this.radius * 0.5);264 }265 ctx.fillStyle = this.color;266 ctx.fill();267 ctx.closePath();268 ctx.restore();269 }270 move(playerX, playerY) {271 const angle = Math.atan2(playerY - this.y, playerX - this.x);272 this.x += Math.cos(angle) * this.speed;273 this.y += Math.sin(angle) * this.speed;274 }275}276class Boss extends Enemy {277 constructor() {278 super();279 this.radius = 50; 280 this.color = '#ff00ff';281 this.health = 1000; 282 this.speed = 0.8 * difficulty; 283 this.shootInterval = 1500; 284 this.lastShot = 0;285 }286 draw() {287 ctx.save();288 ctx.translate(this.x, this.y);289 ctx.beginPath();290 for (let i = 0; i < 8; i++) {291 ctx.rotate(Math.PI * 2 / 8);292 ctx.lineTo(0, -this.radius);293 ctx.lineTo(0, -this.radius * 0.7);294 }295 ctx.fillStyle = this.color;296 ctx.fill();297 ctx.closePath();298 ctx.restore();299 ctx.fillStyle = 'red';300 ctx.fillRect(this.x - 20, this.y - this.radius - 10, 40, 5);301 ctx.fillStyle = 'green';302 ctx.fillRect(this.x - 20, this.y - this.radius - 10, 40 * (this.health / 1000), 5);303 }304 shoot(playerX, playerY) {305 const now = Date.now();306 if (now - this.lastShot > this.shootInterval) {307 const angle = Math.atan2(playerY - this.y, playerX - this.x);308 bullets.push(new Bullet(this.x, this.y, this.x + Math.cos(angle) * 1000, this.y + Math.sin(angle) * 1000, true));309 this.lastShot = now;310 }311 }312}313class Bullet extends GameObject {314 constructor(x, y, targetX, targetY, isBossBullet = false) {315 super(x, y, 5, isBossBullet ? '#ff00ff' : '#ffff00');316 const angle = Math.atan2(targetY - y, targetX - x);317 this.speed = 10;318 this.dx = Math.cos(angle) * this.speed;319 this.dy = Math.sin(angle) * this.speed;320 this.isBossBullet = isBossBullet;321 }322 move() {323 this.x += this.dx;324 this.y += this.dy;325 }326 draw() {327 ctx.beginPath();328 ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);329 ctx.fillStyle = this.color;330 ctx.fill();331 ctx.closePath();332 ctx.shadowColor = '#ffff00';333 ctx.shadowBlur = 10;334 ctx.beginPath();335 ctx.arc(this.x, this.y, this.radius + 2, 0, Math.PI * 2);336 ctx.strokeStyle = '#ffffff';337 ctx.lineWidth = 2;338 ctx.stroke();339 }340}341class Star {342 constructor() {343 this.x = Math.random() * canvas.width;344 this.y = Math.random() * canvas.height;345 this.size = Math.random() * 2;346 this.speed = Math.random() * 0.5;347 }348 draw() {349 ctx.fillStyle = '#ffffff';350 ctx.fillRect(this.x, this.y, this.size, this.size);351 }352 move() {353 this.y += this.speed;354 if (this.y > canvas.height) {355 this.y = 0;356 this.x = Math.random() * canvas.width;357 }358 }359}360class Planet {361 constructor() {362 this.x = Math.random() * canvas.width;363 this.y = Math.random() * canvas.height;364 this.radius = Math.random() * 30 + 10;365 this.color = `hsl(${Math.random() * 360}, 50%, 50%)`;366 }367 draw() {368 ctx.beginPath();369 ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);370 ctx.fillStyle = this.color;371 ctx.fill();372 ctx.closePath();373 for (let i = 0; i < 5; i++) {374 const craterRadius = Math.random() * (this.radius / 4);375 const craterX = this.x + (Math.random() - 0.5) * this.radius;376 const craterY = this.y + (Math.random() - 0.5) * this.radius;377 ctx.beginPath();378 ctx.arc(craterX, craterY, craterRadius, 0, Math.PI * 2);379 ctx.fillStyle = `rgba(0, 0, 0, 0.3)`;380 ctx.fill();381 ctx.closePath();382 }383 }384}385function applyScreenShake(intensity) {386 const shakeAmount = intensity * 10; 387 ctx.save();388 ctx.translate(389 (Math.random() - 0.5) * shakeAmount,390 (Math.random() - 0.5) * shakeAmount391 );392}393function showLanguageSelection() {394 document.getElementById('languageSelection').style.display = 'block';395}396function hideLanguageSelection() {397 document.getElementById('languageSelection').style.display = 'none';398}399function selectLanguage(lang) {400 currentLanguage = lang;401 hideLanguageSelection();402 updateUILanguage();403 showModeSelection();404}405function updateUILanguage() {406 document.getElementById('modeSelection').querySelector('h2').textContent = translations[currentLanguage].selectMode;407 document.getElementById('classicMode').textContent = translations[currentLanguage].classic;408 document.getElementById('bossMode').textContent = translations[currentLanguage].boss;409 document.getElementById('insanityMode').textContent = translations[currentLanguage].insanity;410 startButton.textContent = translations[currentLanguage].start;411}412function showModeSelection() {413 document.getElementById('modeSelection').style.display = 'block';414}415function hideModeSelection() {416 document.getElementById('modeSelection').style.display = 'none';417}418function selectMode(mode) {419 gameMode = mode;420 hideModeSelection();421 startButton.style.display = 'block';422 if (mode === 'insanity') {423 player = new Player(true);424 }425}426function resetGame() {427 player = new Player(gameMode === 'insanity');428 enemies = [];429 bullets = [];430 stars = Array(200).fill().map(() => new Star());431 planets = Array(5).fill().map(() => new Planet());432 score = 0;433 difficulty = 1;434 435 if (gameMode === 'insanity') {436 enemies.push(new Boss(), new Boss());437 }438}439function initAudio(file) {440 const reader = new FileReader();441 reader.onload = function(e) {442 audioContext.decodeAudioData(e.target.result, function(buffer) {443 audioBuffer = buffer;444 analyser = audioContext.createAnalyser();445 dataArray = new Uint8Array(analyser.frequencyBinCount);446 showLanguageSelection();447 });448 };449 reader.readAsArrayBuffer(file);450}451function startGame() {452 if (isGameRunning) return;453 454 isGameRunning = true;455 isPaused = false;456 resetGame();457 458 if (!audioContext || audioContext.state === 'closed') {459 audioContext = new (window.AudioContext || window.webkitAudioContext)();460 analyser = audioContext.createAnalyser();461 dataArray = new Uint8Array(analyser.frequencyBinCount);462 }463 464 audioSource = audioContext.createBufferSource();465 audioSource.buffer = audioBuffer;466 audioSource.connect(analyser);467 analyser.connect(audioContext.destination);468 audioSource.start(0);469 startTime = audioContext.currentTime;470 audioSource.onended = () => {471 isGameRunning = false;472 showGameOver();473 };474 475 animate();476}477function showPauseScreen() {478 ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';479 ctx.fillRect(0, 0, canvas.width, canvas.height);480 ctx.fillStyle = '#ffffff';481 ctx.font = '48px Orbitron';482 ctx.textAlign = 'center';483 ctx.fillText(translations[currentLanguage].paused, canvas.width / 2, canvas.height / 2);484}485function hidePauseScreen() {486}487function togglePause() {488 isPaused = !isPaused;489 if (isPaused) {490 audioSource.stop();491 pausedAt = audioContext.currentTime - startTime;492 showPauseScreen();493 } else {494 startTime = audioContext.currentTime - pausedAt;495 audioSource = audioContext.createBufferSource();496 audioSource.buffer = audioBuffer;497 audioSource.connect(analyser);498 audioSource.start(0, pausedAt);499 hidePauseScreen();500 requestAnimationFrame(animate);501 }502}503function animate() {504 if (!isGameRunning || isPaused) return;505 analyser.getByteFrequencyData(dataArray);506 let sum = dataArray.reduce((a, b) => a + b, 0);507 let average = sum / dataArray.length;508 difficulty = 1 + (average / 128) * 0.5; 509 ctx.clearRect(0, 0, canvas.width, canvas.height);510 511 applyScreenShake(average / 255); 512 spawnEnemy();513 updateGameObjects();514 drawGameObjects();515 ctx.fillStyle = `rgba(255, 255, 255, ${average / 512})`;516 ctx.fillRect(0, 0, canvas.width, canvas.height);517 ctx.restore(); 518 scoreDisplay.textContent = `${translations[currentLanguage].score}: ${score}`;519 requestAnimationFrame(animate);520}521const keys = {};522window.addEventListener('keydown', e => {523 keys[e.key.toLowerCase()] = true;524 if (e.code === 'Space' && isGameRunning) {525 e.preventDefault();526 togglePause();527 }528});529window.addEventListener('keyup', e => keys[e.key.toLowerCase()] = false);530canvas.addEventListener('mousemove', e => {531 mouseX = e.clientX;532 mouseY = e.clientY;533});534canvas.addEventListener('click', e => {535 if (isGameRunning && !isPaused) {536 bullets.push(new Bullet(player.x, player.y, e.clientX, e.clientY));537 }538});539document.getElementById('englishBtn').addEventListener('click', () => selectLanguage('en'));540document.getElementById('russianBtn').addEventListener('click', () => selectLanguage('ru'));541document.getElementById('classicMode').addEventListener('click', () => selectMode('classic'));542document.getElementById('bossMode').addEventListener('click', () => selectMode('boss'));543document.getElementById('insanityMode').addEventListener('click', () => selectMode('insanity'));544audioInput.addEventListener('change', e => {545 const file = e.target.files[0];546 if (file) {547 audioContext = new (window.AudioContext || window.webkitAudioContext)();548 initAudio(file);549 }550});551startButton.addEventListener('click', startGame);552window.addEventListener('resize', () => {553 canvas.width = window.innerWidth;554 canvas.height = window.innerHeight;555});556function spawnEnemy() {557 const spawnRate = gameMode === 'insanity' ? 0.04 : 0.02;558 if (Math.random() < spawnRate * difficulty) {559 enemies.push(new Enemy());560 }561 if (gameMode === 'boss' && enemies.every(e => !(e instanceof Boss))) {562 enemies.push(new Boss());563 }564 if (gameMode === 'insanity' && enemies.filter(e => e instanceof Boss).length < 2) {565 enemies.push(new Boss());566 }567}568function updateGameObjects() {569 player.move(keys);570 571 enemies.forEach((enemy, index) => {572 enemy.move(player.x, player.y);573 if (enemy instanceof Boss) {574 enemy.shoot(player.x, player.y);575 }576 if (Math.hypot(enemy.x - player.x, enemy.y - player.y) < player.radius + enemy.radius) {577 if (!player.invincible) {578 player.health -= enemy instanceof Boss ? 20 : 10; 579 }580 if (enemy instanceof Boss) {581 enemy.health -= 5; 582 if (enemy.health <= 0) {583 createBossExplosion(enemy.x, enemy.y);584 enemies.splice(index, 1);585 score += 2000; 586 }587 } else {588 enemies.splice(index, 1);589 }590 if (player.health <= 0) {591 isGameRunning = false;592 showGameOver();593 }594 }595 });596 const healthFill = document.getElementById('healthFill');597 healthFill.style.width = `${player.health}%`;598 bullets = bullets.filter(bullet => {599 bullet.move();600 if (bullet.isBossBullet) {601 if (Math.hypot(bullet.x - player.x, bullet.y - player.y) < bullet.radius + player.radius) {602 if (!player.invincible) {603 player.health -= 5;604 }605 return false;606 }607 } else {608 let hitEnemy = false;609 enemies = enemies.filter(enemy => {610 if (Math.hypot(bullet.x - enemy.x, bullet.y - enemy.y) < bullet.radius + enemy.radius) {611 hitEnemy = true;612 if (enemy instanceof Boss) {613 enemy.health -= 2; 614 if (enemy.health <= 0) {615 score += 2000;616 return false;617 }618 return true;619 } else {620 score += 10;621 return false;622 }623 }624 return true;625 });626 if (hitEnemy) return false;627 }628 return bullet.x > 0 && bullet.x < canvas.width && bullet.y > 0 && bullet.y < canvas.height;629 });630 stars.forEach(star => star.move());631}632function drawBackground() {633 ctx.fillStyle = '#000033';634 ctx.fillRect(0, 0, canvas.width, canvas.height);635 stars.forEach(star => star.draw());636 planets.forEach(planet => planet.draw());637}638function drawGameObjects() {639 drawBackground();640 player.draw();641 enemies.forEach(enemy => enemy.draw());642 bullets.forEach(bullet => bullet.draw());643}644function showGameOver() {645 if (audioContext && audioContext.state === 'running') {646 audioContext.close();647 }648 ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';649 ctx.fillRect(0, 0, canvas.width, canvas.height);650 651 ctx.fillStyle = '#ffffff';652 ctx.font = '48px Orbitron';653 ctx.textAlign = 'center';654 ctx.fillText(translations[currentLanguage].gameOver, canvas.width / 2, canvas.height / 2 - 50);655 656 ctx.font = '24px Orbitron';657 ctx.fillText(`${translations[currentLanguage].finalScore}: ${score}`, canvas.width / 2, canvas.height / 2 + 50);658 659 const restartButton = document.createElement('button');660 restartButton.textContent = translations[currentLanguage].playAgain;661 restartButton.style.position = 'absolute';662 restartButton.style.left = '50%';663 restartButton.style.top = '60%';664 restartButton.style.transform = 'translate(-50%, -50%)';665 restartButton.style.padding = '10px 20px';666 restartButton.style.fontSize = '18px';667 restartButton.style.backgroundColor = '#4CAF50';668 restartButton.style.color = 'white';669 restartButton.style.border = 'none';670 restartButton.style.borderRadius = '5px';671 restartButton.style.cursor = 'pointer';672 673 restartButton.addEventListener('click', () => {674 document.body.removeChild(restartButton);675 restartGame();676 });677 678 document.body.appendChild(restartButton);679}680function restartGame() {681 resetGame();682 startGame();683}684function createBossExplosion(x, y) {685 const explosionParticles = [];686 for (let i = 0; i < 100; i++) {687 explosionParticles.push({688 x: x,689 y: y,690 radius: Math.random() * 3 + 1,691 color: `hsl(${Math.random() * 60 + 300}, 100%, 50%)`,692 velocity: {693 x: (Math.random() - 0.5) * 8,694 y: (Math.random() - 0.5) * 8695 },696 alpha: 1697 });698 }699 700 function animateExplosion() {701 ctx.save();702 ctx.globalAlpha = 0.7;703 explosionParticles.forEach((particle, index) => {704 particle.x += particle.velocity.x;705 particle.y += particle.velocity.y;706 particle.alpha -= 0.01;707 708 if (particle.alpha <= 0) {709 explosionParticles.splice(index, 1);710 } else {711 ctx.beginPath();712 ctx.arc(particle.x, particle.y, particle.radius, 0, Math.PI * 2);713 ctx.fillStyle = particle.color;714 ctx.globalAlpha = particle.alpha;715 ctx.fill();716 }717 });718 ctx.restore();719 720 if (explosionParticles.length > 0) {721 requestAnimationFrame(animateExplosion);722 }723 }724 725 animateExplosion();726}727</script>728</body></html>