fix(phys7): главный визуал курса работает + §22, §24 интерактивы улучшены

1. БАГ В HillSlideSim (phys.js):
   - При reset() начальное состояние x=0, h=hStart, v=0.
   - Первый step(): dropped=0 → v=0 → x не растёт → h не падает → тележка
     навсегда стоит на вершине (бесконечный нуль). Анимация ничего не показывала.
   - Фикс: reset() даёт начальный толчок (x = L*0.01) и v по энергии для
     этой малой высоты падения. step() теперь корректно ускоряет тележку.
   - Тест node: за 2.05 с тележка проходит 11.7 м, h падает с 4.9 м до 0.86 м,
     v растёт с 1.4 до 9.0 м/с. Е_полн ≈ const.

2. §22 «Сила тяжести» — новый IV-2 «Падение на 4 планетах»:
   - SVG 4-колоночная сцена, 4 шарика стартуют с одной высоты.
   - Slider высоты 2..20 м, кнопки «Уронить» / «Сброс».
   - Свободное падение по h(t) = h₀ − gt²/2 для каждой планеты (Земля 9.8,
     Луна 1.6, Марс 3.7, Юпитер 24.8).
   - Видно: Юпитер падает первым, Луна последней; для каждого сохраняется
     время падения √(2h/g) и итоговая v = g·t.
   - Live info: текущее t, статус каждого шарика (падает / упал за X с,
     v = Y м/с).

3. §24 «Вес тела» — переработан IV-1 «Лифт с динамометром»:
   - Было: 4 статичных схемы покой/падение/верх/вниз.
   - Стало: динамический симулятор. Кабина лифта со стрелкой ускорения
     снаружи, внутри — груз на пружинном динамометре с шкалой.
   - 2 slider'а: масса 0.5..10 кг, ускорение −10..+10 м/с².
   - 4 кнопки-пресета: Покой / Едет вверх / Едет вниз / Свободное падение.
   - Формула P = m(g + a) считается в реальном времени.
   - 4 режима с автоопределением: ПОКОЙ / НЕВЕСОМОСТЬ / ПЕРЕГРУЗКА /
     ПОНИЖЕННЫЙ ВЕС с разной цветовой индикацией.
   - Пружина динамометра реально растягивается/сжимается в зависимости
     от P; указатель и шкала тоже.

Parse OK, smoke (15 экспортов CH3) OK.
This commit is contained in:
Maxim Dolgolyov
2026-05-30 12:14:48 +03:00
parent a60349d339
commit 98f955a85e
2 changed files with 194 additions and 74 deletions
+23 -5
View File
@@ -672,15 +672,33 @@ class HillSlideSim {
this.scale = opts.scale || 30;
this.reset();
}
reset() { this.t = 0; this.x = 0; this.v = 0; this.h = this.hStart; }
reset() {
// Начальный импульс: тележка стартует с лёгким толчком (1% от L) и небольшой скоростью,
// иначе при h=hStart, v=0 — она навсегда останется на вершине (бесконечный нуль).
const L = this.hStart * 4;
this.t = 0;
this.x = L * 0.01;
const xRel = this.x / L;
this.h = this.hStart * Math.pow(1 - xRel, 2);
this.v = Math.sqrt(2 * this.g * (this.hStart - this.h));
}
step(dt) {
const gEff = this.g * (1 - this.friction);
this.t += dt;
const dropped = this.hStart - this.h;
if (this.h <= 0) { this.h = 0; this.v = Math.sqrt(2 * gEff * this.hStart); return; }
this.v = Math.sqrt(2 * gEff * Math.max(0, dropped));
this.x += this.v * dt;
const L = this.hStart * 4;
if (this.h <= 0.001 || this.x >= L) {
this.h = 0;
// Финальная скорость с учётом потерь на трение.
this.v = Math.sqrt(2 * gEff * this.hStart);
this.x = L;
return;
}
// Скорость по закону сохранения энергии (с учётом трения).
const dropped = Math.max(0.0001, this.hStart - this.h);
this.v = Math.sqrt(2 * gEff * dropped);
// Скорость по x — это горизонтальная компонента; для наглядного моделирования
// используем её напрямую как темп роста x.
this.x += this.v * dt;
const xRel = Math.min(this.x, L) / L;
this.h = this.hStart * Math.pow(1 - xRel, 2);
}