Батч 3, шаг 4. Соединения между телами по классам GMod: phys_ballsocket,
phys_hinge, phys_slider, phys_weld, rope. Плюс add_force (база для
thruster/hover) и set_angular_velocity_target (мотор шарнира).
Главная тонкость переноса: скрипт задаёт якорь в мировых координатах, а
Rapier ждёт локальные в каждом теле. Пересчёт через обратное вращение.
Ошибка не бросает исключение — соединение просто «приклеивается» к другой
точке и уезжает при первом движении.
Четыре вывода из измерений, а не из рассуждений:
1. Констрейн не «стягивает» тела, и это правильно: якорь в мировой точке
совпадает у обоих тел в момент создания, ограничение выполнено сразу и
включается, только когда тела расходятся. Пять первых тестов проверяли
расстояние между телами и падали именно поэтому. Правильный инвариант —
совпадение ТОЧЕК КРЕПЛЕНИЯ под действием силы.
2. Сила в Rapier действует один шаг и сбрасывается: add_force надо вызывать
каждый кадр. Тест с однократной силой измерял не силу, а её отсутствие,
и падал одинаково при 8000 и при 40000.
3. Спящее тело честно сообщает нулевую скорость, поэтому эффект силы
проверяется сравнением с контрольным прогоном, а не по скорости.
4. ПОЛЗУН НЕ УДЕРЖИВАЕТ. Сустав сообщает enabled = true и 5 заблокированных
осей из 6, шар/шарнир/сварка в том же прогоне держат, но ползун пропускает
расхождение по высоте. Тест помечен #[ignore] с причиной: зелёная галочка
на неработающем коде хуже явного отказа. Гипотеза к проверке записана в
docs/PARITY.md B2.6.
Тестов 67 в engine (было 56), 23 набора по воркспейсу, clippy чист.