test: 109 Rust tests + 14 JSON scenarios, polish physics
Tests added: - physics_materials.rs: 15 tests (fire, smoke, steam, grass, dirt, bone, wood, stone, lava temp) - physics_interactions.rs: 12 tests (lava+water, fire spread, acid interactions, sand+water) - player_controls.rs: 12 tests (move L/R, jump, double jump, rapid input, wait, continuous) - collision_robust.rs: 10 tests (walls, ceiling, sliding, corridor, slope, dirt wall, unstick) - ragdoll_death.rs: 7 tests (death transition, ragdoll fall, progressive damage, corpse) - determinism.rs: 8 tests (same seed, replay exact, replay partial, recording, 100-tick) - edge_cases.rs: 19 tests (boundary, stress 20 goblins, fill/clear/paint, gravity, camera) - 6 new JSON scenarios (fire chain, lava pool, sand bury, entity fall, steam, acid wall) Fixes: - AABB resolve_aabb_y: add vertical overlap check (was pushing player down when jumping) - AABB resolve_aabb_x: velocity-aware resolution (player was stuck against walls) - check_on_ground: use fractional position check (was always true) - jump_force 1.5 (was 0.8) for 27-body entity - Gravity read from self.verlet (was from clone, SetGravity didn't work) - u8 overflow in lava color (saturating_add) 109 Rust tests, 14 JSON scenarios, 0 warnings, 0 failures
This commit is contained in:
@@ -11,8 +11,8 @@ impl Player {
|
||||
let id = manager.spawn(EntityKind::Player);
|
||||
Self {
|
||||
entity_id: id,
|
||||
move_speed: 0.25,
|
||||
jump_force: 0.8,
|
||||
move_speed: 0.3,
|
||||
jump_force: 1.5,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+39
-15
@@ -244,11 +244,16 @@ impl Game {
|
||||
|
||||
pub fn check_on_ground(&self) -> bool {
|
||||
if let Some(e) = self.player.entity(&self.entities) {
|
||||
let bottom = (e.cy + e.half_h + 0.1) as i32;
|
||||
let bottom_y = e.cy + e.half_h;
|
||||
let bottom_cell = bottom_y.floor() as i32;
|
||||
let frac = bottom_y - bottom_cell as f32;
|
||||
if frac > 0.05 {
|
||||
return false;
|
||||
}
|
||||
let left = (e.cx - e.half_w) as i32;
|
||||
let right = (e.cx + e.half_w) as i32;
|
||||
for x in left..=right {
|
||||
if self.grid.in_bounds(x, bottom) && self.grid.get(x, bottom).is_solid() {
|
||||
if self.grid.in_bounds(x, bottom_cell) && self.grid.get(x, bottom_cell).is_solid() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -273,8 +278,8 @@ impl Game {
|
||||
fn update_entities(&mut self) {
|
||||
let solver = self.verlet.clone();
|
||||
let substeps = solver.substeps;
|
||||
let gravity = solver.gravity;
|
||||
let damping = solver.damping;
|
||||
let gravity = self.verlet.gravity;
|
||||
let damping = self.verlet.damping;
|
||||
let max_vel = solver.max_vel;
|
||||
|
||||
let entity_count = self.entities.all().len();
|
||||
@@ -333,7 +338,7 @@ impl Game {
|
||||
|
||||
// Move X then resolve X collisions
|
||||
nx += nvx;
|
||||
let (resolved_x, hit_wall_x) = self.resolve_aabb_x(idx, nx, ny, half_w, half_h, nvx > 0.0);
|
||||
let (resolved_x, hit_wall_x) = self.resolve_aabb_x(idx, nx, ny, half_w, half_h, nvx);
|
||||
nx = resolved_x;
|
||||
if hit_wall_x {
|
||||
if nvx > 0.0 { nvx = 0.0; }
|
||||
@@ -410,7 +415,7 @@ impl Game {
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_aabb_x(&self, _idx: usize, cx: f32, cy: f32, hw: f32, hh: f32, _moving_right: bool) -> (f32, bool) {
|
||||
fn resolve_aabb_x(&self, _idx: usize, cx: f32, cy: f32, hw: f32, hh: f32, vx: f32) -> (f32, bool) {
|
||||
let grid = &self.grid;
|
||||
let left = cx - hw;
|
||||
let right = cx + hw;
|
||||
@@ -422,7 +427,7 @@ impl Game {
|
||||
let min_y = top.floor() as i32;
|
||||
let max_y = bottom.ceil() as i32;
|
||||
|
||||
let mut best_push = 0.0f32;
|
||||
let mut new_cx = cx;
|
||||
let mut hit = false;
|
||||
|
||||
for y in min_y..=max_y {
|
||||
@@ -440,18 +445,33 @@ impl Game {
|
||||
continue;
|
||||
}
|
||||
|
||||
let pen_left = right - cell_left;
|
||||
let pen_right = cell_right - left;
|
||||
|
||||
let push = if pen_left < pen_right { -pen_left } else { pen_right };
|
||||
if push.abs() > best_push.abs() {
|
||||
best_push = push;
|
||||
hit = true;
|
||||
if vx > 0.0 {
|
||||
let pen = right - cell_left;
|
||||
if pen > 0.0 && pen < 1.5 {
|
||||
new_cx -= pen;
|
||||
hit = true;
|
||||
}
|
||||
} else if vx < 0.0 {
|
||||
let pen = cell_right - left;
|
||||
if pen > 0.0 && pen < 1.5 {
|
||||
new_cx += pen;
|
||||
hit = true;
|
||||
}
|
||||
} else {
|
||||
let pen_left = right - cell_left;
|
||||
let pen_right = cell_right - left;
|
||||
if pen_left < pen_right && pen_left > 0.0 && pen_left < 1.5 {
|
||||
new_cx -= pen_left;
|
||||
hit = true;
|
||||
} else if pen_right > 0.0 && pen_right < 1.5 {
|
||||
new_cx += pen_right;
|
||||
hit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(cx + best_push, hit)
|
||||
(new_cx, hit)
|
||||
}
|
||||
|
||||
fn resolve_aabb_y(&self, _idx: usize, cx: f32, cy: f32, hw: f32, hh: f32, moving_down: bool) -> (f32, bool, bool) {
|
||||
@@ -485,6 +505,10 @@ impl Game {
|
||||
continue;
|
||||
}
|
||||
|
||||
if bottom <= cell_top || top >= cell_bottom {
|
||||
continue;
|
||||
}
|
||||
|
||||
if moving_down {
|
||||
let pen = bottom - cell_top;
|
||||
if pen > max_pen {
|
||||
|
||||
Reference in New Issue
Block a user