142 lines
5.2 KiB
JavaScript
142 lines
5.2 KiB
JavaScript
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 = "<strong>Неудача.</strong> Ракета упала обратно на Землю.";
|
||
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 = "<strong>Успешный запуск!</strong> Ракета улетит в космос.";
|
||
resultMessage.className = 'alert alert-success';
|
||
} else {
|
||
resultMessage.innerHTML = "Запуск... Ракета должна упасть.";
|
||
resultMessage.className = 'alert alert-info';
|
||
}
|
||
|
||
if (!animationFrameId) {
|
||
animationFrameId = requestAnimationFrame(animate);
|
||
}
|
||
});
|
||
|
||
// Начальная отрисовка
|
||
resetSimulation();
|
||
}); |