engine: тест на прошивку тонкого пола — гипотеза не подтвердилась

Две версии про проваливание проверены тестами и обе оказались неверными.

1. «Пропов нет в коллизии игрока» — пробел реальный и устранён, но игрок
   ходил по брашам, это его не объясняло.
2. «На низком FPS шаг подшага прошивает пол» — опровергнуто: при
   terminal-скорости 2000 юнитов/с и dt = 1/60 игрок садится на площадку
   толщиной 4 юнита, on_ground = true.

Тест оставлен как регрессионный сторож: если подшаги когда-нибудь
ослабнут, он сразу это покажет.

Замер: стояние на спавне gm_construct стабильно 180 кадров (z = -143.9,
on_ground = true). Дефект локальный и требует указания места.

Причина не найдена — фиксирую это в docs/PARITY.md B3, а не подгоняю
тест под желаемый результат.
This commit is contained in:
Niko Marmeladkov 2026-10-13 14:44:45 +03:00
parent 2afa265fed
commit e6d7454a6a
2 changed files with 75 additions and 0 deletions

View file

@ -1265,4 +1265,50 @@ mod tests {
player.position.x
);
}
/// Падающий игрок не должен прошивать тонкий пол даже на 60 fps.
///
/// Скорость падения ограничена 2000 юнитов/с; при dt = 1/60 это 33 юнита
/// за кадр. Число подшагов ограничено восемью, значит на шаг приходится
/// около 6.6 юнита — пол тоньше этого игрок проходит насквозь. Именно
/// это и выглядит как «проваливаюсь при хождении»: чем быстрее кадр,
/// тем больше шаг подшага.
#[test]
fn fast_fall_does_not_tunnel_thin_floor() {
let mut collision = Collision {
brushes: Vec::new(),
tris: Vec::new(),
grid: HashMap::new(),
boxes: Vec::new(),
box_grid: HashMap::new(),
};
// Тонкая площадка толщиной 4 юнита — как отступы и площадки на картах.
collision.brushes = vec![Brush {
planes: vec![
(Vec3::new(1.0, 0.0, 0.0), 512.0),
(Vec3::new(-1.0, 0.0, 0.0), 512.0),
(Vec3::new(0.0, 1.0, 0.0), 512.0),
(Vec3::new(0.0, -1.0, 0.0), 512.0),
(Vec3::new(0.0, 0.0, 1.0), 0.0),
(Vec3::new(0.0, 0.0, -1.0), 4.0),
],
}];
let mut player = Player::new(Vec3::new(0.0, 0.0, 400.0));
// Падаем до удара: за один кадр игрок проходит лишь ~33 юнита, до
// пола от 400 нужно десятки кадров.
for _ in 0..200 {
player.update(&collision, 0.0, 0.0, false, false, 0.0, 1.0 / 60.0);
assert!(
player.position.z >= -1.0,
"игрок не должен пройти сквозь пол, z={}",
player.position.z
);
}
assert!(
player.on_ground,
"после удара игрок должен стоять на полу, z={}",
player.position.z
);
}
}

View file

@ -693,3 +693,32 @@ API. Частоты по числу вхождений:
- Оси соединения задаются в мировых координатах, как в GMod.
- Ограничение угла переводится в радианы; вырожденный диапазон игнорируется.
- `pulley` и `thruster` — это не суставы: тяга делается через `add_force`.
## Часть B3. Проваливание сквозь пол: что проверено и что нет
### B3.1. Две гипотезы, обе опровергнуты измерением
1. **«Пропов нет в коллизии игрока».** Гипотеза была верной *как диагноз*,
но не как объяснение жалобы: игрок ходил по брашам. Пробел устранён
(`Collision::boxes`), проп теперь стоит под ногами — это нужно в любом
случае, но от проваливания по брашам не избавило.
2. **«На низком FPS шаг подшага прошивает пол».** Опровергнуто тестом
`fast_fall_does_not_tunnel_thin_floor`: при terminal-скорости 2000
юнитов/с и dt = 1/60 игрок садится на площадку толщиной **4 юнита** и
`on_ground = true`. Подшагов восемь хватает.
Обе версии выглядели правдоподобно и обе были неверны — характерная черта
дефектов, которые видны только после попытки воспроизвести их тестом.
### B3.2. Что измерено
- Стояние на спавне gm_construct: 180 кадров, `z = -143.9` стабильно,
`on_ground = true`, провала нет.
- Значит дефект локальный и воспроизводится на определённой геометрии.
### B3.3. Что нужно, чтобы найти причину
Точное место и обстоятельства: с какой высоты, после какого движения
(прыжок, спуск по рампе, спуск с края) и на каком участке. Без этого
пришлось бы перебирать геометрию карты наугад — а это ровно тот способ,
которым эти две гипотезы и были порождены.