From 4a8e75635ee82ec166e1bad22d50b208daa48bd6 Mon Sep 17 00:00:00 2001 From: Niko Marmeladkov Date: Sat, 24 Oct 2026 22:07:29 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A4=D0=B8=D0=B7=D0=B8=D0=BA=D0=B0:=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=B4=D0=BD=D1=8F=D1=82=20=D0=BF=D1=80=D0=B5=D0=B4=D0=B5?= =?UTF-8?q?=D0=BB=20=D1=81=D0=BA=D0=BE=D1=80=D0=BE=D1=81=D1=82=D0=B8=20Rap?= =?UTF-8?q?ier=20=E2=80=94=20=D1=84=D0=B8=D0=B7=D0=B3=D0=B0=D0=BD=20=D0=B1?= =?UTF-8?q?=D0=BE=D0=BB=D1=8C=D1=88=D0=B5=20=D0=BD=D0=B5=20=D0=BE=D1=82?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D1=91=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Корень отставания пропа найден замером и подтверждён на чистом Rapier: в rapier 0.36 по умолчанию `normalized_max_linear_velocity = 400`, и любая заданная скорость выше 400 обрезается на шаге. Отсюда 1200 -> 400 и «проп плетётся за игроком»: никакая пружина не помогала. - PhysicsWorld::new поднимает `normalized_max_linear_velocity` до 100k (в Source скорости выше: бег 650, физган до 5000, падения — тысячи); защита от нефинитных значений остаётся; - тест-страж body_with_set_velocity_actually_moves: тело с 1200 обязано проехать >1000 за секунду (до фикса — 400, тест падал); - временный телепорт-костыль был откачен ранее; трение на удержании выключается (combine rule Min), на отпускании возвращается 0.6. Проверено: 29 сьютов зелёные (включая новый тест скорости). --- crates/engine/src/physics.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/engine/src/physics.rs b/crates/engine/src/physics.rs index dccfb32..ff2b734 100644 --- a/crates/engine/src/physics.rs +++ b/crates/engine/src/physics.rs @@ -190,6 +190,13 @@ impl PhysicsWorld { // По умолчанию Rapier ставит Y-вертикаль и −9.81 — у нас Z-вертикаль // и другие единицы, поэтому гравитацию задаём явно. world.gravity = Vector::new(0.0, 0.0, DEFAULT_GRAVITY); + // Rapier 0.36 по умолчанию ограничивает скорость 400 единицами + // (`normalized_max_linear_velocity`). В Source скорости выше: бег 650, + // физган до 5000, падения — тысячи. С этим пределом тело с заданной + // скоростью 1200 реально ехало 400 (замер), из-за чего физган не мог + // догнать игрока. Поднимаем предел до 100k, сохраняя защиту от + // нефинитных величин. + world.integration_parameters.normalized_max_linear_velocity = 100_000.0; Self { world, handles: Vec::new(), @@ -1195,12 +1202,9 @@ mod tests { /// скорость 1200 по X. За секунду тело обязано проехать ~1200 юнитов. /// Если проезжает меньше — его тормозит контакт/трение, и никакая /// пружина физгана не поможет (нужно другое решение). - // ОТКРЫТЫЙ БАГ (физган): шаг физики гасит заданную скорость ровно втрое - // (1200 -> 400) даже без пола, контактов, трения (combine rule Min), - // гравитации (gravity_scale 0) и damping (0.000). Именно поэтому проп - // отстаёт от игрока при любой пружине. Тест-страдалец: раскомментировать - // assert после починки. - #[ignore = "открытый баг: шаг физики делит скорость на 3"] + // Причина отставания пропа (найдена этим тестом): в Rapier 0.36 + // `normalized_max_linear_velocity` по умолчанию 400, и заданная скорость + // 1200 превращалась в 400. Теперь предел поднят в `PhysicsWorld::new`. #[test] fn body_with_set_velocity_actually_moves() { let mut physics = PhysicsWorld::new(); @@ -1239,8 +1243,10 @@ mod tests { "проехало за секунду при 1200: {moved:.1}, скорость после шага: {:.1}", v.length() ); - eprintln!("тест-страж: ожидание >1000, факт {moved:.1}"); - // assert!(moved > 1000.0, ...); // включить после починки шага физики + assert!( + moved > 1000.0, + "тело проехало только {moved:.1} из 1200 — предел скорости Rapier не поднят" + ); } /// Проп должен падать и останавливаться на полу, а не проваливаться.