makepad/libs/sim/tests/mover_ceiling.rs
Admin 4ddba62d4b engine libs: csg document, stitch simd, sim providers, teamtalk LAN voice, gltf writer, render, route and maps, bench hygiene
Squashed from work; the fine-grained history is under tag archive/work-2026-08-29:
- mp* wave: mpwm window manager + the mp app family, WM API, theme bridge, PDF engine fix
- mpwm polish wave: terminal key focus, focus-history close order, pop-back-to-origin, occupied-workspace cycling, demo
- work: land the sources the last commits reference
- route: the assistant icon the committed UI references
- fast_inflate: the benches name their dev-deps
- gif/weezl: drop the vendored benches nobody can run
- weezl: the decode tests generate their own LZW fixture
2026-08-29 09:26:27 +02:00

86 lines
2.5 KiB
Rust

//! Ceiling contract for the canonical mover sweep.
//!
//! FPS, third-person and scripted walkers all end here. A head hit must be a
//! clamp, not a bounce or a sticky grounded state.
use makepad_game_sim::{step_world, BodyKind, Entity, GameWorld};
use makepad_math::{vec3f, Vec3f};
fn body(id: u64, kind: BodyKind, pos: Vec3f, half: Vec3f) -> Entity {
Entity {
id,
kind,
pos,
half,
collide: true,
gravity_scale: 1.0,
density: 1.0,
friction: 0.6,
scale: vec3f(1.0, 1.0, 1.0),
scale_target: vec3f(1.0, 1.0, 1.0),
speed_mult: 1.0,
..Default::default()
}
}
#[test]
fn a_low_ceiling_zeroes_upward_velocity_without_wedging_the_mover() {
let mut world = GameWorld::new();
world.gravity = 9.81;
// Floor top y=0, ceiling underside y=1.0. The 0.8 m body has 0.2 m
// standing headroom: enough to jump into the roof, not enough to pass it.
world.push_entity(body(
1,
BodyKind::Static,
vec3f(0.0, -0.5, 0.0),
vec3f(4.0, 0.5, 4.0),
));
world.push_entity(body(
2,
BodyKind::Static,
vec3f(0.0, 1.1, 0.0),
vec3f(4.0, 0.1, 4.0),
));
world.push_entity(body(
3,
BodyKind::Mover,
vec3f(0.0, 0.4, 0.0),
vec3f(0.25, 0.4, 0.25),
));
for _ in 0..4 {
step_world(&mut world);
}
assert!(world.entity(3).unwrap().on_floor);
world.entity_mut(3).unwrap().vel.y = 6.0;
let mut hit_head = false;
let mut landed = false;
for _ in 0..180 {
let before = world.entity(3).unwrap().vel.y;
step_world(&mut world);
let mover = world.entity(3).unwrap();
assert!(
mover.pos.y + mover.half.y <= 1.0 + 1.0e-4,
"mover head crossed the ceiling: {:?}",
mover.pos
);
if before > 0.0 && mover.vel.y == 0.0 && !mover.on_floor {
hit_head = true;
}
if hit_head && mover.on_floor {
landed = true;
break;
}
}
let mover = world.entity(3).unwrap();
assert!(hit_head, "the upward sweep never reported a head stop");
assert!(landed, "the head stop left the mover wedged under the roof");
assert!(
(mover.pos.y - 0.4).abs() < 0.01,
"landed at y {} instead of the floor centre 0.4",
mover.pos.y
);
assert_eq!((mover.pos.x, mover.pos.z), (0.0, 0.0), "ceiling contact must not kick sideways");
}