From 866e0c05b729e7cb5fa3c0e0938184dd82d58d4f Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Wed, 19 Nov 2025 15:16:54 +0000 Subject: [PATCH] step --- assets/js/simulator.js | 154 ++++++++++++++++++++++++++--------------- simulator.php | 14 +++- 2 files changed, 109 insertions(+), 59 deletions(-) diff --git a/assets/js/simulator.js b/assets/js/simulator.js index ea67180..96e88cf 100644 --- a/assets/js/simulator.js +++ b/assets/js/simulator.js @@ -4,28 +4,39 @@ document.addEventListener('DOMContentLoaded', () => { const ctx = canvas.getContext('2d'); const launchButton = document.getElementById('launchButton'); - const velocityInput = document.getElementById('velocity'); + const accelerationInput = document.getElementById('acceleration'); + const burnTimeInput = document.getElementById('burnTime'); + const angleInput = document.getElementById('angle'); 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; // Шаг времени для симуляции (влияет на скорость анимации) + const GRAVITY = 9.8; + const PIXELS_PER_METER = 0.01; + const TIME_STEP = 1.0; let rocket = {}; - let animationFrameId; - let initialVelocity = 0; + let simulationState = {}; + + function initializeState() { + return { + animationFrameId: null, + elapsedTime: 0, + acceleration: 0, + burnTime: 0, + angleRad: 0, + }; + } function initializeRocket() { return { - x: canvas.width / 2, - y: canvas.height - 45, // Позиция на холсте (пиксели) + x: 30, + y: canvas.height - 45, width: 10, height: 25, - // Физические свойства - y_meters: 0, // Высота в метрах - velocityY_meters_per_sec: 0, // Скорость в м/с + x_meters: 0, + y_meters: 0, + vx: 0, // Скорость по X в м/с + vy: 0, // Скорость по Y в м/с }; } @@ -37,21 +48,48 @@ document.addEventListener('DOMContentLoaded', () => { } function drawRocket() { + ctx.save(); + ctx.translate(rocket.x, rocket.y); + + // Угол поворота ракеты зависит от вектора скорости + // Но до старта (скорость 0) она стоит вертикально + const angle = (rocket.vx === 0 && rocket.vy === 0) + ? -Math.PI / 2 + : Math.atan2(rocket.vy, rocket.vx); + + // Поворачиваем ракету. Наша модель "смотрит" вправо, поэтому доп. вращение не нужно. + ctx.rotate(angle); + + // Рисуем пламя, если двигатель работает + if (simulationState.elapsedTime > 0 && simulationState.elapsedTime <= simulationState.burnTime) { + ctx.fillStyle = `rgba(255, ${Math.random() * 150 + 100}, 0, 0.8)`; + ctx.beginPath(); + const flameLength = rocket.height * (1.5 + Math.random() * 0.5); + ctx.moveTo(-rocket.width / 2, 0); + ctx.lineTo(-rocket.width / 2 - flameLength, rocket.width / 2); + ctx.lineTo(-rocket.width / 2 - flameLength, -rocket.width / 2); + ctx.closePath(); + ctx.fill(); + } + + // Корпус ракеты (перерисовываем, чтобы был поверх пламени) + // Модель ракеты теперь "смотрит" вправо (по оси X) 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.moveTo(rocket.height / 2, 0); + ctx.lineTo(-rocket.height / 2, -rocket.width / 2); + ctx.lineTo(-rocket.height / 2, rocket.width / 2); ctx.closePath(); ctx.fill(); + + ctx.restore(); } function resetSimulation() { - if (animationFrameId) { - cancelAnimationFrame(animationFrameId); - animationFrameId = null; + if (simulationState.animationFrameId) { + cancelAnimationFrame(simulationState.animationFrameId); } - initialVelocity = 0; + simulationState = initializeState(); rocket = initializeRocket(); resultMessage.innerHTML = ' '; resultMessage.className = 'alert alert-secondary'; @@ -65,14 +103,27 @@ document.addEventListener('DOMContentLoaded', () => { } function animate() { - // 1. Обновляем физику (пошаговая симуляция) - // Уменьшаем скорость под действием гравитации - rocket.velocityY_meters_per_sec -= GRAVITY * TIME_STEP; - // Обновляем высоту на основе новой скорости - rocket.y_meters += rocket.velocityY_meters_per_sec * TIME_STEP; + simulationState.elapsedTime += TIME_STEP; - // 2. Обновляем позицию для отрисовки + // 1. Обновляем физику + // Если двигатель работает, применяем ускорение + if (simulationState.elapsedTime <= simulationState.burnTime) { + const currentAccelerationX = simulationState.acceleration * Math.cos(simulationState.angleRad); + const currentAccelerationY = simulationState.acceleration * Math.sin(simulationState.angleRad); + rocket.vx += currentAccelerationX * TIME_STEP; + rocket.vy += currentAccelerationY * TIME_STEP; + } + + // Всегда применяем гравитацию (она действует на ось Y) + rocket.vy -= GRAVITY * TIME_STEP; + + // Обновляем позицию в метрах + rocket.x_meters += rocket.vx * TIME_STEP; + rocket.y_meters += rocket.vy * TIME_STEP; + + // 2. Обновляем позицию для отрисовки в пикселях const groundY = canvas.height - 45; + rocket.x = 30 + (rocket.x_meters * PIXELS_PER_METER); rocket.y = groundY - (rocket.y_meters * PIXELS_PER_METER); // 3. Отрисовываем сцену @@ -81,62 +132,53 @@ document.addEventListener('DOMContentLoaded', () => { drawRocket(); // 4. Проверяем условия завершения - const hasEscaped = initialVelocity >= ESCAPE_VELOCITY && rocket.y < -rocket.height; - const hasCrashed = rocket.y_meters <= 0 && initialVelocity < ESCAPE_VELOCITY; + const hasCrashed = rocket.y_meters < 0 && simulationState.elapsedTime > 1; + const outOfBounds = rocket.x > canvas.width + rocket.height; - if (hasEscaped) { - cancelAnimationFrame(animationFrameId); - animationFrameId = null; - return; - } - - if (hasCrashed) { - // Фиксируем ракету на земле + if (hasCrashed || outOfBounds) { rocket.y_meters = 0; rocket.y = groundY; clearCanvas(); drawEarth(); drawRocket(); - resultMessage.innerHTML = "Неудача. Ракета упала обратно на Землю."; + resultMessage.innerHTML = outOfBounds + ? "Неудача. Ракета улетела за пределы видимости." + : "Неудача. Ракета упала обратно на Землю."; resultMessage.className = 'alert alert-danger'; - - cancelAnimationFrame(animationFrameId); - animationFrameId = null; + + cancelAnimationFrame(simulationState.animationFrameId); + simulationState.animationFrameId = null; return; } - // Продолжаем анимацию - animationFrameId = requestAnimationFrame(animate); + simulationState.animationFrameId = requestAnimationFrame(animate); } launchButton.addEventListener('click', () => { - const velocityValue = parseFloat(velocityInput.value); + const accelValue = parseFloat(accelerationInput.value); + const burnTimeValue = parseFloat(burnTimeInput.value); + const angleValue = parseFloat(angleInput.value); - if (isNaN(velocityValue) || velocityValue < 0) { - resultMessage.innerHTML = 'Пожалуйста, введите положительное число.'; + if (isNaN(accelValue) || isNaN(burnTimeValue) || isNaN(angleValue) || accelValue <= 0 || burnTimeValue <= 0 || angleValue < 0 || angleValue > 90) { + resultMessage.innerHTML = 'Пожалуйста, введите корректные значения (ускорение > 0, время > 0, угол 0-90).'; resultMessage.className = 'alert alert-warning'; return; } resetSimulation(); - initialVelocity = velocityValue; - rocket.velocityY_meters_per_sec = initialVelocity; + simulationState.acceleration = accelValue; + simulationState.burnTime = burnTimeValue; + simulationState.angleRad = angleValue * (Math.PI / 180); - if (initialVelocity >= ESCAPE_VELOCITY) { - resultMessage.innerHTML = "Успешный запуск! Ракета улетит в космос."; - resultMessage.className = 'alert alert-success'; - } else { - resultMessage.innerHTML = "Запуск... Ракета должна упасть."; - resultMessage.className = 'alert alert-info'; - } + resultMessage.innerHTML = "Запуск..."; + resultMessage.className = 'alert alert-info'; - if (!animationFrameId) { - animationFrameId = requestAnimationFrame(animate); + if (!simulationState.animationFrameId) { + simulationState.animationFrameId = requestAnimationFrame(animate); } }); - // Начальная отрисовка resetSimulation(); }); \ No newline at end of file diff --git a/simulator.php b/simulator.php index d8f4b1f..82af42a 100644 --- a/simulator.php +++ b/simulator.php @@ -51,7 +51,7 @@

Симулятор Запуска Ракеты

-

Введите начальную скорость ракеты в метрах в секунду (м/с).
Чтобы преодолеть притяжение Земли, нужна скорость не менее 11 200 м/с.

+

Задайте параметры запуска: ускорение, время работы двигателя и угол.
Наблюдайте, как ракета набирает скорость и летит по траектории.

@@ -60,8 +60,16 @@
- - + + +
+
+ + +
+
+ +