document.addEventListener('DOMContentLoaded', () => { const canvas = document.getElementById('simulationCanvas'); if (!canvas) return; const ctx = canvas.getContext('2d'); const launchButton = document.getElementById('launchButton'); const velocityInput = document.getElementById('velocity'); const resultMessage = document.getElementById('result-message'); // --- Параметры симуляции --- const GRAVITY = 9.8; // Ускорение свободного падения (м/с^2) const ESCAPE_VELOCITY = 11200; // Вторая космическая скорость (м/с) const PIXELS_PER_METER = 0.005; // Масштаб: сколько пикселей в одном метре const TIME_STEP = 2.0; // Шаг времени для симуляции (влияет на скорость анимации) let rocket = {}; let animationFrameId; let initialVelocity = 0; function initializeRocket() { return { x: canvas.width / 2, y: canvas.height - 45, // Позиция на холсте (пиксели) width: 10, height: 25, // Физические свойства y_meters: 0, // Высота в метрах velocityY_meters_per_sec: 0, // Скорость в м/с }; } function drawEarth() { ctx.fillStyle = '#2c5c23'; ctx.beginPath(); ctx.arc(canvas.width / 2, canvas.height + canvas.height - 50, canvas.height, 0, Math.PI, true); ctx.fill(); } function drawRocket() { ctx.fillStyle = '#d0d0d0'; ctx.beginPath(); ctx.moveTo(rocket.x, rocket.y - rocket.height / 2); ctx.lineTo(rocket.x - rocket.width / 2, rocket.y + rocket.height / 2); ctx.lineTo(rocket.x + rocket.width / 2, rocket.y + rocket.height / 2); ctx.closePath(); ctx.fill(); } function resetSimulation() { if (animationFrameId) { cancelAnimationFrame(animationFrameId); animationFrameId = null; } initialVelocity = 0; rocket = initializeRocket(); resultMessage.innerHTML = ' '; resultMessage.className = 'alert alert-secondary'; clearCanvas(); drawEarth(); drawRocket(); } function clearCanvas() { ctx.clearRect(0, 0, canvas.width, canvas.height); } function animate() { // 1. Обновляем физику (пошаговая симуляция) // Уменьшаем скорость под действием гравитации rocket.velocityY_meters_per_sec -= GRAVITY * TIME_STEP; // Обновляем высоту на основе новой скорости rocket.y_meters += rocket.velocityY_meters_per_sec * TIME_STEP; // 2. Обновляем позицию для отрисовки const groundY = canvas.height - 45; rocket.y = groundY - (rocket.y_meters * PIXELS_PER_METER); // 3. Отрисовываем сцену clearCanvas(); drawEarth(); drawRocket(); // 4. Проверяем условия завершения const hasEscaped = initialVelocity >= ESCAPE_VELOCITY && rocket.y < -rocket.height; const hasCrashed = rocket.y_meters <= 0 && initialVelocity < ESCAPE_VELOCITY; if (hasEscaped) { cancelAnimationFrame(animationFrameId); animationFrameId = null; return; } if (hasCrashed) { // Фиксируем ракету на земле rocket.y_meters = 0; rocket.y = groundY; clearCanvas(); drawEarth(); drawRocket(); resultMessage.innerHTML = "Неудача. Ракета упала обратно на Землю."; resultMessage.className = 'alert alert-danger'; cancelAnimationFrame(animationFrameId); animationFrameId = null; return; } // Продолжаем анимацию animationFrameId = requestAnimationFrame(animate); } launchButton.addEventListener('click', () => { const velocityValue = parseFloat(velocityInput.value); if (isNaN(velocityValue) || velocityValue < 0) { resultMessage.innerHTML = 'Пожалуйста, введите положительное число.'; resultMessage.className = 'alert alert-warning'; return; } resetSimulation(); initialVelocity = velocityValue; rocket.velocityY_meters_per_sec = initialVelocity; if (initialVelocity >= ESCAPE_VELOCITY) { resultMessage.innerHTML = "Успешный запуск! Ракета улетит в космос."; resultMessage.className = 'alert alert-success'; } else { resultMessage.innerHTML = "Запуск... Ракета должна упасть."; resultMessage.className = 'alert alert-info'; } if (!animationFrameId) { animationFrameId = requestAnimationFrame(animate); } }); // Начальная отрисовка resetSimulation(); });